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