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