versioning
[svn/Prometheus-QoS/.git] / prometheus.c
CommitLineData
068f0e75 1/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
b1a5c883 2/* Prometheus QoS - you can "steal fire" from your ISP */\r
3/* "fair-per-IP" quality of service (QoS) utility */\r
068f0e75 4/* requires Linux 2.4.x or 2.6.x with HTB support */\r
f71cfa3b 5/* Copyright(C) 2005-2014 Michael Polak, Arachne Aerospace */\r
068f0e75 6/* iptables-restore support Copyright(C) 2007-2008 ludva */\r
7/* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */\r
8/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
9\r
f71cfa3b 10/* Modified by: xChaos, 20140812\r
a031788f 11 ludva, 20080415\r
208112af 12 \r
007c44c5 13 Prometheus QoS is free software; you can redistribute it and/or\r
14 modify it under the terms of the GNU General Public License as \r
15 published by the Free Software Foundation; either version 2.1 of \r
16 the License, or (at your option) any later version.\r
17\r
18 Prometheus QoS is distributed in the hope that it will be useful,\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
21 General Public License for more details.\r
22\r
c9012978 23 You should have received a copy of the GNU General Public License\r
24 along with Prometheus Qos; if not, write to the Free Software\r
d1ae4fa7 25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \r
26 \r
c9012978 27 GNU General Public License is located in file COPYING */\r
007c44c5 28\r
208112af 29#include "cll1-0.6.2.h"\r
1c9cae56 30#include "ipstruct.h"\r
007c44c5 31\r
f71cfa3b 32const char *version = "0.8.5-b";\r
007c44c5 33\r
068f0e75 34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
35/* Versions: 0.8.3 is development release, 0.8.4 will be "stable" */\r
36/* Official Trac URL: https://dev.arachne.cz/svn/prometheus */\r
37/* Official SVN URL: https://dev.arachne.cz/repos/prometheus */\r
38/* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */\r
39/* CZK donations account: 2900242944/2010 (transparent account) */\r
40/* Warning: unofficial Github mirror is not supported by author! */\r
41/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
77e71d6b 42\r
f71cfa3b 43const char *stats_html_signature = "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2014 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";\r
2d114137 44\r
068f0e75 45#define STRLEN 512\r
46#undef DEBUG\r
47\r
82c702a1 48/* ======= All path names are defined here (for RPM patch) ======= */\r
ae776b10 49\r
f19d3cd0 50const char *tc = "/sbin/tc"; /* requires tc with HTB support */\r
51const char *iptables = "/sbin/iptables"; /* requires iptables utility */\r
52const char *ip6tables = "/sbin/ip6tables"; /* requires iptables utility */\r
53const char *iptablessave = "/sbin/iptables-save"; /* not yet required */\r
54const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */\r
55const char *ip6tablessave = "/sbin/ip6tables-save"; /* not yet required */\r
56const char *ip6tablesrestore = "/sbin/ip6tables-restore"; /* requires iptables-restore */\r
57const char *ls = "/bin/ls"; /* this is not user configurable :-) */\r
ae776b10 58\r
2d114137 59char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */\r
60char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */\r
bb5e7385 61char *macrosfile = "/etc/prometheus/prometheus.macros"; /* rewrite rules for most common tariffs */\r
2d114137 62char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/\r
f64d5431 63char *ip6tablesfile = "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/\r
2d114137 64char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */\r
be96b71b 65char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */\r
66char *html = "/var/www/traffic.html"; /* hall of fame - html version */\r
6fb3c58a 67char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */\r
1ab008b9 68char *json_traffic = "/var/www/logs/traffic.json"; /* hall of fame - json version */\r
6fb3c58a 69char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */\r
2d114137 70char *cmdlog = "/var/log/prometheuslog"; /* command log filename */\r
71char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */\r
8bcc3268 72char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */\r
2d114137 73char *html_log_dir = "/var/www/logs/html/";\r
ae776b10 74\r
6cc38f96 75char *jquery_url = "http://code.jquery.com/jquery-latest.js";\r
76char *lms_url = "/lms/?m=customerinfo&amp;id=";\r
9a56ab25 77int use_jquery_popups = TRUE;\r
9aa195f6 78int row_odd_even = 0; /*<tr class="odd/even"> */\r
b6fb849a 79 \r
007c44c5 80/* === Configuraration file values defaults - stored in global variables ==== */\r
81\r
43cde5c3 82int filter_type = 1; /*1 mark, 2 classify*/\r
0b9c3c19 83char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */\r
43cde5c3 84char *mark = "MARK";\r
85char *mark_iptables = "MARK --set-mark ";\r
9a56ab25 86int dry_run = FALSE; /* preview - use puts() instead of system() */\r
43cde5c3 87char *iptablespreamble = "*mangle\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]";\r
0995c4ad 88char *ip6preamble = "-A FORWARD -p ipv6-icmp -j ACCEPT\n-A POSTROUTING -p ipv6-icmp -j ACCEPT\n-A FORWARD -s fe80::/10 -j ACCEPT\n-A FORWARD -d ff00::/8 -j ACCEPT\n-A POSTROUTING -s fe80::/10 -j ACCEPT\n-A POSTROUTING -d ff00::/8 -j ACCEPT";\r
43cde5c3 89FILE *iptables_file = NULL;\r
0b9c3c19 90FILE *ip6tables_file = NULL;\r
9a56ab25 91int enable_credit = TRUE; /* enable credit file */\r
92int use_credit = FALSE; /* use credit file (if enabled)*/\r
43cde5c3 93char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */\r
9a56ab25 94int hall_of_fame = TRUE; /* enable hall of fame */\r
43cde5c3 95char *lan = "eth0"; /* LAN interface */\r
96char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */\r
97char *wan = "eth1"; /* WAN/ISP interface */\r
f64d5431 98char *ip6prefix = NULL; /* Prefix for global /48 IPv6 subnet */\r
43cde5c3 99char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */\r
100char *qos_leaf = "sfq perturb 5"; /* leaf discipline */\r
101char *qos_free_zone = NULL; /* QoS free zone */\r
7d05bfc0 102/* int qos_proxy = TRUE; include proxy port to QoS */\r
9a56ab25 103int found_lmsid = FALSE; /* show links to users in LMS information system */\r
104int include_upload = TRUE; /* upload+download=total traffic */\r
7ae5a593 105/* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */\r
106/* int proxy_port = 3128; proxy port number */\r
43cde5c3 107long long int line = 1024; /* WAN/ISP download in kbps */\r
108long long int up = 1024; /* WAN/ISP upload in kbps */\r
0b9c3c19 109int free_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
110int free_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
73cf6e9d 111int overlimit_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
112int overlimit_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
43cde5c3 113int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */\r
114int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */ \r
fa54950d 115int max_nesting = 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */\r
208112af 116int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */\r
43cde5c3 117int burst = 8; /* HTB burst (in kbits) */\r
118int burst_main = 64;\r
119int burst_group = 32;\r
43cde5c3 120int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */\r
121int keywordcount = 0;\r
9a56ab25 122int class_count = 0;\r
123int ip_count = 0;\r
43cde5c3 124FILE *log_file = NULL;\r
125char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */\r
007c44c5 126\r
208112af 127const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */\r
fa54950d 128const int lowest_priority = 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */\r
208112af 129const int idxtable_treshold1 = 24; /* this is no longer configurable */\r
130const int idxtable_treshold2 = 12; /* this is no longer configurable */\r
131const int idxtable_bitmask1 = 3; /* this is no longer configurable */\r
132const int idxtable_bitmask2 = 3; /* this is no longer configurable */\r
007c44c5 133\r
af37be1d 134struct IP *ips = NULL, *networks = NULL, *ip, *sharedip;\r
1c9cae56 135struct Group *groups = NULL, *group;\r
bb5e7385 136struct Keyword *keyword, *defaultkeyword=NULL, *keywords = NULL;\r
137struct Macro *macro, *macros = NULL;\r
007c44c5 138\r
a25842fa 139#define FREE_CLASS 3\r
140#define OVERLIMIT_CLASS 4\r
141\r
068f0e75 142void help(void);\r
143/* implemented in help.c */
144\r
d7357b63 145void get_traffic_statistics(const char *whichiptables, int ipv6);\r
f19d3cd0 146/* implemented in parseiptables.c */\r
147\r
b6fb849a 148void parse_ip_log(int argc, char **argv);\r
1ab008b9 149/* implemented in parselog.c */\r
b6fb849a 150\r
151void parse_hosts(char *hosts);\r
1ab008b9 152/* implemented in parsehosts.c */\r
153\r
154void write_json_traffic(char *json);\r
155/* implemented in json.c */\r
b6fb849a 156\r
9a56ab25 157void write_htmlandlogs(char *html, char *d, int total, int just_preview);\r
158/* implemented in htmlandlogs.c */\r
159\r
af37be1d 160void analyse_topology(char *traceroute);\r
161/* implemented in networks.c */\r
162\r
163\r
b6fb849a 164const char *tr_odd_even(void)\r
165{\r
166 row_odd_even = 1 - row_odd_even;\r
167 if(row_odd_even)\r
168 {\r
169 return "<tr class=\"even\">\n";\r
170 }\r
171 else\r
172 {\r
173 return "<tr class=\"odd\">\n";\r
174 }\r
175}\r
176\r
1c9cae56 177/* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */\r
068f0e75 178/* (except that this code uses obsolete, archaic version of this header file...) */\r
007c44c5 179\r
180struct Index\r
181{\r
182 char *addr;\r
183 char *id;\r
184 struct Index *parent;\r
185 int bitmask;\r
186 int children;\r
0b9c3c19 187 int ipv6;\r
007c44c5 188 list(Index);\r
189} *idxs=NULL, *idx, *metaindex;\r
190\r
007c44c5 191\r
5b902402 192/* ====== iptables indexes are used to reduce complexity to log8(N) ===== */\r
007c44c5 193\r
59c3032e 194char *index_id(char *ip, int bitmask);\r
195/* function implemented in ipv4subnets.c */\r
007c44c5 196\r
59c3032e 197char *subnet_id(char *ip, int bitmask);\r
198/* function implemented in ipv4subnets.c */\r
007c44c5 199\r
0b9c3c19 200char *index6_id(char *ip, int bitmask);\r
201/* function implemented in ipv6subnets.c */\r
202\r
203char *subnet6_id(char *ip, int bitmask);\r
204/* function implemented in ipv6subnets.c */\r
205\r
59c3032e 206/* ================= Let's parse configuration file here ================ */\r
007c44c5 207\r
208void reject_config_and_exit(char *filename)\r
209{\r
210 printf("Configuration file %s rejected - abnormal exit.",filename);\r
211 exit(-1);\r
212}\r
213\r
214void get_config(char *config_filename)\r
215{\r
216 char *cnf="mark";\r
217 \r
218 printf("Configured keywords: ");\r
219 parse(config_filename)\r
220 {\r
221 option("keyword",kwd);\r
222 if(kwd)\r
223 {\r
224 printf("%s ",kwd);\r
225\r
226 create(keyword,Keyword);\r
73cf6e9d 227 keyword->key = kwd;\r
228 keyword->asymetry_ratio = 1; /* ratio for ADSL-like upload */\r
229 keyword->asymetry_fixed = 0; /* fixed treshold for ADSL-like upload */\r
230 keyword->data_limit = 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
231 keyword->data_prio = 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
232 keyword->fixed_limit = 0; /* fixed data limit for setting lower HTB ceil */\r
233 keyword->fixed_prio = 0; /* fixed data limit for setting lower HTB prio */\r
234 keyword->reserve_min = 8; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
235 keyword->reserve_max = 0; /* malus for nominal HTB ceil (in kbps) */\r
236 keyword->default_prio = highest_priority+1;\r
237 keyword->html_color = "000000";\r
238 keyword->ip_count = 0;\r
239 keyword->leaf_discipline = "";\r
240 keyword->allowed_avgmtu = 0;\r
007c44c5 241\r
bb5e7385 242 push(keyword, keywords);\r
4d41c1e4 243 if(!defaultkeyword)\r
244 {\r
73cf6e9d 245 defaultkeyword = keyword;\r
4d41c1e4 246 }\r
007c44c5 247 keywordcount++;\r
248 \r
249 kwd=NULL;\r
250 }\r
208112af 251 else\r
007c44c5 252 {\r
208112af 253 for_each(keyword,keywords)\r
254 {\r
255 int l=strlen(keyword->key);\r
007c44c5 256\r
208112af 257 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)\r
258 {\r
259 char *tmptr=_; /* <---- l+1 ----> */\r
260 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */\r
73cf6e9d 261 ioption("asymetry-ratio", keyword->asymetry_ratio);\r
262 ioption("asymetry-treshold", keyword->asymetry_fixed);\r
263 ioption("magic-relative-limit", keyword->data_limit);\r
264 ioption("magic-relative-prio", keyword->data_prio);\r
265 loption("magic-fixed-limit", keyword->fixed_limit);\r
266 loption("magic-fixed-prio", keyword->fixed_prio);\r
267 ioption("htb-default-prio", keyword->default_prio);\r
268 ioption("htb-rate-bonus", keyword->reserve_min);\r
269 ioption("htb-ceil-malus", keyword->reserve_max);\r
270 option("leaf-discipline", keyword->leaf_discipline);\r
271 option("html-color", keyword->html_color);\r
272 ioption("allowed-avgmtu" ,keyword->allowed_avgmtu);\r
208112af 273 _=tmptr;\r
274 \r
275 if(keyword->data_limit || keyword->fixed_limit || \r
276 keyword->data_prio || keyword->fixed_prio)\r
bb9e11ee 277 {\r
278 use_credit=1; \r
279 }\r
208112af 280 }\r
281 }\r
007c44c5 282 }\r
283\r
284 option("tc",tc);\r
285 option("iptables",iptables);\r
f64d5431 286 option("iptables-save",iptablessave);\r
287 option("iptables-restore",iptablesrestore);\r
f19d3cd0 288 option("ip6tables",ip6tables);\r
f64d5431 289 option("ip6tables-save",ip6tablessave);\r
290 option("ip6tables-restore",ip6tablesrestore);\r
291 option("iptables-in-filename",iptablesfile);\r
292 option("ip6tables-in-filename",ip6tablesfile);\r
007c44c5 293 option("hosts",hosts);\r
294 option("lan-interface",lan);\r
295 option("wan-interface",wan);\r
f64d5431 296 option("ip6-prefix",ip6prefix);\r
007c44c5 297 option("lan-medium",lan_medium);\r
298 option("wan-medium",wan_medium);\r
299 lloption("wan-download",line);\r
300 lloption("wan-upload",up);\r
301 ioption("hall-of-fame-enable",hall_of_fame);\r
302 option("hall-of-fame-title",title);\r
303 option("hall-of-fame-filename",html);\r
1ab008b9 304 option("json-filename",json_traffic);\r
007c44c5 305 option("hall-of-fame-preview",preview);\r
6fb3c58a 306 option("json-preview",json_preview);\r
007c44c5 307 option("log-filename",cmdlog);\r
308 option("credit-filename",credit);\r
be96b71b 309 option("classmap-filename",classmap);\r
007c44c5 310 ioption("credit-enable",enable_credit);\r
311 option("log-traffic-directory",log_dir);\r
5b902402 312 option("log-traffic-html-directory",html_log_dir);\r
007c44c5 313 option("log-traffic-url-path",log_url);\r
6cc38f96 314 option("jquery-url",jquery_url);\r
315 option("lms-url",lms_url);\r
316 ioption("use-jquery-popups",use_jquery_popups);\r
007c44c5 317 option("qos-free-zone",qos_free_zone);\r
318 ioption("qos-free-delay",qos_free_delay);\r
7d05bfc0 319/* ioption("qos-proxy-enable",qos_proxy); */\r
7ae5a593 320/* option("qos-proxy-ip",proxy_ip);*/\r
007c44c5 321 option("htb-leaf-discipline",qos_leaf);\r
7ae5a593 322/* ioption("qos-proxy-port",proxy_port); */\r
007c44c5 323 ioption("free-rate",free_min);\r
324 ioption("free-ceil",free_max);\r
73cf6e9d 325 ioption("overlimit-rate",overlimit_min);\r
326 ioption("overlimit-ceil",overlimit_max);\r
007c44c5 327 ioption("htb-burst",burst);\r
328 ioption("htb-burst-main",burst_main);\r
329 ioption("htb-burst-group",burst_group);\r
330 ioption("htb-nesting-limit",max_nesting);\r
331 ioption("htb-r2q",htb_r2q);\r
332 ioption("magic-include-upload",include_upload);\r
5b902402 333 ioption("magic-treshold",magic_treshold); \r
260c2719 334 option("filter-type", cnf); \r
007c44c5 335/* not yet implemented:\r
336 ioption("magic-fixed-packets",fixed_packets);\r
337 ioption("magic-relative-packets",packet_limit);\r
338*/\r
339 }\r
340 fail\r
341 { \r
342 perror(config_filename);\r
343 puts("Warning - using built-in defaults instead ...");\r
344 }\r
8e29188a 345 done; /* ugly macro end */\r
007c44c5 346 printf("\n");\r
347 \r
be96b71b 348 /* leaf discipline for keywords */\r
208112af 349 for_each(keyword,keywords)\r
007c44c5 350 {\r
af37be1d 351 if(!strcmpi(keyword->leaf_discipline, ""))\r
352 {\r
353 keyword->leaf_discipline = qos_leaf;\r
354 }\r
007c44c5 355 }\r
356\r
260c2719 357 if(strcmpi(cnf, "mark"))\r
bb9e11ee 358 {\r
359 filter_type = 2;\r
360 mark = "CLASSIFY";\r
361 mark_iptables = "CLASSIFY --set-class 1:";\r
362 }\r
363 else\r
364 {\r
365 filter_type = 1;\r
366 mark = "MARK";\r
367 mark_iptables = "MARK --set-mark ";\r
007c44c5 368 }\r
369\r
370 /* are supplied values meaningful ?*/\r
371 if(line<=0 || up<=0)\r
372 {\r
b1b59b3a 373 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");\r
007c44c5 374 reject_config_and_exit(config_filename);\r
375 }\r
376}\r
377\r
007c44c5 378 \r
379/* ========== This function executes, logs OR ALSO prints command ========== */\r
380\r
381void safe_run(char *cmd)\r
382{\r
a1d21464 383 if(dry_run)\r
384 {\r
385 printf("\n=>%s\n",cmd);\r
386 }\r
387 else\r
388 {\r
389 system(cmd);\r
390 }\r
391 if(log_file)\r
392 {\r
393 fprintf(log_file,"%s\n",cmd);\r
394 }\r
007c44c5 395}\r
396\r
0b9c3c19 397void iptables_save_line(char *line, int ipv6)\r
007c44c5 398{\r
0b9c3c19 399 if(ipv6)\r
400 {\r
401 fprintf(ip6tables_file,"%s\n",line);\r
402 }\r
403 else\r
404 {\r
405 fprintf(iptables_file,"%s\n",line);\r
406 }\r
007c44c5 407}\r
408\r
0b9c3c19 409void run_iptables_restore(void)\r
007c44c5 410{\r
5da44508 411 char *restor;\r
007c44c5 412 string(restor,STRLEN);\r
abe9b855 413\r
414 /*-----------------------------------------------------------------*/\r
1c004f15 415 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
abe9b855 416 /*-----------------------------------------------------------------*/\r
0b9c3c19 417\r
418 iptables_save_line("COMMIT", FALSE);\r
007c44c5 419 fclose(iptables_file);\r
ae776b10 420 if(dry_run) \r
421 {\r
a1d21464 422 parse(iptablesfile)\r
423 {\r
424 printf("%s\n",_);\r
425 }\r
8e29188a 426 done; /* ugly macro end */\r
ae776b10 427 }\r
428\r
429 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
430 safe_run(restor);\r
0b9c3c19 431\r
432 if(ip6prefix)\r
433 {\r
434 /*-----------------------------------------------------------------*/\r
435 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
436 /*-----------------------------------------------------------------*/\r
437 iptables_save_line("COMMIT", TRUE);\r
438 fclose(ip6tables_file);\r
439 if(dry_run) \r
440 {\r
441 parse(ip6tablesfile)\r
442 {\r
443 printf("%s\n",_);\r
444 }\r
445 done; /* ugly macro end */\r
446 }\r
447 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
448 safe_run(restor);\r
449 }\r
007c44c5 450 free(restor);\r
451}\r
452\r
007c44c5 453char *parse_datafile_line(char *str)\r
454{\r
bb5e7385 455 char *ptr = strchr(str,' ');\r
456 if(!ptr)\r
457 {\r
458 ptr = strchr(str,'\t');\r
459 }\r
007c44c5 460\r
461 if(ptr)\r
462 {\r
bb5e7385 463 *ptr = 0;\r
007c44c5 464 ptr++;\r
bb5e7385 465 while(*ptr == ' ' || *ptr == '\t')\r
466 {\r
467 ptr++;\r
468 }\r
007c44c5 469 return ptr;\r
470 } \r
471 else \r
4358455e 472 {\r
007c44c5 473 return NULL;\r
4358455e 474 }\r
007c44c5 475}\r
476\r
5b902402 477\r
007c44c5 478/*-----------------------------------------------------------------*/\r
493e1ccd 479/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
007c44c5 480/*-----------------------------------------------------------------*/\r
481\r
482program\r
483{\r
8e29188a 484 int i=0; /* just plain old Fortran style integer :-) */\r
485 FILE *f=NULL; /* everything is just stream of bytes... */\r
486 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
c38473c1 487 char *substring, *limit_pkts;\r
1c9cae56 488\r
9a56ab25 489 int parent = 1;\r
af37be1d 490 int just_networks = FALSE; \r
9a56ab25 491 int just_flush = FALSE; /* deactivates all previous actions */\r
492 int nodelay = FALSE;\r
493 int just_preview = FALSE; /* preview - generate just stats */\r
494 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
62b118c2 495 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
496 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
9a56ab25 497 int just_logs = FALSE; /* just parse logs */\r
498 int run = FALSE;\r
499 int total = 0;\r
33ec95ab 500 \r
007c44c5 501 char *chain_forward, *chain_postrouting;\r
502 char *althosts=NULL;\r
503 \r
504 printf("\n\\r
505Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
0b9c3c19 506Version %s - Copyright (C)2005-2013 Michael Polak, Arachne Labs\n\\r
43cde5c3 507iptables-restore & burst tunning & classify modification by Ludva\n\\r
0d5026c6 508Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
007c44c5 509\r
8e29188a 510 /*----- Boring... we have to check command line options first: ----*/ \r
007c44c5 511 arguments\r
512 {\r
513 argument("-c") { nextargument(config); }\r
514 argument("-h") { nextargument(althosts);}\r
208112af 515 argument("-d") { run=TRUE; dry_run=TRUE; }\r
516 argument("-f") { run=TRUE; just_flush=TRUE; }\r
517 argument("-9") { run=TRUE; just_flush=9; }\r
518 argument("-p") { run=TRUE; just_preview=TRUE; }\r
3f76726a 519 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
62b118c2 520 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
521 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
8e29188a 522 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
208112af 523 argument("-r") { run=TRUE; }\r
524 argument("-n") { run=TRUE; nodelay=TRUE; }\r
af37be1d 525 argument("-a") { run=TRUE; just_networks=TRUE; }\r
208112af 526 argument("-l") { just_logs=TRUE; }\r
527 argument("-m") { just_logs=TRUE; }\r
528 argument("-y") { just_logs=TRUE; }\r
007c44c5 529 argument("-?") { help(); exit(0); }\r
530 argument("--help") { help(); exit(0); }\r
531 argument("-v") { exit(0); } \r
532 argument("--version") { exit(0); } \r
533 }\r
208112af 534 \r
007c44c5 535 if(dry_run)\r
208112af 536 {\r
007c44c5 537 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
208112af 538 }\r
007c44c5 539\r
208112af 540 date(d); /* this is typical cll1.h macro - prints current date */\r
007c44c5 541\r
542 /*-----------------------------------------------------------------*/\r
543 printf("Parsing configuration file %s ...\n", config);\r
544 /*-----------------------------------------------------------------*/\r
545 get_config(config);\r
c9012978 546 \r
33ec95ab 547 if(just_logs)\r
c9012978 548 {\r
208112af 549 parse_ip_log(argc,argv);\r
550 exit(0);\r
551 }\r
552 else if(not run)\r
553 {\r
554 help();\r
555 exit(0);\r
c9012978 556 }\r
007c44c5 557\r
208112af 558 if(althosts)\r
559 {\r
af37be1d 560 hosts = althosts;\r
208112af 561 }\r
007c44c5 562\r
563 if(just_flush<9)\r
564 {\r
565 /*-----------------------------------------------------------------*/\r
566 puts("Parsing iptables verbose output ...");\r
567 /*-----------------------------------------------------------------*/\r
d7357b63 568 get_traffic_statistics(iptables, FALSE);\r
0b9c3c19 569 if(ip6prefix)\r
570 {\r
571 /*-----------------------------------------------------------------*/\r
572 puts("Parsing ip6tables verbose output ...");\r
573 /*-----------------------------------------------------------------*/ \r
d7357b63 574 get_traffic_statistics(ip6tables, TRUE);\r
0b9c3c19 575 }\r
007c44c5 576 }\r
577\r
578 /*-----------------------------------------------------------------*/\r
af37be1d 579 /* cll1.h - let's allocate brand new character buffer... */\r
007c44c5 580 /*-----------------------------------------------------------------*/\r
c38473c1 581 string(str, STRLEN); \r
582 string(limit_pkts, STRLEN);\r
007c44c5 583\r
8dcd2b4c 584 /*-----------------------------------------------------------------*/\r
585 printf("Parsing macro definition file %s ...\n", macrosfile);\r
586 /*-----------------------------------------------------------------*/\r
587 parse(macrosfile)\r
588 {\r
589 ptr = parse_datafile_line(_);\r
590 if(ptr)\r
591 {\r
592 create(macro, Macro);\r
593 macro->rewrite_from = _;\r
594 macro->rewrite_to = ptr;\r
595 push(macro, macros);\r
596 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
597 }\r
598 }\r
599 done; /* ugly macro end */\r
600\r
007c44c5 601 /*-----------------------------------------------------------------*/\r
af37be1d 602 printf("Parsing class defintion file %s ...\n", hosts);\r
007c44c5 603 /*-----------------------------------------------------------------*/\r
af37be1d 604 parse_hosts(hosts);\r
605 if(just_networks)\r
606 {\r
607 analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d");\r
608 exit(-1); \r
609 }\r
007c44c5 610\r
611 /*-----------------------------------------------------------------*/\r
612 puts("Resolving shared connections ...");\r
613 /*-----------------------------------------------------------------*/\r
af37be1d 614 for_each(ip, ips) if(ip->sharing)\r
007c44c5 615 {\r
af37be1d 616 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
007c44c5 617 {\r
b1a5c883 618 sharedip->traffic += ip->traffic;\r
619 ip->traffic = 0;\r
620 ip->mark = sharedip->mark; \r
621 ip->lmsid = sharedip->lmsid;\r
c38473c1 622 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
007c44c5 623 break;\r
624 }\r
1c9cae56 625 if(not sharedip)\r
bb9e11ee 626 {\r
260c2719 627 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
628 ip->addr, ip->name, ip->sharing);\r
bb9e11ee 629 }\r
007c44c5 630 }\r
631\r
632 if(enable_credit && just_flush<9)\r
633 {\r
634 /*-----------------------------------------------------------------*/\r
635 printf("Parsing credit file %s ...\n", credit);\r
636 /*-----------------------------------------------------------------*/\r
637 parse(credit)\r
638 {\r
bb5e7385 639 ptr = parse_datafile_line(_);\r
007c44c5 640 if(ptr)\r
641 {\r
208112af 642 if_exists(ip,ips,eq(ip->addr,_))\r
643 {\r
007c44c5 644 sscanf(ptr,"%Lu",&(ip->credit));\r
208112af 645 }\r
007c44c5 646 }\r
647 }\r
8e29188a 648 done; /* ugly macro end */\r
007c44c5 649 }\r
650\r
bb5e7385 651\r
007c44c5 652 if(!just_preview)\r
653 {\r
654 /*-----------------------------------------------------------------*/\r
655 puts("Initializing iptables and tc classes ...");\r
656 /*-----------------------------------------------------------------*/\r
657 \r
f64d5431 658 iptables_file = fopen(iptablesfile, "w");\r
260c2719 659 if(iptables_file == NULL)\r
bb9e11ee 660 {\r
f64d5431 661 perror(iptablesfile);\r
007c44c5 662 exit(-1);\r
663 }\r
0b9c3c19 664 iptables_save_line(iptablespreamble, FALSE);\r
665\r
666 if(ip6prefix)\r
667 {\r
668 ip6tables_file = fopen(ip6tablesfile, "w");\r
669 if(ip6tables_file == NULL)\r
670 {\r
671 perror(ip6tablesfile);\r
672 exit(-1);\r
673 }\r
674 iptables_save_line(iptablespreamble, TRUE);\r
e36b49c7 675 iptables_save_line(ip6preamble, TRUE);\r
0b9c3c19 676 }\r
677\r
678 run_iptables_restore();\r
007c44c5 679 \r
f64d5431 680 log_file = fopen(cmdlog, "w");\r
260c2719 681 if(log_file == NULL) \r
bb9e11ee 682 {\r
f64d5431 683 perror(cmdlog);\r
007c44c5 684 exit(-1);\r
ca6f7e80 685 } \r
007c44c5 686 \r
687 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
688 safe_run(str);\r
689\r
690 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
691 safe_run(str);\r
692 \r
693 iptables_file=fopen(iptablesfile,"w");\r
0b9c3c19 694 iptables_save_line(iptablespreamble, FALSE);\r
695 if(ip6prefix)\r
696 {\r
697 ip6tables_file=fopen(ip6tablesfile,"w");\r
698 iptables_save_line(iptablespreamble, TRUE);\r
e36b49c7 699 iptables_save_line(ip6preamble, TRUE);\r
0b9c3c19 700 }\r
007c44c5 701\r
0b9c3c19 702 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */\r
007c44c5 703 {\r
704 char *chain;\r
705 \r
706 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
0b9c3c19 707 iptables_save_line(str, FALSE); /* this is currently supported only for IPv4 */\r
007c44c5 708 \r
a25842fa 709/*\r
007c44c5 710 if(qos_proxy)\r
711 {\r
0b9c3c19 712 iptables_save_line(":post_noproxy - [0:0]", FALSE);\r
6b39193d 713 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);\r
0b9c3c19 714 iptables_save_line(str , FALSE);\r
6b39193d 715 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);\r
0b9c3c19 716 iptables_save_line(str, FALSE);\r
6b39193d 717 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
0b9c3c19 718 iptables_save_line(str, FALSE);\r
007c44c5 719\r
720 chain="post_noproxy"; \r
721 }\r
a25842fa 722\r
007c44c5 723 else\r
bb9e11ee 724 {\r
a25842fa 725*/\r
726 chain = "POSTROUTING";\r
727// }\r
007c44c5 728 \r
729 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
0b9c3c19 730 iptables_save_line(str, FALSE);\r
007c44c5 731 }\r
732 \r
f64d5431 733 if(ip_count > idxtable_treshold1 && !just_flush)\r
007c44c5 734 {\r
0b9c3c19 735 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
e0161edb 736 char *subnet, *buf;\r
007c44c5 737 /*-----------------------------------------------------------------*/\r
738 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
739 /*-----------------------------------------------------------------*/\r
740\r
0b9c3c19 741 iptables_save_line(":post_common - [0:0]", FALSE);\r
742 iptables_save_line(":forw_common - [0:0]", FALSE);\r
743 if(ip6prefix)\r
744 {\r
745 iptables_save_line(":post_common - [0:0]", TRUE);\r
746 iptables_save_line(":forw_common - [0:0]", TRUE);\r
747 }\r
007c44c5 748\r
0b9c3c19 749 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
007c44c5 750 {\r
0b9c3c19 751 if(ip->v6)\r
752 {\r
753 buf=index6_id(ip->addr,bitmask+32);\r
754 }\r
755 else\r
756 {\r
757 buf=index_id(ip->addr, bitmask);\r
758 }\r
759 \r
208112af 760 if_exists(idx,idxs,eq(idx->id,buf))\r
761 {\r
007c44c5 762 idx->children++;\r
208112af 763 }\r
007c44c5 764 else\r
765 {\r
766 create(idx,Index);\r
0b9c3c19 767 idx->addr = ip->addr;\r
768 idx->id = buf;\r
769 idx->bitmask = bitmask+32*ip->v6;\r
770 idx->parent = NULL;\r
771 idx->children = 0;\r
772 idx->ipv6 = ip->v6;\r
007c44c5 773 idxcount++;\r
774 push(idx,idxs);\r
775 }\r
776 }\r
777\r
778 /* brutal perfomance optimalization */\r
f64d5431 779 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
007c44c5 780 {\r
f64d5431 781 bitmask -= idxtable_bitmask2;\r
782 idxcount = 0;\r
208112af 783\r
6cc38f96 784 for_each(idx,idxs) if(idx->parent == NULL)\r
007c44c5 785 {\r
0b9c3c19 786 if(idx->ipv6)\r
787 {\r
788 buf = index6_id(idx->addr, bitmask+32);\r
789 }\r
790 else\r
791 {\r
792 buf = index_id(idx->addr, bitmask);\r
793 }\r
208112af 794 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
795 {\r
796 metaindex->children++;\r
797 }\r
007c44c5 798 else\r
799 {\r
800 create(metaindex,Index);\r
0b9c3c19 801 metaindex->addr = idx->addr;\r
802 metaindex->id = buf;\r
803 metaindex->bitmask = bitmask+32*idx->ipv6;\r
804 metaindex->parent = NULL;\r
805 metaindex->children = 0;\r
806 metaindex->ipv6 = idx->ipv6;\r
007c44c5 807 idxcount++;\r
808 push(metaindex,idxs);\r
809 }\r
810 idx->parent=metaindex;\r
811 }\r
812 }\r
813\r
f64d5431 814 /* this should slightly optimize throughput ... */\r
007c44c5 815 sort(idx,idxs,desc_order_by,children);\r
816 sort(idx,idxs,order_by,bitmask);\r
817\r
818 i=0;\r
208112af 819 for_each(idx,idxs)\r
007c44c5 820 {\r
0b9c3c19 821 if(idx->ipv6)\r
822 {\r
823 subnet=subnet6_id(idx->addr, idx->bitmask);\r
824 }\r
825 else\r
826 {\r
827 subnet=subnet_id(idx->addr, idx->bitmask);\r
828 }\r
829 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
007c44c5 830 \r
831 sprintf(str,":post_%s - [0:0]", idx->id);\r
0b9c3c19 832 iptables_save_line(str, idx->ipv6);\r
007c44c5 833\r
834 sprintf(str,":forw_%s - [0:0]", idx->id);\r
0b9c3c19 835 iptables_save_line(str, idx->ipv6);\r
007c44c5 836\r
837 if(idx->parent)\r
838 {\r
839 string(buf,strlen(idx->parent->id)+6);\r
0b9c3c19 840 sprintf(buf,"post_%s", idx->parent->id);\r
007c44c5 841 }\r
842 else\r
bb9e11ee 843 {\r
007c44c5 844 buf="POSTROUTING";\r
bb9e11ee 845 }\r
007c44c5 846\r
847 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
0b9c3c19 848 iptables_save_line(str, idx->ipv6);\r
007c44c5 849\r
850 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
0b9c3c19 851 iptables_save_line(str, idx->ipv6);\r
007c44c5 852\r
853 if(idx->parent)\r
854 {\r
855 string(buf,strlen(idx->parent->id)+6);\r
856 sprintf(buf,"forw_%s",idx->parent->id);\r
857 }\r
858 else\r
bb9e11ee 859 {\r
007c44c5 860 buf="FORWARD";\r
bb9e11ee 861 }\r
007c44c5 862\r
863 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
0b9c3c19 864 iptables_save_line(str, idx->ipv6);\r
007c44c5 865\r
866 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
0b9c3c19 867 iptables_save_line(str, idx->ipv6);\r
007c44c5 868 }\r
869 printf("Total indexed iptables chains created: %d\n", i);\r
870\r
871 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
0b9c3c19 872 iptables_save_line(str, FALSE);\r
007c44c5 873 \r
874 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
0b9c3c19 875 iptables_save_line(str, FALSE);\r
876\r
877 if(ip6prefix)\r
878 {\r
879 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
880 iptables_save_line(str, TRUE);\r
881 \r
882 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
883 iptables_save_line(str, TRUE);\r
884 }\r
007c44c5 885 }\r
007c44c5 886 }\r
887\r
888 if(just_flush)\r
889 {\r
890 fclose(iptables_file);\r
add90548 891 if(log_file)\r
892 { \r
893 fclose(log_file);\r
894 }\r
007c44c5 895 puts("Just flushed iptables and tc classes - now exiting ...");\r
896 exit(0);\r
897 }\r
898\r
899 if(!just_preview)\r
900 {\r
901 if(!dry_run && !nodelay && qos_free_delay)\r
902 {\r
903 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
904 sleep(qos_free_delay);\r
905 }\r
906\r
6cc38f96 907 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
908 tc,lan,htb_r2q);\r
007c44c5 909 safe_run(str);\r
910\r
208112af 911 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
912 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);\r
007c44c5 913 safe_run(str);\r
914\r
208112af 915 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
916 tc,lan,line,line,burst_main,highest_priority);\r
007c44c5 917 safe_run(str);\r
918\r
919 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
920 safe_run(str);\r
921\r
208112af 922 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
923 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);\r
007c44c5 924 safe_run(str);\r
925\r
208112af 926 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
927 tc,wan,up,up,burst_main,highest_priority);\r
007c44c5 928 safe_run(str);\r
929 }\r
930\r
931 /*-----------------------------------------------------------------*/\r
208112af 932 puts("Locating heavy downloaders and generating root classes ...");\r
007c44c5 933 /*-----------------------------------------------------------------*/\r
bb9e11ee 934 sort(ip,ips,desc_order_by,traffic); \r
007c44c5 935\r
936 /*-----------------------------------------------------------------*/\r
937 /* sub-scope - local variables */ \r
938 {\r
6cc38f96 939 long long int rate = line;\r
940 long long int max = line;\r
941 int group_count = 0;\r
942 FILE *credit_file = NULL;\r
007c44c5 943 \r
4358455e 944 if(!just_preview && !dry_run && enable_credit)\r
945 {\r
6cc38f96 946 credit_file = fopen(credit,"w");\r
4358455e 947 }\r
007c44c5 948 \r
208112af 949 for_each(group,groups)\r
007c44c5 950 {\r
951 if(!just_preview)\r
952 {\r
007c44c5 953 //download\r
208112af 954 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #down desired %d", \r
955 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
007c44c5 956 safe_run(str);\r
957 \r
958 //upload\r
208112af 959 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #up desired %d", \r
960 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);\r
007c44c5 961 safe_run(str);\r
962 }\r
963 \r
6cc38f96 964 if(group_count++ < max_nesting)\r
bb9e11ee 965 {\r
6cc38f96 966 parent = group->id;\r
bb9e11ee 967 }\r
007c44c5 968 \r
6cc38f96 969 rate -= digital_divide*group->min;\r
970 if(rate < group->min)\r
4358455e 971 {\r
6cc38f96 972 rate = group->min;\r
4358455e 973 }\r
007c44c5 974 \r
975 /*shaping of aggresive downloaders, with credit file support */\r
976 if(use_credit)\r
977 {\r
6cc38f96 978 int group_rate = group->min, priority_sequence = lowest_priority;\r
007c44c5 979 \r
6cc38f96 980 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
007c44c5 981 {\r
e48d46c9 982 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
983 if( ip->keyword->data_limit \r
984 and not ip->fixedprio \r
985 and ip->traffic > ip->realquota )\r
007c44c5 986 {\r
e48d46c9 987 if(group_rate < ip->max)\r
4358455e 988 {\r
e48d46c9 989 ip->max = group_rate;\r
4358455e 990 }\r
007c44c5 991 group_rate+=magic_treshold;\r
208112af 992 ip->prio=lowest_priority;\r
4358455e 993 if(ip->prio<highest_priority+2)\r
994 {\r
995 ip->prio=highest_priority+2;\r
996 }\r
007c44c5 997 }\r
998 else\r
999 {\r
6cc38f96 1000 if( ip->keyword->data_prio \r
1001 && !ip->fixedprio \r
f71cfa3b 1002 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
007c44c5 1003 {\r
1004 ip->prio=priority_sequence--;\r
4358455e 1005 if(ip->prio<highest_priority+1)\r
1006 {\r
1007 ip->prio=highest_priority+1;\r
1008 }\r
007c44c5 1009 }\r
1010 \r
1011 if(credit_file)\r
1012 {\r
1013 unsigned long long lcredit=0;\r
99127c70 1014 \r
4358455e 1015 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1016 {\r
007c44c5 1017 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
4358455e 1018 }\r
007c44c5 1019 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1020 }\r
1021 }\r
6cc38f96 1022 } \r
007c44c5 1023 }\r
1024 }\r
4358455e 1025 if(credit_file)\r
1026 {\r
1027 fclose(credit_file);\r
1028 }\r
007c44c5 1029 }\r
1030\r
1031 if(just_preview)\r
1032 {\r
62b118c2 1033 if(start_shaping || stop_shaping || reduce_ceil)\r
8e29188a 1034 {\r
1035 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap);\r
1036 parse(classmap)\r
1037 {\r
1038 ptr=strchr(_,' ');\r
1039 if(ptr)\r
1040 {\r
1041 *ptr=0;\r
1042 ptr++;\r
1043 if_exists(ip,ips,eq(ip->addr,_))\r
1044 {\r
1045 ip->mark=atoi(ptr);\r
62b118c2 1046 if(ip->max < ip->desired || stop_shaping || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
8e29188a 1047 {\r
3f76726a 1048 if(stop_shaping)\r
1049 {\r
1050 ip->max = ip->desired;\r
1051 printf("Removing limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark); \r
1052 }\r
1053 else\r
1054 {\r
62b118c2 1055 printf("Applying limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark);\r
1056 if(reduce_ceil)\r
1057 {\r
1058 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1059 }\r
3f76726a 1060 }\r
8e29188a 1061 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1062 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1063 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);\r
1064 safe_run(str);\r
1065 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1066 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1067 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1068 tc, wan, ip->group, ip->mark,\r
1069 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1070 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1071 safe_run(str);\r
1072 }\r
1073 }\r
1074 }\r
1075 }\r
1076 fail\r
1077 { \r
1078 perror(classmap);\r
1079 puts("Warning - classmap file not fund, just generating preview ...");\r
1080 start_shaping=FALSE;\r
3f76726a 1081 stop_shaping=FALSE;\r
8e29188a 1082 }\r
1083 done; /* ugly macro end */\r
1084 }\r
6fb3c58a 1085 html=preview;\r
1ab008b9 1086 json_traffic=json_preview;\r
007c44c5 1087 }\r
6fb3c58a 1088\r
1089 if(!dry_run && !just_flush)\r
007c44c5 1090 {\r
1091 /*-----------------------------------------------------------------*/\r
1ab008b9 1092 printf("Writing json traffic overview %s ... ", json_traffic);\r
007c44c5 1093 /*-----------------------------------------------------------------*/\r
1ab008b9 1094 write_json_traffic(json_traffic);\r
007c44c5 1095\r
0b9c3c19 1096 /*-----------------------------------------------------------------*/\r
1097 printf("Writing statistics into HTML page %s ...\n", html);\r
1098 /*-----------------------------------------------------------------*/\r
1099 write_htmlandlogs(html, d, total, just_preview);\r
1100 }\r
007c44c5 1101\r
1102 if(just_preview)\r
1103 {\r
8e29188a 1104 char swchar='p';\r
1105 if(start_shaping)\r
1106 {\r
1107 swchar='s';\r
1108 }\r
62b118c2 1109 else if(reduce_ceil)\r
1110 {\r
1111 swchar='0'+reduce_ceil; /* -2, -4 */\r
1112 }\r
3f76726a 1113 else if(stop_shaping)\r
1114 {\r
1115 swchar='q';\r
1116 }\r
1117\r
8e29188a 1118 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
007c44c5 1119 exit(0);\r
be96b71b 1120 } \r
007c44c5 1121\r
1122 i=0;\r
260c2719 1123#ifdef DEBUG\r
007c44c5 1124 printf("%-22s %-15s mark\n","name","ip");\r
260c2719 1125#endif\r
208112af 1126\r
14e28c6f 1127 printf("Writing %s", classmap); \r
be96b71b 1128 f = fopen(classmap, "w"); \r
1129 if(f < 0)\r
1130 {\r
1131 perror(classmap);\r
1132 }\r
1133\r
1134 /*-----------------------------------------------------------------*/\r
0995c4ad 1135 printf(" + generating iptables and tc classes ... ");\r
be96b71b 1136 /*-----------------------------------------------------------------*/\r
1137\r
0b9c3c19 1138 for_each(ip, ips) if(ip->mark > 0) /* works only for IPv4 so far */\r
be96b71b 1139 {\r
007c44c5 1140 if(idxs)\r
1141 {\r
1142 char *buf;\r
1143 duplicate(ip->addr,buf);\r
0b9c3c19 1144 if(ip->v6)\r
1145 {\r
1146 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1147 }\r
1148 else\r
1149 {\r
1150 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1151 }\r
007c44c5 1152 \r
1153 string(chain_forward,6+strlen(buf));\r
1154 strcpy(chain_forward,"forw_");\r
1155 strcat(chain_forward,buf);\r
1156\r
1157 string(chain_postrouting,6+strlen(buf));\r
1158 strcpy(chain_postrouting,"post_");\r
1159 strcat(chain_postrouting,buf);\r
1160 \r
1161 free(buf);\r
1162 }\r
1163 else\r
1164 {\r
1165 chain_forward="FORWARD";\r
1166 chain_postrouting="POSTROUTING";\r
1167 }\r
1168\r
a25842fa 1169 /* packet limits - this will be optional in future */\r
06733b88 1170 if(ip->pps_limit)\r
1171 {\r
8e7aa995 1172 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1173 ip->pps_limit, ip->pps_limit);\r
06733b88 1174 }\r
1175 else\r
1176 {\r
1177 *limit_pkts = 0;\r
1178 } \r
1179\r
260c2719 1180#ifdef DEBUG\r
06733b88 1181 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
260c2719 1182#endif\r
007c44c5 1183\r
06733b88 1184 /* -------------------------------------------------------- mark download */ \r
0b9c3c19 1185 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
c38473c1 1186 chain_postrouting, ip->addr, 32*(1+ip->v6),\r
1187 lan, mark_iptables, ip->mark);\r
0b9c3c19 1188 iptables_save_line(str, ip->v6);\r
007c44c5 1189\r
a25842fa 1190/*\r
007c44c5 1191 if(qos_proxy)\r
1192 {\r
0b9c3c19 1193 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/%d -o %s -j %s%d",\r
c38473c1 1194 chain_postrouting, proxy_ip, proxy_port, ip->addr,\r
1195 32*(1+ip->v6), lan, mark_iptables, ip->mark);\r
0b9c3c19 1196 iptables_save_line(str, ip->v6);\r
007c44c5 1197 }\r
a25842fa 1198*/\r
c38473c1 1199 sprintf(str, "-A %s -d %s/%d -o %s %s-j ACCEPT",\r
1200 chain_postrouting, ip->addr, 32*(1+ip->v6), lan, limit_pkts);\r
0b9c3c19 1201 iptables_save_line(str, ip->v6);\r
007c44c5 1202\r
a25842fa 1203 /* classify overlimit packets to separate overlimit class */\r
1204 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1205 chain_postrouting, ip->addr, 32*(1+ip->v6),\r
1206 lan, mark_iptables, OVERLIMIT_CLASS);\r
1207 iptables_save_line(str, ip->v6);\r
1208\r
1209 sprintf(str, "-A %s -d %s/%d -o %s -j ACCEPT",\r
1210 chain_postrouting, ip->addr, 32*(1+ip->v6), lan);\r
1211 iptables_save_line(str, ip->v6);\r
1212\r
007c44c5 1213 /* -------------------------------------------------------- mark upload */\r
0b9c3c19 1214 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1215 chain_forward, ip->addr, 32*(1+ip->v6), wan, mark_iptables, ip->mark);\r
1216 iptables_save_line(str, ip->v6);\r
007c44c5 1217\r
c38473c1 1218 sprintf(str, "-A %s -s %s/%d -o %s %s-j ACCEPT",\r
1219 chain_forward, ip->addr, 32*(1+ip->v6), wan, limit_pkts);\r
0b9c3c19 1220 iptables_save_line(str, ip->v6);\r
007c44c5 1221\r
a25842fa 1222 /* classify overlimit packets to separate overlimit class */\r
1223 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1224 chain_forward, ip->addr, 32*(1+ip->v6), wan, mark_iptables, OVERLIMIT_CLASS);\r
1225 iptables_save_line(str, ip->v6);\r
1226\r
1227 sprintf(str, "-A %s -s %s/%d -o %s -j ACCEPT",\r
1228 chain_forward, ip->addr, 32*(1+ip->v6), wan);\r
1229 iptables_save_line(str, ip->v6);\r
1230\r
007c44c5 1231 if(ip->min)\r
1232 {\r
1233 /* -------------------------------------------------------- download class */\r
260c2719 1234#ifdef DEBUG\r
007c44c5 1235 printf("(down: %dk-%dk ", ip->min, ip->max); \r
260c2719 1236#endif\r
007c44c5 1237\r
be96b71b 1238 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
c38473c1 1239 tc, lan, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
007c44c5 1240 safe_run(str);\r
1241\r
260c2719 1242 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
dee5592e 1243 {\r
0b9c3c19 1244 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1245 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1246 safe_run(str);\r
be96b71b 1247 }\r
1248\r
260c2719 1249 if(filter_type == 1)\r
dee5592e 1250 {\r
0b9c3c19 1251 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1252 tc, lan, ip->mark, ip->mark);\r
1253 safe_run(str);\r
007c44c5 1254 }\r
1255\r
1256 /* -------------------------------------------------------- upload class */\r
260c2719 1257#ifdef DEBUG\r
007c44c5 1258 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1259 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
260c2719 1260#endif\r
007c44c5 1261\r
1262 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1263 tc, wan, ip->group, ip->mark,\r
1264 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1265 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1266 safe_run(str);\r
1267 \r
260c2719 1268 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
dee5592e 1269 {\r
0b9c3c19 1270 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",\r
1271 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1272 safe_run(str);\r
dee5592e 1273 } \r
be96b71b 1274\r
260c2719 1275 if(filter_type == 1)\r
dee5592e 1276 {\r
0b9c3c19 1277 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1278 tc, wan, ip->mark, ip->mark);\r
1279 safe_run(str);\r
007c44c5 1280 }\r
be96b71b 1281 \r
6fb3c58a 1282 if(f > 0)\r
be96b71b 1283 {\r
0b9c3c19 1284 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
be96b71b 1285 }\r
007c44c5 1286 }\r
1287 else\r
260c2719 1288 {\r
1289#ifdef DEBUG\r
007c44c5 1290 printf("(sharing %s)\n", ip->sharing);\r
260c2719 1291#endif\r
1292 }\r
007c44c5 1293 i++;\r
1294 }\r
6fb3c58a 1295 if(f > 0)\r
be96b71b 1296 {\r
1297 puts("done.");\r
1298 fclose(f);\r
1299 }\r
1300 \r
007c44c5 1301 if(idxs)\r
1302 {\r
0b9c3c19 1303 chain_forward = "forw_common";\r
1304 chain_postrouting = "post_common";\r
007c44c5 1305 }\r
1306 else\r
1307 {\r
0b9c3c19 1308 chain_forward = "FORWARD";\r
1309 chain_postrouting = "POSTROUTING";\r
007c44c5 1310 }\r
0b9c3c19 1311\r
1312 if(free_min)\r
007c44c5 1313 {\r
0b9c3c19 1314 final_chain = "ACCEPT";\r
1315 }\r
1316\r
a25842fa 1317/*\r
0b9c3c19 1318 if(qos_proxy)\r
1319 {\r
1320 if(free_min) \r
1321 {\r
1322 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s%d",\r
1323 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables, 3);\r
a25842fa 1324 iptables_save_line(str, FALSE); // only for IPv4\r
0b9c3c19 1325 }\r
1326 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s",\r
1327 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);\r
a25842fa 1328 iptables_save_line(str, FALSE); // only for IPv4\r
0b9c3c19 1329 }\r
a25842fa 1330*/\r
0b9c3c19 1331\r
1332 if(free_min)\r
1333 {\r
1334 sprintf(str, "-A %s -o %s -j %s%d",\r
a25842fa 1335 chain_postrouting, lan, mark_iptables, FREE_CLASS);\r
0b9c3c19 1336 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1337 }\r
1338\r
1339 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1340 iptables_save_line(str, FALSE);\r
1341 if(ip6prefix)\r
1342 {\r
1343 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1344 iptables_save_line(str, TRUE);\r
1345 }\r
1346\r
1347 if(free_min)\r
1348 {\r
a25842fa 1349 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, FREE_CLASS);\r
0b9c3c19 1350 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1351 }\r
1352\r
1353 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);\r
1354 iptables_save_line(str, FALSE);\r
1355 if(ip6prefix)\r
1356 {\r
1357 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1358 iptables_save_line(str, TRUE);\r
007c44c5 1359 }\r
abe9b855 1360\r
dee5592e 1361 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1362 {\r
1363 /*-----------------------------------------------------------------*/\r
a25842fa 1364 puts("Generating free bandwith class ...");\r
dee5592e 1365 /*-----------------------------------------------------------------*/\r
a25842fa 1366 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1367 tc, lan, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority);\r
dee5592e 1368 safe_run(str);\r
a25842fa 1369 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1370 tc, wan, parent, FREE_CLASS, free_min, free_max, burst, lowest_priority);\r
dee5592e 1371 safe_run(str);\r
1372 /* tc SFQ */\r
260c2719 1373 if(strcmpi(qos_leaf, "none"))\r
dee5592e 1374 {\r
a25842fa 1375 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
dee5592e 1376 safe_run(str);\r
1377 \r
a25842fa 1378 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, wan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
dee5592e 1379 safe_run(str);\r
1380 } \r
1381 /* tc handle 1 fw flowid */\r
a25842fa 1382 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, FREE_CLASS, FREE_CLASS);\r
1383 safe_run(str);\r
1384\r
1385 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, wan, FREE_CLASS, FREE_CLASS);\r
dee5592e 1386 safe_run(str);\r
007c44c5 1387\r
a25842fa 1388 /*-----------------------------------------------------------------*/\r
1389 puts("Generating bandwith class for overlimit packets...");\r
1390 /*-----------------------------------------------------------------*/\r
1391 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
73cf6e9d 1392 tc, lan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
a25842fa 1393 safe_run(str);\r
1394 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
73cf6e9d 1395 tc, wan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
dee5592e 1396 safe_run(str);\r
007c44c5 1397 }\r
dee5592e 1398 printf("Total IP count: %d\n", i);\r
0b9c3c19 1399 run_iptables_restore();\r
260c2719 1400 if(log_file)\r
1401 {\r
1402 fclose(log_file);\r
1403 }\r
007c44c5 1404 return 0;\r
007c44c5 1405 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1406 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1407}\r
This page took 3.409617 seconds and 4 git commands to generate.