should be completely fixed now
[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 just_logs = FALSE; /* just parse logs */
476 int run = FALSE;
477 int total = 0;
478
479 char *chain_forward, *chain_postrouting;
480 char *althosts=NULL;
481
482 printf("\n\
483 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
484 Version %s - Copyright (C)2005-2013 Michael Polak, Arachne Labs\n\
485 iptables-restore & burst tunning & classify modification by Ludva\n\
486 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
487
488 /*----- Boring... we have to check command line options first: ----*/
489 arguments
490 {
491 argument("-c") { nextargument(config); }
492 argument("-h") { nextargument(althosts);}
493 argument("-d") { run=TRUE; dry_run=TRUE; }
494 argument("-f") { run=TRUE; just_flush=TRUE; }
495 argument("-9") { run=TRUE; just_flush=9; }
496 argument("-p") { run=TRUE; just_preview=TRUE; }
497 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }
498 argument("-r") { run=TRUE; }
499 argument("-n") { run=TRUE; nodelay=TRUE; }
500 argument("-l") { just_logs=TRUE; }
501 argument("-m") { just_logs=TRUE; }
502 argument("-y") { just_logs=TRUE; }
503 argument("-?") { help(); exit(0); }
504 argument("--help") { help(); exit(0); }
505 argument("-v") { exit(0); }
506 argument("--version") { exit(0); }
507 }
508
509 if(dry_run)
510 {
511 puts("*** THIS IS JUST DRY RUN ! ***\n");
512 }
513
514 date(d); /* this is typical cll1.h macro - prints current date */
515
516 /*-----------------------------------------------------------------*/
517 printf("Parsing configuration file %s ...\n", config);
518 /*-----------------------------------------------------------------*/
519 get_config(config);
520
521 if(just_logs)
522 {
523 parse_ip_log(argc,argv);
524 exit(0);
525 }
526 else if(not run)
527 {
528 help();
529 exit(0);
530 }
531
532 if(althosts)
533 {
534 hosts=althosts;
535 }
536
537 if(just_flush<9)
538 {
539 /*-----------------------------------------------------------------*/
540 puts("Parsing iptables verbose output ...");
541 /*-----------------------------------------------------------------*/
542 get_traffic_statistics(iptables, FALSE);
543 if(ip6prefix)
544 {
545 /*-----------------------------------------------------------------*/
546 puts("Parsing ip6tables verbose output ...");
547 /*-----------------------------------------------------------------*/
548 get_traffic_statistics(ip6tables, TRUE);
549 }
550 }
551
552 /*-----------------------------------------------------------------*/
553 printf("Parsing class defintion file %s ...\n", hosts);
554 /*-----------------------------------------------------------------*/
555 parse_hosts(hosts);
556
557 /*-----------------------------------------------------------------*/
558 /* cll1.h - let's allocate brand new character buffer... */
559 /*-----------------------------------------------------------------*/
560 string(str,STRLEN);
561
562 /*-----------------------------------------------------------------*/
563 puts("Resolving shared connections ...");
564 /*-----------------------------------------------------------------*/
565 for_each(ip,ips) if(ip->sharing)
566 {
567 for_each(sharedip,ips) if(eq(sharedip->name, ip->sharing))
568 {
569 sharedip->traffic += ip->traffic;
570 ip->traffic = 0;
571 ip->mark = sharedip->mark;
572 ip->lmsid = sharedip->lmsid;
573 break;
574 }
575 if(not sharedip)
576 {
577 printf("Unresolved shared connection: %s %s sharing-%s\n",
578 ip->addr, ip->name, ip->sharing);
579 }
580 }
581
582 if(enable_credit && just_flush<9)
583 {
584 /*-----------------------------------------------------------------*/
585 printf("Parsing credit file %s ...\n", credit);
586 /*-----------------------------------------------------------------*/
587 parse(credit)
588 {
589 ptr=parse_datafile_line(_);
590 if(ptr)
591 {
592 if_exists(ip,ips,eq(ip->addr,_))
593 {
594 sscanf(ptr,"%Lu",&(ip->credit));
595 }
596 }
597 }
598 done; /* ugly macro end */
599 }
600
601 if(!just_preview)
602 {
603 /*-----------------------------------------------------------------*/
604 puts("Initializing iptables and tc classes ...");
605 /*-----------------------------------------------------------------*/
606
607 iptables_file = fopen(iptablesfile, "w");
608 if(iptables_file == NULL)
609 {
610 perror(iptablesfile);
611 exit(-1);
612 }
613 iptables_save_line(iptablespreamble, FALSE);
614
615 if(ip6prefix)
616 {
617 ip6tables_file = fopen(ip6tablesfile, "w");
618 if(ip6tables_file == NULL)
619 {
620 perror(ip6tablesfile);
621 exit(-1);
622 }
623 iptables_save_line(iptablespreamble, TRUE);
624 iptables_save_line(ip6preamble, TRUE);
625 }
626
627 run_iptables_restore();
628
629 log_file = fopen(cmdlog, "w");
630 if(log_file == NULL)
631 {
632 perror(cmdlog);
633 exit(-1);
634 }
635
636 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
637 safe_run(str);
638
639 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
640 safe_run(str);
641
642 iptables_file=fopen(iptablesfile,"w");
643 iptables_save_line(iptablespreamble, FALSE);
644 if(ip6prefix)
645 {
646 ip6tables_file=fopen(ip6tablesfile,"w");
647 iptables_save_line(iptablespreamble, TRUE);
648 iptables_save_line(ip6preamble, TRUE);
649 }
650
651 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */
652 {
653 char *chain;
654
655 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
656 iptables_save_line(str, FALSE); /* this is currently supported only for IPv4 */
657
658 if(qos_proxy)
659 {
660 iptables_save_line(":post_noproxy - [0:0]", FALSE);
661 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);
662 iptables_save_line(str , FALSE);
663 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);
664 iptables_save_line(str, FALSE);
665 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
666 iptables_save_line(str, FALSE);
667
668 chain="post_noproxy";
669 }
670 else
671 {
672 chain="POSTROUTING";
673 }
674
675 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
676 iptables_save_line(str, FALSE);
677 }
678
679 if(ip_count > idxtable_treshold1 && !just_flush)
680 {
681 int idxcount=0, bitmask=32-idxtable_bitmask1;
682 char *subnet, *buf;
683 /*-----------------------------------------------------------------*/
684 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
685 /*-----------------------------------------------------------------*/
686
687 iptables_save_line(":post_common - [0:0]", FALSE);
688 iptables_save_line(":forw_common - [0:0]", FALSE);
689 if(ip6prefix)
690 {
691 iptables_save_line(":post_common - [0:0]", TRUE);
692 iptables_save_line(":forw_common - [0:0]", TRUE);
693 }
694
695 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
696 {
697 if(ip->v6)
698 {
699 buf=index6_id(ip->addr,bitmask+32);
700 }
701 else
702 {
703 buf=index_id(ip->addr, bitmask);
704 }
705
706 if_exists(idx,idxs,eq(idx->id,buf))
707 {
708 idx->children++;
709 }
710 else
711 {
712 create(idx,Index);
713 idx->addr = ip->addr;
714 idx->id = buf;
715 idx->bitmask = bitmask+32*ip->v6;
716 idx->parent = NULL;
717 idx->children = 0;
718 idx->ipv6 = ip->v6;
719 idxcount++;
720 push(idx,idxs);
721 }
722 }
723
724 /* brutal perfomance optimalization */
725 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)
726 {
727 bitmask -= idxtable_bitmask2;
728 idxcount = 0;
729
730 for_each(idx,idxs) if(idx->parent == NULL)
731 {
732 if(idx->ipv6)
733 {
734 buf = index6_id(idx->addr, bitmask+32);
735 }
736 else
737 {
738 buf = index_id(idx->addr, bitmask);
739 }
740 if_exists(metaindex,idxs,eq(metaindex->id,buf))
741 {
742 metaindex->children++;
743 }
744 else
745 {
746 create(metaindex,Index);
747 metaindex->addr = idx->addr;
748 metaindex->id = buf;
749 metaindex->bitmask = bitmask+32*idx->ipv6;
750 metaindex->parent = NULL;
751 metaindex->children = 0;
752 metaindex->ipv6 = idx->ipv6;
753 idxcount++;
754 push(metaindex,idxs);
755 }
756 idx->parent=metaindex;
757 }
758 }
759
760 /* this should slightly optimize throughput ... */
761 sort(idx,idxs,desc_order_by,children);
762 sort(idx,idxs,order_by,bitmask);
763
764 i=0;
765 for_each(idx,idxs)
766 {
767 if(idx->ipv6)
768 {
769 subnet=subnet6_id(idx->addr, idx->bitmask);
770 }
771 else
772 {
773 subnet=subnet_id(idx->addr, idx->bitmask);
774 }
775 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);
776
777 sprintf(str,":post_%s - [0:0]", idx->id);
778 iptables_save_line(str, idx->ipv6);
779
780 sprintf(str,":forw_%s - [0:0]", idx->id);
781 iptables_save_line(str, idx->ipv6);
782
783 if(idx->parent)
784 {
785 string(buf,strlen(idx->parent->id)+6);
786 sprintf(buf,"post_%s", idx->parent->id);
787 }
788 else
789 {
790 buf="POSTROUTING";
791 }
792
793 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
794 iptables_save_line(str, idx->ipv6);
795
796 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
797 iptables_save_line(str, idx->ipv6);
798
799 if(idx->parent)
800 {
801 string(buf,strlen(idx->parent->id)+6);
802 sprintf(buf,"forw_%s",idx->parent->id);
803 }
804 else
805 {
806 buf="FORWARD";
807 }
808
809 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
810 iptables_save_line(str, idx->ipv6);
811
812 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
813 iptables_save_line(str, idx->ipv6);
814 }
815 printf("Total indexed iptables chains created: %d\n", i);
816
817 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
818 iptables_save_line(str, FALSE);
819
820 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
821 iptables_save_line(str, FALSE);
822
823 if(ip6prefix)
824 {
825 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
826 iptables_save_line(str, TRUE);
827
828 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
829 iptables_save_line(str, TRUE);
830 }
831 }
832 }
833
834 if(just_flush)
835 {
836 fclose(iptables_file);
837 if(log_file)
838 {
839 fclose(log_file);
840 }
841 puts("Just flushed iptables and tc classes - now exiting ...");
842 exit(0);
843 }
844
845 if(!just_preview)
846 {
847 if(!dry_run && !nodelay && qos_free_delay)
848 {
849 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
850 sleep(qos_free_delay);
851 }
852
853 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
854 tc,lan,htb_r2q);
855 safe_run(str);
856
857 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
858 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
859 safe_run(str);
860
861 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
862 tc,lan,line,line,burst_main,highest_priority);
863 safe_run(str);
864
865 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
866 safe_run(str);
867
868 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
869 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
870 safe_run(str);
871
872 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
873 tc,wan,up,up,burst_main,highest_priority);
874 safe_run(str);
875 }
876
877 /*-----------------------------------------------------------------*/
878 puts("Locating heavy downloaders and generating root classes ...");
879 /*-----------------------------------------------------------------*/
880 sort(ip,ips,desc_order_by,traffic);
881
882 /*-----------------------------------------------------------------*/
883 /* sub-scope - local variables */
884 {
885 long long int rate = line;
886 long long int max = line;
887 int group_count = 0;
888 FILE *credit_file = NULL;
889
890 if(!just_preview && !dry_run && enable_credit)
891 {
892 credit_file = fopen(credit,"w");
893 }
894
895 for_each(group,groups)
896 {
897 if(!just_preview)
898 {
899 //download
900 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",
901 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
902 safe_run(str);
903
904 //upload
905 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",
906 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
907 safe_run(str);
908 }
909
910 if(group_count++ < max_nesting)
911 {
912 parent = group->id;
913 }
914
915 rate -= digital_divide*group->min;
916 if(rate < group->min)
917 {
918 rate = group->min;
919 }
920
921 /*shaping of aggresive downloaders, with credit file support */
922 if(use_credit)
923 {
924 int group_rate = group->min, priority_sequence = lowest_priority;
925
926 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
927 {
928 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));
929 if( ip->keyword->data_limit
930 and not ip->fixedprio
931 and ip->traffic > ip->realquota )
932 {
933 if(group_rate < ip->max)
934 {
935 ip->max = group_rate;
936 }
937 group_rate+=magic_treshold;
938 ip->prio=lowest_priority;
939 if(ip->prio<highest_priority+2)
940 {
941 ip->prio=highest_priority+2;
942 }
943 }
944 else
945 {
946 if( ip->keyword->data_prio
947 && !ip->fixedprio
948 && ( ip->traffic>ip->credit
949 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
950 {
951 ip->prio=priority_sequence--;
952 if(ip->prio<highest_priority+1)
953 {
954 ip->prio=highest_priority+1;
955 }
956 }
957
958 if(credit_file)
959 {
960 unsigned long long lcredit=0;
961
962 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
963 {
964 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
965 }
966 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
967 }
968 }
969 }
970 }
971 }
972 if(credit_file)
973 {
974 fclose(credit_file);
975 }
976 }
977
978 if(just_preview)
979 {
980 if(start_shaping)
981 {
982 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap);
983 parse(classmap)
984 {
985 ptr=strchr(_,' ');
986 if(ptr)
987 {
988 *ptr=0;
989 ptr++;
990 if_exists(ip,ips,eq(ip->addr,_))
991 {
992 ip->mark=atoi(ptr);
993 if(ip->max < ip->desired) /* apply FUP limit immediately.... */
994 {
995 printf("Applying limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
996 printf("(down: %dk-%dk ", ip->min, ip->max);
997 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
998 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
999 safe_run(str);
1000 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1001 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1002 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1003 tc, wan, ip->group, ip->mark,
1004 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1005 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1006 safe_run(str);
1007 }
1008 }
1009 }
1010 }
1011 fail
1012 {
1013 perror(classmap);
1014 puts("Warning - classmap file not fund, just generating preview ...");
1015 start_shaping=FALSE;
1016 }
1017 done; /* ugly macro end */
1018 }
1019 html=preview;
1020 json_traffic=json_preview;
1021 }
1022
1023 if(!dry_run && !just_flush)
1024 {
1025 /*-----------------------------------------------------------------*/
1026 printf("Writing json traffic overview %s ... ", json_traffic);
1027 /*-----------------------------------------------------------------*/
1028 write_json_traffic(json_traffic);
1029
1030 /*-----------------------------------------------------------------*/
1031 printf("Writing statistics into HTML page %s ...\n", html);
1032 /*-----------------------------------------------------------------*/
1033 write_htmlandlogs(html, d, total, just_preview);
1034 }
1035
1036 if(just_preview)
1037 {
1038 char swchar='p';
1039 if(start_shaping)
1040 {
1041 swchar='s';
1042 }
1043 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);
1044 exit(0);
1045 }
1046
1047 i=0;
1048 #ifdef DEBUG
1049 printf("%-22s %-15s mark\n","name","ip");
1050 #endif
1051
1052 printf("Writing %s", classmap);
1053 f = fopen(classmap, "w");
1054 if(f < 0)
1055 {
1056 perror(classmap);
1057 }
1058
1059 /*-----------------------------------------------------------------*/
1060 printf(" + generating iptables and tc classes ... ");
1061 /*-----------------------------------------------------------------*/
1062
1063 for_each(ip, ips) if(ip->mark > 0) /* works only for IPv4 so far */
1064 {
1065 if(idxs)
1066 {
1067 char *buf;
1068 duplicate(ip->addr,buf);
1069 if(ip->v6)
1070 {
1071 buf=index6_id(ip->addr,64-idxtable_bitmask1);
1072 }
1073 else
1074 {
1075 buf=index_id(ip->addr,32-idxtable_bitmask1);
1076 }
1077
1078 string(chain_forward,6+strlen(buf));
1079 strcpy(chain_forward,"forw_");
1080 strcat(chain_forward,buf);
1081
1082 string(chain_postrouting,6+strlen(buf));
1083 strcpy(chain_postrouting,"post_");
1084 strcat(chain_postrouting,buf);
1085
1086 free(buf);
1087 }
1088 else
1089 {
1090 chain_forward="FORWARD";
1091 chain_postrouting="POSTROUTING";
1092 }
1093
1094 #ifdef DEBUG
1095 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1096 #endif
1097
1098 /* -------------------------------------------------------- mark download */
1099
1100 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",
1101 chain_postrouting, ip->addr, 32*(1+ip->v6), lan, mark_iptables, ip->mark);
1102 /* -m limit --limit 1/s */
1103 iptables_save_line(str, ip->v6);
1104
1105 if(qos_proxy)
1106 {
1107 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/%d -o %s -j %s%d",
1108 chain_postrouting, proxy_ip, proxy_port, ip->addr, 32*(1+ip->v6), lan, mark_iptables, ip->mark);
1109 iptables_save_line(str, ip->v6);
1110 }
1111
1112 sprintf(str, "-A %s -d %s/%d -o %s -j ACCEPT",
1113 chain_postrouting, ip->addr, 32*(1+ip->v6), lan);
1114 iptables_save_line(str, ip->v6);
1115
1116 /* -------------------------------------------------------- mark upload */
1117 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d",
1118 chain_forward, ip->addr, 32*(1+ip->v6), wan, mark_iptables, ip->mark);
1119 iptables_save_line(str, ip->v6);
1120
1121 sprintf(str, "-A %s -s %s/%d -o %s -j ACCEPT",
1122 chain_forward, ip->addr, 32*(1+ip->v6), wan);
1123 iptables_save_line(str, ip->v6);
1124
1125 if(ip->min)
1126 {
1127 /* -------------------------------------------------------- download class */
1128 #ifdef DEBUG
1129 printf("(down: %dk-%dk ", ip->min, ip->max);
1130 #endif
1131
1132 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1133 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1134 safe_run(str);
1135
1136 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1137 {
1138 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1139 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1140 safe_run(str);
1141 }
1142
1143 if(filter_type == 1)
1144 {
1145 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1146 tc, lan, ip->mark, ip->mark);
1147 safe_run(str);
1148 }
1149
1150 /* -------------------------------------------------------- upload class */
1151 #ifdef DEBUG
1152 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1153 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1154 #endif
1155
1156 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1157 tc, wan, ip->group, ip->mark,
1158 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1159 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1160 safe_run(str);
1161
1162 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1163 {
1164 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1165 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1166 safe_run(str);
1167 }
1168
1169 if(filter_type == 1)
1170 {
1171 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1172 tc, wan, ip->mark, ip->mark);
1173 safe_run(str);
1174 }
1175
1176 if(f > 0)
1177 {
1178 fprintf(f, "%s %d\n", ip->addr, ip->mark);
1179 }
1180 }
1181 else
1182 {
1183 #ifdef DEBUG
1184 printf("(sharing %s)\n", ip->sharing);
1185 #endif
1186 }
1187 i++;
1188 }
1189 if(f > 0)
1190 {
1191 puts("done.");
1192 fclose(f);
1193 }
1194
1195 if(idxs)
1196 {
1197 chain_forward = "forw_common";
1198 chain_postrouting = "post_common";
1199 }
1200 else
1201 {
1202 chain_forward = "FORWARD";
1203 chain_postrouting = "POSTROUTING";
1204 }
1205
1206 if(free_min)
1207 {
1208 final_chain = "ACCEPT";
1209 }
1210
1211 if(qos_proxy)
1212 {
1213 if(free_min)
1214 {
1215 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
1216 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables, 3);
1217 iptables_save_line(str, FALSE); /* only for IPv4 */
1218 }
1219 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s",
1220 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
1221 iptables_save_line(str, FALSE); /* only for IPv4 */
1222 }
1223
1224 if(free_min)
1225 {
1226 sprintf(str, "-A %s -o %s -j %s%d",
1227 chain_postrouting, lan, mark_iptables, 3);
1228 iptables_save_line(str, FALSE); /* only for IPv4 */
1229 }
1230
1231 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
1232 iptables_save_line(str, FALSE);
1233 if(ip6prefix)
1234 {
1235 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
1236 iptables_save_line(str, TRUE);
1237 }
1238
1239 if(free_min)
1240 {
1241 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);
1242 iptables_save_line(str, FALSE); /* only for IPv4 */
1243 }
1244
1245 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);
1246 iptables_save_line(str, FALSE);
1247 if(ip6prefix)
1248 {
1249 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
1250 iptables_save_line(str, TRUE);
1251 }
1252
1253 if(free_min) /* allocate free bandwith if it is not zero... */
1254 {
1255 /*-----------------------------------------------------------------*/
1256 puts("Generating free bandwith classes ...");
1257 /*-----------------------------------------------------------------*/
1258 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1259 tc, lan, parent, free_min, free_max,burst, lowest_priority);
1260 safe_run(str);
1261 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1262 tc, wan, parent, free_min, free_max, burst, lowest_priority);
1263 safe_run(str);
1264 /* tc SFQ */
1265 if(strcmpi(qos_leaf, "none"))
1266 {
1267 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);
1268 safe_run(str);
1269
1270 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);
1271 safe_run(str);
1272 }
1273 /* tc handle 1 fw flowid */
1274 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);
1275 safe_run(str);
1276
1277 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);
1278 safe_run(str);
1279 }
1280 printf("Total IP count: %d\n", i);
1281 run_iptables_restore();
1282 if(log_file)
1283 {
1284 fclose(log_file);
1285 }
1286 return 0;
1287 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1288 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1289 }
This page took 0.914676 seconds and 5 git commands to generate.