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