9853a5a169de8b41c1fa80c928fe6e5e303a2abd
[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-2008 Michael Polak (xChaos) */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
9
10 /* Modified by: xChaos, 20110427
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 #define STRLEN 256
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
32 #undef DEBUG
33
34 #include "cll1-0.6.2.h"
35
36 const char *version = "0.8.3";
37
38 /* Version numbers: 0.8.3 is development releases ("beta"), 0.8.4 will be "stable" */
39 /* Debian(RPM) package versions/patchlevels: 0.7.9-2, 0.8.0-1, 0.8.0-2, etc. */
40 /* C source code development versions ("beta"): 0.7.9-a, 0.8.1-b, etc. */
41 /* C source code release versions: 0.8.0, 0.8.2, 0.8.4, etc. */
42
43 const char *stats_html_signature = "<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005-2011 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n";
44
45 /* ======= All path names are defined here (for RPM patch) ======= */
46
47 char *tc = "/sbin/tc"; /* requires tc with HTB support */
48 char *iptables = "/sbin/iptables"; /* requires iptables utility */
49 char *iptablessave = "/sbin/iptables-save"; /* not yet required */
50 char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */
51 const char *ls = "/bin/ls"; /* this is not user configurable :-) */
52
53 char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
55
56 char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
57 char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */
58 char *html = "/var/www/traffic.html"; /* hall of fame filename */
59 char *preview = "/var/www/preview.html"; /* hall of fame preview */
60 char *cmdlog = "/var/log/prometheuslog"; /* command log filename */
61 char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */
62 char *log_url = "logs/"; /* log directory relative URI prefix (partial URL) */
63 char *html_log_dir = "/var/www/logs/html/";
64
65 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
66
67 void help(void)
68 {
69 puts("Command line switches:\n\
70 \n\
71 -?, --help this help screen\n\
72 -v, --version show Version number of this utility and exit\n\
73 -c filename force alternative /etc/prometheus.Conf filename\n\
74 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
75 -f just Flush iptables and tc classes and exit (stop shaping)\n\
76 -9 emergency iptables flush (do not read data transfer statistics)\n\
77 -p just generate Preview of data transfer statistics and exit\n\
78 -d Dry run (preview tc and iptables commands on stdout)\n\
79 -r Run (reset all statistics and start shaping)\n\
80 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
81 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
82 -m generate HTML summary of traffic logs for yesterday's Month\n\
83 -y generate HTML summary of traffic logs for yesterday's Year\n");
84 /* not yet implemented:
85 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
86 */
87 }
88 /* === Configuraration file values defaults - stored in global variables ==== */
89
90 int filter_type = 1; /*1 mark, 2 classify*/
91 char *mark = "MARK";
92 char *mark_iptables = "MARK --set-mark ";
93 int dry_run = 0; /* preview - use puts() instead of system() */
94 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]";
95 FILE *iptables_file = NULL;
96 int enable_credit = 1; /* enable credit file */
97 int use_credit = 0; /* use credit file (if enabled)*/
98 char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */
99 int hall_of_fame = 1; /* enable hall of fame */
100 char *lan = "eth0"; /* LAN interface */
101 char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
102 char *wan = "eth1"; /* WAN/ISP interface */
103 char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
104 char *qos_leaf = "sfq perturb 5"; /* leaf discipline */
105 char *qos_free_zone = NULL; /* QoS free zone */
106 int qos_proxy = 1; /* include proxy port to QoS */
107 int found_lmsid = 0; /* show links to users in LMS information system */
108 int include_upload = 1; /* upload+download=total traffic */
109 char *proxy_ip = "192.168.1.1/32"; /* our IP with proxy port */
110 int proxy_port = 3128; /* proxy port number */
111 long long int line = 1024; /* WAN/ISP download in kbps */
112 long long int up = 1024; /* WAN/ISP upload in kbps */
113 int free_min = 32; /* minimum guaranted bandwidth for all undefined hosts */
114 int free_max = 64; /* maximum allowed bandwidth for all undefined hosts */
115 int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */
116 int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */
117 int max_nesting = 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
118 int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */
119 int burst = 8; /* HTB burst (in kbits) */
120 int burst_main = 64;
121 int burst_group = 32;
122 int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
123 int keywordcount = 0;
124 /* not yet implemented:
125 int fixed_packets = 0; maximum number of pps per IP address (not class!)
126 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
127 */
128 FILE *log_file = NULL;
129 char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
130
131 const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */
132 const int lowest_priority = 7; /* lowest HTB priority (HTB built-in value is 7) */
133 const int idxtable_treshold1 = 24; /* this is no longer configurable */
134 const int idxtable_treshold2 = 12; /* this is no longer configurable */
135 const int idxtable_bitmask1 = 3; /* this is no longer configurable */
136 const int idxtable_bitmask2 = 3; /* this is no longer configurable */
137
138 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
139
140 struct IP
141 {
142 char *addr;
143 char *name;
144 char *sharing;
145 int min;
146 int desired;
147 int max;
148 int mark;
149 int prio;
150 int fixedprio;
151 int group;
152 int lmsid;
153 unsigned long long direct;
154 unsigned long long proxy;
155 unsigned long long upload;
156 unsigned long long traffic;
157 unsigned long long credit;
158 unsigned long pktsup;
159 unsigned long pktsdown;
160 struct Keyword *keyword;
161 list(IP);
162 } *ips=NULL, *ip, *sharedip;
163
164 struct Group
165 {
166 int min;
167 int count;
168 int desired;
169 int id;
170 list(Group);
171 } *groups=NULL, *group;
172
173 struct Index
174 {
175 char *addr;
176 char *id;
177 struct Index *parent;
178 int bitmask;
179 int children;
180 list(Index);
181 } *idxs=NULL, *idx, *metaindex;
182
183 struct Keyword
184 {
185 char *key;
186
187 int asymetry_ratio; /* ratio for ADSL-like upload */
188 int asymetry_fixed; /* fixed treshold for ADSL-like upload */
189 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
190 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
191 long fixed_limit; /* fixed data limit for setting lower HTB ceil */
192 long fixed_prio; /* fixed data lmit for setting lower HTB prio */
193 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */
194 int reserve_max; /* malus for nominal HTB ceil (in kbps) */
195 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
196 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
197 int default_prio; /* default HTB priority for this keyword */
198 char *html_color;
199 int ip_count;
200 char *leaf_discipline;
201
202 list(Keyword);
203 } *keyword,*defaultkeyword=NULL,*keywords=NULL;
204
205 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
206
207 void TheIP(void)
208 {
209 create(ip,IP);
210 ip->name = "";
211 ip->addr = "";
212 ip->sharing = NULL;
213 ip->prio = highest_priority+1;
214 ip->lmsid = \
215 ip->fixedprio = \
216 ip->mark = \
217 ip->min = \
218 ip->max = \
219 ip->desired = \
220 ip->credit = \
221 ip->upload = \
222 ip->proxy = \
223 ip->direct = \
224 ip->traffic = \
225 ip->pktsup = \
226 ip->pktsdown = 0;
227 ip->keyword = keywords;
228 push(ip,ips);
229 }
230
231 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
232
233 char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)
234 {
235 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
236 int dot=0,n;
237 char *ip,*outip,*outptr,*fmt;
238
239 duplicate(inip,ip);
240 /* debug printf("(%s,%d) -> ",ip,bitmask); */
241
242 if(ip && *ip && bitmask>=0 && bitmask<=32)
243 {
244 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
245 }
246 else
247 {
248 /* should never exit here */
249 return "undefined";
250 }
251 outptr=outip;
252 while(ip && *ip)
253 {
254 if(*ip=='.')
255 {
256 if(dot<(bitmask/8-1))
257 {
258 if(format_as_chainname)
259 {
260 *outptr='_';
261 }
262 else
263 {
264 *outptr='.';
265 }
266 outptr++;
267 dot++;
268 }
269 else
270 {
271 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/
272 if(cutdot)*cutdot='\0';
273 if(format_as_chainname)
274 fmt="_%d_%d";
275 else
276 fmt=".%d";
277 if(bitmask%8)
278 n=atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));
279 else
280 n=0;
281
282 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
283 sprintf(outptr,fmt,n,bitmask);
284 if(!format_as_chainname) while(bitmask<24)
285 {
286 strcat(outip,".0");
287 bitmask+=8;
288 }
289 /* debug printf("[%s]\n",outip); */
290 return outip;
291 }
292 }
293 else
294 {
295 *outptr=*ip;
296 outptr++;
297 }
298 ip++;
299 }
300 /*should never exit here*/
301 *outptr='\0';
302 return outip;
303 }
304
305 char *hash_id(char *ip,int bitmask)
306 { return very_ugly_ipv4_code(ip,bitmask,1); }
307
308 char *subnet_id(char *ip,int bitmask)
309 { return very_ugly_ipv4_code(ip,bitmask,0); }
310
311 /* ================= Let's parse configuration file here =================== */
312
313 void reject_config_and_exit(char *filename)
314 {
315 printf("Configuration file %s rejected - abnormal exit.",filename);
316 exit(-1);
317 }
318
319 void get_config(char *config_filename)
320 {
321 char *cnf="mark";
322
323 printf("Configured keywords: ");
324 parse(config_filename)
325 {
326 option("keyword",kwd);
327 if(kwd)
328 {
329 printf("%s ",kwd);
330
331 create(keyword,Keyword);
332 keyword->key=kwd;
333 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
334 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
335 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
336 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
337 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
338 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
339 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
340 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
341 keyword->default_prio=highest_priority+1;
342 keyword->html_color="000000";
343 keyword->ip_count=0;
344 keyword->leaf_discipline="";
345
346 push(keyword,keywords);
347 if(!defaultkeyword) defaultkeyword=keyword;
348 keywordcount++;
349
350 kwd=NULL;
351 }
352 else
353 {
354 for_each(keyword,keywords)
355 {
356 int l=strlen(keyword->key);
357
358 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
359 {
360 char *tmptr=_; /* <---- l+1 ----> */
361 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
362 ioption("asymetry-ratio",keyword->asymetry_ratio);
363 ioption("asymetry-treshold",keyword->asymetry_fixed);
364 ioption("magic-relative-limit",keyword->data_limit);
365 ioption("magic-relative-prio",keyword->data_prio);
366 loption("magic-fixed-limit",keyword->fixed_limit);
367 loption("magic-fixed-prio",keyword->fixed_prio);
368 ioption("htb-default-prio",keyword->default_prio);
369 ioption("htb-rate-bonus",keyword->reserve_min);
370 ioption("htb-ceil-malus",keyword->reserve_max);
371 option("leaf-discipline",keyword->leaf_discipline);
372 option("html-color",keyword->html_color);
373 _=tmptr;
374
375 if(keyword->data_limit || keyword->fixed_limit ||
376 keyword->data_prio || keyword->fixed_prio)
377 {
378 use_credit=1;
379 }
380 }
381 }
382 }
383
384 option("tc",tc);
385 option("iptables",iptables);
386 option("iptables-save",iptablessave); /* new */
387 option("iptables-restore",iptablesrestore); /* new */
388 option("iptables-file",iptablesfile); /* new */
389 option("hosts",hosts);
390 option("lan-interface",lan);
391 option("wan-interface",wan);
392 option("lan-medium",lan_medium);
393 option("wan-medium",wan_medium);
394 lloption("wan-download",line);
395 lloption("wan-upload",up);
396 ioption("hall-of-fame-enable",hall_of_fame);
397 option("hall-of-fame-title",title);
398 option("hall-of-fame-filename",html);
399 option("hall-of-fame-preview",preview);
400 option("log-filename",cmdlog);
401 option("credit-filename",credit);
402 ioption("credit-enable",enable_credit);
403 option("log-traffic-directory",log_dir);
404 option("log-traffic-html-directory",html_log_dir);
405 option("log-traffic-url-path",log_url);
406 option("qos-free-zone",qos_free_zone);
407 ioption("qos-free-delay",qos_free_delay);
408 ioption("qos-proxy-enable",qos_proxy);
409 option("qos-proxy-ip",proxy_ip);
410 option("htb-leaf-discipline",qos_leaf);
411 ioption("qos-proxy-port",proxy_port);
412 ioption("free-rate",free_min);
413 ioption("free-ceil",free_max);
414 ioption("htb-burst",burst);
415 ioption("htb-burst-main",burst_main);
416 ioption("htb-burst-group",burst_group);
417 ioption("htb-nesting-limit",max_nesting);
418 ioption("htb-r2q",htb_r2q);
419 ioption("magic-include-upload",include_upload);
420 ioption("magic-treshold",magic_treshold);
421 option("filter-type", cnf);
422
423 /* not yet implemented:
424 ioption("magic-fixed-packets",fixed_packets);
425 ioption("magic-relative-packets",packet_limit);
426 */
427 }
428 fail
429 {
430 perror(config_filename);
431 puts("Warning - using built-in defaults instead ...");
432 }
433 done;
434 printf("\n");
435
436 /*leaf discipline for keywords*/
437 for_each(keyword,keywords)
438 {
439 if (!strcmpi(keyword->leaf_discipline, ""))
440 {
441 keyword->leaf_discipline = qos_leaf;
442 }
443 }
444
445 if (strcmpi(cnf, "mark"))
446 {
447 filter_type = 2;
448 mark = "CLASSIFY";
449 mark_iptables = "CLASSIFY --set-class 1:";
450 }
451 else
452 {
453 filter_type = 1;
454 mark = "MARK";
455 mark_iptables = "MARK --set-mark ";
456 }
457
458 /* are supplied values meaningful ?*/
459 if(line<=0 || up<=0)
460 {
461 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
462 reject_config_and_exit(config_filename);
463 }
464 }
465
466 /* ===================== traffic analyser - uses iptables ================ */
467
468 void get_traffic_statistics(void)
469 {
470 char *str,*cmd;
471 int downloadflag=0;
472
473 textfile(Pipe,str) *line,*lines=NULL;
474 string(str,STRLEN);
475 string(cmd,STRLEN);
476
477 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
478 shell(cmd);
479 input(str,STRLEN)
480 {
481 create(line,Pipe);
482 line->str=str;
483 string(str,STRLEN);
484 append(line,lines);
485 }
486
487 for_each(line,lines)
488 {
489 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
490 unsigned long long traffic=0;
491 unsigned long pkts=0;
492 char *ipaddr=NULL,*ptr;
493
494 /* debug puts(line->str); */
495 valid_columns(ptr,line->str,' ',col)
496 if(valid) switch(col)
497 {
498 case 1: if(eq(ptr,"Chain"))
499 setchainname=1;
500 else if(eq(ptr,"pkts"))
501 valid=0;
502 else
503 sscanf(ptr,"%lu",&pkts);
504 break;
505 case 2: if(setchainname)
506 {
507 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
508 downloadflag=1;
509 else
510 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
511 downloadflag=0;
512
513 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
514 commonflag=1;
515 }
516 else
517 sscanf(ptr,"%Lu",&traffic); traffic+=(1<<19); traffic>>=20;
518 break;
519 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)
520 accept=eq(ptr,mark);
521 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
522 break;
523 case 8: if(downloadflag)
524 {
525 if(strstr(proxy_ip,ptr))proxyflag=1;
526 }
527 else
528 ipaddr=ptr;
529 break;
530 case 9: if(downloadflag)ipaddr=ptr;break;
531 }
532
533 if(accept && traffic>0 && ipaddr)
534 {
535 if(proxyflag)printf("(proxy) ");
536 else if(!downloadflag) printf("(upload) ");
537 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr, traffic, pkts);
538
539 if_exists(ip,ips,eq(ip->addr,ipaddr));
540 else
541 {
542 TheIP();
543 ip->addr=ipaddr;
544 if(eq(ip->addr,"0.0.0.0/0"))
545 {
546 ip->name="(unregistered)";
547 ip->min=free_min;
548 ip->max=ip->desired=free_max;
549 }
550 }
551
552 if(downloadflag)
553 {
554 if(proxyflag)
555 ip->proxy=traffic;
556 else
557 ip->traffic+=traffic;
558 ip->direct=ip->traffic-ip->upload-ip->proxy;
559 ip->pktsdown=pkts;
560 }
561 else
562 {
563 ip->upload=traffic;
564 ip->pktsup=pkts;
565 if(include_upload)
566 {
567 ip->traffic+=traffic;
568 }
569 else
570 {
571 if(traffic>ip->traffic)
572 {
573 ip->traffic=traffic;
574 }
575 }
576 }
577 }
578 }
579
580 free(cmd);
581 }
582
583 /* ========== This function executes, logs OR ALSO prints command ========== */
584
585 void safe_run(char *cmd)
586 {
587 if(dry_run) printf("\n=>%s\n",cmd); else system(cmd);
588 if(log_file) fprintf(log_file,"%s\n",cmd);
589 }
590
591 void save_line(char *line)
592 {
593 fprintf(iptables_file,"%s\n",line);
594 }
595
596 void run_restore(void)
597 {
598 char *restor, *str;
599 string(restor,STRLEN);
600
601 /*-----------------------------------------------------------------*/
602 printf("Running %s <%s ...\n",iptablesrestore,iptablesfile);
603 /*-----------------------------------------------------------------*/
604
605 save_line("COMMIT");
606 fclose(iptables_file);
607 if(dry_run)
608 {
609 parse(iptablesfile)
610 {
611 str=_;
612 printf("%s\n", str);
613 }done;
614 }
615
616 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);
617 safe_run(restor);
618
619 free(restor);
620 }
621
622 /* == This function strips extra characters after IP address and stores it = */
623
624 void parse_ip(char *str)
625 {
626 char *ptr,*ipaddr=NULL,*ipname=NULL,*lmsid=NULL;
627
628 ptr=strchr(str,'{');
629 if(ptr)
630 {
631 lmsid=++ptr;
632 while(*ptr && *ptr!='}')
633 ptr++;
634 *ptr=0;
635 }
636
637 ptr=str;
638 while(*ptr && *ptr!=' ' && *ptr!=9)
639 ptr++;
640
641 *ptr=0;
642 ipaddr=str;
643 ptr++;
644 while(*ptr && (*ptr==' ' || *ptr==9))
645 ptr++;
646 ipname=ptr;
647 while(*ptr && *ptr!=' ' && *ptr!=9)
648 ptr++;
649 *ptr=0;
650
651 if_exists(ip,ips,eq(ip->addr,ipaddr));
652 else
653 {
654 TheIP();
655 }
656 ip->addr=ipaddr;
657 ip->name=ipname;
658 if(lmsid)
659 {
660 ip->lmsid=atoi(lmsid);
661 found_lmsid=1;
662 }
663 }
664
665 char *parse_datafile_line(char *str)
666 {
667 char *ptr=strchr(str,' ');
668
669 if(ptr)
670 {
671 *ptr=0;
672 ptr++;
673 return ptr;
674 }
675 else
676 {
677 return NULL;
678 }
679 }
680
681 struct IpLog
682 {
683 char *name;
684 long traffic;
685 long guaranted;
686 int i;
687 long l;
688 list(IpLog);
689 } *iplog,*iplogs;
690
691 void parse_ip_log(int argc, char **argv)
692 {
693 char *month, *year, *str, *name="(undefined)", *ptr, *ptr2, *filename;
694 long traffic=0l, traffic_month, total=0, guaranted;
695 int col, col2, y_ok, m_ok, accept_month, i=1, any_month=0, lmsid;
696 char mstr[4], ystr[5];
697 FILE *f;
698 string(str,STRLEN);
699 string(filename,STRLEN);
700
701 if(argv[1][1]=='l') /* -l */
702 {
703 if(argc<4)
704 {
705 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
706 exit(-1);
707 }
708 else
709 {
710 month=argv[2];
711 if(eq(month,"Year")) any_month=1;
712 year=argv[3];
713 }
714 }
715 else
716 {
717 time_t t = time(NULL) - 3600*24 ; /* yesterday's timestamp*/
718 struct tm *timep = localtime(&t);
719
720 if(argv[1][1]=='m') /* -m yestarday - month */
721 {
722 strftime(mstr, 4, "%b", timep);
723 month=mstr;
724 strftime(ystr, 5, "%Y", timep);
725 year=ystr;
726 }
727 else /* -y yesterday - year */
728 {
729 month="Year";
730 any_month=1;
731 strftime(ystr, 5, "%Y", timep);
732 year=ystr;
733 }
734 }
735 printf("Analysing traffic for %s %s ...\n",month,year);
736
737 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
738 sprintf(str,"%s %s/",ls,log_dir);
739 shell(str);
740 input(str,STRLEN)
741 {
742 if(strstr(str,".log"))
743 {
744 ptr=strrchr(str,'\n');
745 if(ptr) *ptr='\0';
746 sprintf(filename,"%s/%s",log_dir,str);
747 printf("Parsing %s ...",filename);
748 accept_month=0;
749 traffic_month=0;
750 guaranted=0;
751 lmsid=0;
752 parse(filename)
753 {
754 y_ok=m_ok=0;
755 valid_columns(ptr,_,'\t',col) switch(col)
756 {
757 case 2: name = ptr;break;
758 case 3: traffic = atol(ptr);break;
759 /* column number - was 7, now 11...*/
760 case 7:
761 case 8:
762 case 9:
763 case 10:
764 case 11: if (isalpha(*ptr)) /* character, not numeric string = date, just one*/
765 {
766 valid_columns(ptr2,ptr,' ',col2) switch(col2)
767 {
768 case 2: if(any_month || eq(ptr2,month)) m_ok = 1; break;
769 case 5: if(eq(ptr2,year)) y_ok = 1; break;
770 }
771 }
772 else
773 {
774 if(col == 7) guaranted = atol(ptr);
775 if(col == 10) lmsid = atoi(ptr);
776 }
777 }
778
779 if(y_ok && m_ok)
780 {
781 traffic_month += traffic;
782 accept_month = 1;
783 }
784 }
785 done;
786
787 if(accept_month)
788 {
789 create(iplog,IpLog);
790 iplog->name = name;
791 iplog->guaranted = guaranted;
792 iplog->traffic = traffic_month;
793 insert(iplog,iplogs,desc_order_by,traffic);
794 printf(" %ld MB\n",iplog->traffic);
795 }
796 else
797 {
798 puts(" no records.");
799 }
800 }
801 }
802 sprintf(str,"%s/%s-%s.html",html_log_dir,year,month);
803 printf("Writing %s ...",str);
804 f=fopen(str,"w");
805 if(f)
806 {
807 fprintf(f,"<table border><tr><th colspan=\"2\">%s %s</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",month,year);
808
809 for_each(iplog,iplogs)
810 {
811 if(iplog->traffic)
812 {
813 fprintf(f,"<tr><td align=\"right\">%d</td><th align=\"left\">%s</td><td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
814 i++, iplog->name, iplog->traffic, iplog->traffic>>10, iplog->guaranted);
815 total+=iplog->traffic>>10;
816 iplog->i=i;
817 iplog->l=total;
818 }
819 }
820 fprintf(f,"<tr><th colspan=\"3\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total, line);
821 fputs("</table>\n", f);
822
823 if(i>10)
824 {
825 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
826 fputs("<tr><td>Analytic category</td>\n",f);
827 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
828
829 if_exists(iplog,iplogs,iplog->l>=total/4)
830 {
831 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
832 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
833 }
834
835 if_exists(iplog,iplogs,iplog->i==10)
836 {
837 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
838 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
839 }
840
841 if_exists(iplog,iplogs,iplog->l>=total/2)
842 {
843 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
844 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
845 }
846
847 if_exists(iplog,iplogs,iplog->l>=4*total/5)
848 {
849 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
850 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
851 }
852
853 if_exists (iplog,iplogs,iplog->i>=i/5)
854 {
855 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
856 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
857 }
858
859 if_exists(iplog,iplogs,iplog->i>=i/4)
860 {
861 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
862 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
863 }
864
865 if_exists(iplog,iplogs,iplog->i>=i/2)
866 {
867 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
868 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
869 }
870
871 if_exists(iplog,iplogs,iplog->i>=4*i/5)
872 {
873 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
874 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
875 }
876
877 fprintf(f,"<tr><td>All users, all traffic</td>\n");
878 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%ld G</th><th align=\"right\">100 %%</th></tr>\n",i-1,total);
879 fputs("</table>\n", f);
880 }
881
882 fprintf(f, stats_html_signature, version);
883 fclose(f);
884 puts(" done.");
885 }
886 }
887
888 /*-----------------------------------------------------------------*/
889 /* Are you looking for int main(int argc, char **argv) ? :-)) */
890 /*-----------------------------------------------------------------*/
891
892 program
893 {
894 int i=0;
895 FILE *f=NULL;
896 char *str, *ptr, *d;
897 char *substring;
898 int class_count=0,ip_count=0;
899 int parent=1;
900 int just_flush=FALSE;
901 int nodelay=FALSE;
902 int just_preview=FALSE; /* preview - generate just stats */
903 int just_logs=FALSE; /* just parse logs */
904 int run=FALSE;
905
906 char *chain_forward, *chain_postrouting;
907 char *althosts=NULL;
908
909 printf("\n\
910 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
911 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
912 iptables-restore & burst tunning & classify modification by Ludva\n\
913 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
914
915 /*----- Boring... we have to check command line options first: ----*/
916
917 arguments
918 {
919 argument("-c") { nextargument(config); }
920 argument("-h") { nextargument(althosts);}
921 argument("-d") { run=TRUE; dry_run=TRUE; }
922 argument("-f") { run=TRUE; just_flush=TRUE; }
923 argument("-9") { run=TRUE; just_flush=9; }
924 argument("-p") { run=TRUE; just_preview=TRUE; }
925 argument("-r") { run=TRUE; }
926 argument("-n") { run=TRUE; nodelay=TRUE; }
927 argument("-l") { just_logs=TRUE; }
928 argument("-m") { just_logs=TRUE; }
929 argument("-y") { just_logs=TRUE; }
930 argument("-?") { help(); exit(0); }
931 argument("--help") { help(); exit(0); }
932 argument("-v") { exit(0); }
933 argument("--version") { exit(0); }
934 }
935
936 if(dry_run)
937 {
938 puts("*** THIS IS JUST DRY RUN ! ***\n");
939 }
940
941 date(d); /* this is typical cll1.h macro - prints current date */
942
943 /*-----------------------------------------------------------------*/
944 printf("Parsing configuration file %s ...\n", config);
945 /*-----------------------------------------------------------------*/
946 get_config(config);
947
948 if(just_logs)
949 {
950 parse_ip_log(argc,argv);
951 exit(0);
952 }
953 else if(not run)
954 {
955 help();
956 exit(0);
957 }
958
959 if(althosts)
960 {
961 hosts=althosts;
962 }
963
964 if(just_flush<9)
965 {
966 /*-----------------------------------------------------------------*/
967 puts("Parsing iptables verbose output ...");
968 /*-----------------------------------------------------------------*/
969 get_traffic_statistics();
970 }
971
972 /*-----------------------------------------------------------------*/
973 printf("Parsing class defintion file %s ...\n", hosts);
974 /*-----------------------------------------------------------------*/
975 int groupidx = FIRSTGROUPID;
976 parse(hosts)
977 {
978 str=_;
979
980 if(*str<'0' || *str>'9')
981 {
982 /* any line starting with non-number is comment ...*/
983 continue;
984 }
985
986 //Does this IP share QoS class with some other ?
987 substring=strstr(str,"sharing-");
988 if(substring)
989 {
990 substring+=8; //"sharing-"
991 parse_ip(str);
992 ip_count++;
993 ip->sharing=substring;
994 ip->keyword=defaultkeyword; /* settings for default keyword */
995 while(*substring && *substring!='\n')
996 {
997 substring++;
998 }
999 *substring=0;
1000 }
1001 else
1002 {
1003 //Do we have to create new QoS class for this IP ?
1004
1005 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))
1006 {
1007 parse_ip(str);
1008 ip_count++;
1009 ip->keyword=keyword;
1010 keyword->ip_count++;
1011 ip->prio=keyword->default_prio;
1012 substring+=strlen(keyword->key)+1;
1013 ptr=substring;
1014 while(*ptr && *ptr!='-')
1015 {
1016 ptr++;
1017 }
1018 if(*ptr=='-')
1019 {
1020 *ptr=0;
1021 ip->max=ip->desired=atoi(ptr+1);
1022 }
1023 ip->min=atoi(substring);
1024 if(ip->min<=0)
1025 {
1026 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str,free_min);
1027 ip->min=free_min;
1028 }
1029 if(ip->max<=ip->min)
1030 {
1031 ip->fixedprio=1;
1032 ip->max=ip->min+ip->keyword->reserve_min;
1033 }
1034 else
1035 {
1036 ip->max-=ip->keyword->reserve_max;
1037 if(ip->max<ip->min)
1038 {
1039 ip->max=ip->min;
1040 }
1041 }
1042 ip->mark=FIRSTIPCLASS+1+class_count++;
1043
1044 if_exists(group,groups,group->min==ip->min)
1045 {
1046 group->count++;
1047 group->desired+=ip->min;
1048 ip->group = group->id;
1049 }
1050 else
1051 {
1052 create(group,Group);
1053 group->min=ip->min;
1054 group->id = groupidx++;
1055 ip->group = group->id;
1056
1057 if(group->min<8) group->min=8;
1058 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1059 /* it is because class IDs are derived from min. bandwidth. - xCh */
1060 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1061
1062 group->count=1;
1063 group->desired=ip->min;
1064 insert(group,groups,desc_order_by,min);
1065 }
1066 }//endif keyword-
1067 }//endif sharing-
1068 }
1069 fail
1070 {
1071 perror(hosts);
1072 exit(-1);
1073 }
1074 done;
1075
1076 /*-----------------------------------------------------------------*/
1077 /* cll1.h - let's allocate brand new character buffer... */
1078 /*-----------------------------------------------------------------*/
1079 string(str,STRLEN);
1080
1081 /*-----------------------------------------------------------------*/
1082 puts("Resolving shared connections ...");
1083 /*-----------------------------------------------------------------*/
1084 for_selected(ip,ips,ip->sharing)
1085 {
1086 for_selected(sharedip,ips,eq(sharedip->name,ip->sharing))
1087 {
1088 sharedip->traffic+=ip->traffic;
1089 ip->traffic=0;
1090 ip->mark=sharedip->mark;
1091 break;
1092 }
1093 if(!sharedip)
1094 {
1095 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);
1096 }
1097 }
1098
1099 if(enable_credit && just_flush<9)
1100 {
1101 /*-----------------------------------------------------------------*/
1102 printf("Parsing credit file %s ...\n", credit);
1103 /*-----------------------------------------------------------------*/
1104 parse(credit)
1105 {
1106 ptr=parse_datafile_line(_);
1107 if(ptr)
1108 {
1109 if_exists(ip,ips,eq(ip->addr,_))
1110 {
1111 sscanf(ptr,"%Lu",&(ip->credit));
1112 }
1113 }
1114 }
1115 done;
1116 }
1117
1118 if(!just_preview)
1119 {
1120 /*-----------------------------------------------------------------*/
1121 puts("Initializing iptables and tc classes ...");
1122 /*-----------------------------------------------------------------*/
1123
1124 iptables_file=fopen(iptablesfile,"w");
1125 if (iptables_file == NULL)
1126 {
1127 puts("Cannot open iptablesfile!");
1128 exit(-1);
1129 }
1130
1131 log_file=fopen(cmdlog,"w");
1132 if (log_file == NULL)
1133 {
1134 puts("Cannot open logfile!");
1135 exit(-1);
1136 }
1137
1138 save_line(iptablespreamble);
1139 run_restore();
1140
1141 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
1142 safe_run(str);
1143
1144 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
1145 safe_run(str);
1146
1147 iptables_file=fopen(iptablesfile,"w");
1148 save_line(iptablespreamble);
1149
1150 if(qos_free_zone && *qos_free_zone!='0')
1151 {
1152 char *chain;
1153
1154 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
1155 save_line(str);
1156
1157 if(qos_proxy)
1158 {
1159 save_line(":post_noproxy - [0:0]");
1160 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
1161 save_line(str);
1162 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
1163 save_line(str);
1164 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
1165 save_line(str);
1166
1167 chain="post_noproxy";
1168 }
1169 else
1170 {
1171 chain="POSTROUTING";
1172 }
1173
1174 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1175 save_line(str);
1176 }
1177
1178 if(ip_count>idxtable_treshold1 && !just_flush)
1179 {
1180 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1181 char *subnet, *buf;
1182 /*-----------------------------------------------------------------*/
1183 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1184 /*-----------------------------------------------------------------*/
1185
1186 save_line(":post_common - [0:0]");
1187 save_line(":forw_common - [0:0]");
1188
1189 for_selected(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1190 {
1191 buf=hash_id(ip->addr,bitmask);
1192 if_exists(idx,idxs,eq(idx->id,buf))
1193 {
1194 idx->children++;
1195 }
1196 else
1197 {
1198 create(idx,Index);
1199 idx->addr=ip->addr;
1200 idx->id=buf;
1201 idx->bitmask=bitmask;
1202 idx->parent=NULL;
1203 idx->children=0;
1204 idxcount++;
1205 push(idx,idxs);
1206 }
1207 }
1208
1209 /* brutal perfomance optimalization */
1210 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1211 {
1212 bitmask-=idxtable_bitmask2;
1213 idxcount=0;
1214
1215 for_selected(idx,idxs,idx->parent==NULL)
1216 {
1217 buf=hash_id(idx->addr,bitmask);
1218 if_exists(metaindex,idxs,eq(metaindex->id,buf))
1219 {
1220 metaindex->children++;
1221 }
1222 else
1223 {
1224 create(metaindex,Index);
1225 metaindex->addr=idx->addr;
1226 metaindex->id=buf;
1227 metaindex->bitmask=bitmask;
1228 metaindex->parent=NULL;
1229 metaindex->children=0;
1230 idxcount++;
1231 push(metaindex,idxs);
1232 }
1233 idx->parent=metaindex;
1234 }
1235 }
1236
1237 /* this should slightly optimize throughout ... */
1238 sort(idx,idxs,desc_order_by,children);
1239 sort(idx,idxs,order_by,bitmask);
1240
1241 i=0;
1242 for_each(idx,idxs)
1243 {
1244 subnet=subnet_id(idx->addr,idx->bitmask);
1245 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);
1246
1247 sprintf(str,":post_%s - [0:0]", idx->id);
1248 save_line(str);
1249
1250 sprintf(str,":forw_%s - [0:0]", idx->id);
1251 save_line(str);
1252
1253 if(idx->parent)
1254 {
1255 string(buf,strlen(idx->parent->id)+6);
1256 sprintf(buf,"post_%s",idx->parent->id);
1257 }
1258 else
1259 {
1260 buf="POSTROUTING";
1261 }
1262
1263 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1264 save_line(str);
1265
1266 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1267 save_line(str);
1268
1269 if(idx->parent)
1270 {
1271 string(buf,strlen(idx->parent->id)+6);
1272 sprintf(buf,"forw_%s",idx->parent->id);
1273 }
1274 else
1275 {
1276 buf="FORWARD";
1277 }
1278
1279 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1280 save_line(str);
1281
1282 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1283 save_line(str);
1284 }
1285 printf("Total indexed iptables chains created: %d\n", i);
1286
1287 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1288 save_line(str);
1289
1290 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1291 save_line(str);
1292 }
1293
1294 }
1295
1296 if(just_flush)
1297 {
1298 fclose(iptables_file);
1299 if (log_file) fclose(log_file);
1300 puts("Just flushed iptables and tc classes - now exiting ...");
1301 exit(0);
1302 }
1303
1304 if(!just_preview)
1305 {
1306 if(!dry_run && !nodelay && qos_free_delay)
1307 {
1308 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1309 sleep(qos_free_delay);
1310 }
1311
1312 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);
1313 safe_run(str);
1314
1315 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1316 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
1317 safe_run(str);
1318
1319 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1320 tc,lan,line,line,burst_main,highest_priority);
1321 safe_run(str);
1322
1323 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1324 safe_run(str);
1325
1326 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1327 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
1328 safe_run(str);
1329
1330 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1331 tc,wan,up,up,burst_main,highest_priority);
1332 safe_run(str);
1333 }
1334
1335 /*-----------------------------------------------------------------*/
1336 puts("Locating heavy downloaders and generating root classes ...");
1337 /*-----------------------------------------------------------------*/
1338 sort(ip,ips,desc_order_by,traffic);
1339
1340 /*-----------------------------------------------------------------*/
1341 /* sub-scope - local variables */
1342 {
1343 long long int rate=line;
1344 long long int max=line;
1345 int group_count=0;
1346 FILE *credit_file=NULL;
1347
1348 if(!just_preview && !dry_run && enable_credit)
1349 {
1350 credit_file=fopen(credit,"w");
1351 }
1352
1353 for_each(group,groups)
1354 {
1355 if(!just_preview)
1356 {
1357 //download
1358 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",
1359 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
1360 safe_run(str);
1361
1362 //upload
1363 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",
1364 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
1365 safe_run(str);
1366 }
1367
1368 if(group_count++<max_nesting)
1369 {
1370 parent=group->id;
1371 }
1372
1373 rate-=digital_divide*group->min;
1374 if(rate<group->min)
1375 {
1376 rate=group->min;
1377 }
1378
1379 /*shaping of aggresive downloaders, with credit file support */
1380 if(use_credit)
1381 {
1382 int group_rate=group->min, priority_sequence=lowest_priority;
1383
1384 for_selected(ip, ips, ip->min==group->min && ip->max>ip->min)
1385 {
1386 if( ip->keyword->data_limit && !ip->fixedprio &&
1387 ip->traffic>ip->credit+
1388 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )
1389 {
1390 if(group_rate<ip->max)
1391 {
1392 ip->max=group_rate;
1393 }
1394 group_rate+=magic_treshold;
1395 ip->prio=lowest_priority;
1396 if(ip->prio<highest_priority+2)
1397 {
1398 ip->prio=highest_priority+2;
1399 }
1400 }
1401 else
1402 {
1403 if( ip->keyword->data_prio && !ip->fixedprio &&
1404 ip->traffic>ip->credit+
1405 (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )
1406 {
1407 ip->prio=priority_sequence--;
1408 if(ip->prio<highest_priority+1)
1409 {
1410 ip->prio=highest_priority+1;
1411 }
1412 }
1413
1414 if(credit_file)
1415 {
1416 unsigned long long lcredit=0;
1417
1418 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1419 {
1420 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1421 }
1422 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1423 }
1424 }
1425 }
1426
1427 }
1428 }
1429 if(credit_file)
1430 {
1431 fclose(credit_file);
1432 }
1433 }
1434
1435 if(just_preview)
1436 {
1437 f=fopen(preview,"w");
1438 ptr=preview;
1439 }
1440 else if(!dry_run && !just_flush)
1441 {
1442 /*-----------------------------------------------------------------*/
1443 printf("Writing data transfer database ...\n");
1444 /*-----------------------------------------------------------------*/
1445 f=fopen("/var/run/prometheus.previous","w");
1446 if(f)
1447 {
1448 for_selected(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)
1449 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);
1450 fclose(f);
1451 }
1452
1453 f=fopen(html,"w");
1454 ptr=html;
1455 }
1456
1457 if(f)
1458 {
1459 int total=0;
1460 int count=1;
1461 i=0;
1462
1463 /*-----------------------------------------------------------------*/
1464 printf("Sorting data and generating statistics page %s ...\n",ptr);
1465 /*-----------------------------------------------------------------*/
1466
1467 fputs("<table border>\n<tr><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f);
1468 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);
1469 fputs("</tr>\n",f);
1470
1471 for_each(group,groups)
1472 {
1473 #ifdef DEBUG
1474 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);
1475 #endif
1476 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);
1477 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);
1478
1479 for_each(keyword,keywords)
1480 {
1481 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit);
1482 }
1483 i+=group->desired;
1484 total+=group->count;
1485 count++;
1486 }
1487 #ifdef DEBUG
1488 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);
1489 #endif
1490 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);
1491 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);
1492
1493 for_each(keyword,keywords)
1494 {
1495 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count);
1496 }
1497 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));
1498 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);
1499
1500 fputs("</table>\n",f);
1501 }
1502 else if(!dry_run && !just_flush)
1503 perror(html);
1504
1505 i=1;
1506 if(f)
1507 {
1508 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1509 int active_classes=0;
1510 int colspan;
1511 FILE *iplog;
1512 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1513
1514 colspan=11;
1515 if(qos_proxy)
1516 {
1517 colspan++;
1518 }
1519 if(found_lmsid)
1520 {
1521 colspan++;
1522 }
1523
1524 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);
1525 fprintf(f," (%s)</th></tr>\n", d);
1526 fputs("<tr><td align=\"right\">#</td><td>hostname</td>",f);
1527 if(found_lmsid)
1528 {
1529 fputs("<td align=\"right\">lms</td>\n",f);
1530 }
1531 fputs("<td align=\"right\">credit</td>\
1532 <td align=\"right\">limit</td>\
1533 <td align=\"right\">total</td>\
1534 <td align=\"right\">direct</td>\n",f);
1535 if(qos_proxy)
1536 {
1537 fputs("<td align=\"right\">proxy</td>\n",f);
1538 }
1539 fputs("<td align=\"right\">upload</td>\
1540 <td align=\"right\">minimum</td>\
1541 <td align=\"right\">desired</td>\
1542 <td align=\"right\">maximum</td>\
1543 <td>prio</td></tr>\n",f);
1544
1545 for_each(ip,ips)
1546 {
1547 char *f1="", *f2="";
1548 if(ip->max<ip->desired)
1549 {
1550 f1="<font color=\"red\">";
1551 f2="</font>";
1552 }
1553 else if(ip->prio>highest_priority+1)
1554 {
1555 f1="<font color=\"brown\">";
1556 f2="</font>";
1557 }
1558
1559 #ifdef DEBUG
1560 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1561 #endif
1562 fprintf(f,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td>\n", ip->name, i, log_url, ip->name, ip->name);
1563 if(found_lmsid)
1564 {
1565 fputs("<td align=\"right\">",f);
1566 if(ip->lmsid)
1567 {
1568 /*base URL will be configurable soon ... */
1569 fprintf(f,"<a href=\"https://hermes.spoje.net/?m=customerinfo&amp;id=%d\">%04d</a>\n", ip->lmsid, ip->lmsid);
1570 }
1571 fputs("</td>\n",f);
1572 }
1573 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->credit);
1574 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",
1575 ip->keyword->html_color, ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1576 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);
1577 if(qos_proxy)
1578 {
1579 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);
1580 }
1581 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);
1582 fprintf(f,"<td align=\"right\">%d k</td><td align=\"right\">%d k</td><td align=\"right\">%s%d k%s</td><td>%s%d%s</td></tr>\n",
1583 ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);
1584 total+=ip->traffic;
1585 total_direct+=ip->direct;
1586 total_proxy+=ip->proxy;
1587 total_upload+=ip->upload;
1588 if(ip->traffic>0)
1589 {
1590 active_classes++;
1591 tmp_sum+=ip->traffic;
1592 create(sum,Sum);
1593 sum->l=tmp_sum;
1594 sum->i=active_classes;
1595 insert(sum,sums,order_by,i);
1596 }
1597
1598 i++;
1599
1600 if(!just_preview)
1601 {
1602 sprintf(str,"%s/%s.log",log_dir,ip->name);
1603 iplog=fopen(str,"a");
1604 if(iplog)
1605 {
1606 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1607 time(NULL),ip->name,ip->traffic,ip->direct,ip->proxy,ip->upload,ip->min,ip->max,ip->desired,ip->lmsid,d); /* d = date*/
1608 fclose(iplog);
1609 }
1610 }
1611
1612 }
1613 fprintf(f,"<tr><th colspan=\"%d\" align=\"left\">SUMMARY:</td>",colspan-7);
1614 fprintf(f,"<th align=\"right\">%Lu M</th>\
1615 <th align=\"right\">%Lu M</th>\n", total, total_direct);
1616 if(qos_proxy)
1617 {
1618 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);
1619 }
1620 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);
1621 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);
1622
1623 if(active_classes>10)
1624 {
1625 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
1626 fputs("<tr><td>Analytic category</td>\n",f);
1627 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
1628
1629 if_exists(sum,sums,sum->l>=total/4)
1630 {
1631 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
1632 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1633 }
1634
1635 if_exists(sum,sums,sum->i==10)
1636 {
1637 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
1638 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1639 }
1640
1641 if_exists(sum,sums,sum->l>=total/2)
1642 {
1643 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
1644 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1645 }
1646
1647 if_exists(sum,sums,sum->l>=4*total/5)
1648 {
1649 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
1650 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1651 }
1652
1653 if_exists (sum,sums,sum->i>=(active_classes+1)/5)
1654 {
1655 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
1656 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1657 }
1658
1659 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1660 {
1661 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
1662 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1663 }
1664
1665 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1666 {
1667 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
1668 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1669 }
1670
1671 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1672 {
1673 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
1674 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1675 }
1676
1677 fprintf(f,"<tr><td>All users, all traffic</td>\n");
1678 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes,total);
1679 fputs("</table>\n", f);
1680 }
1681 fprintf(f, stats_html_signature, version);
1682 fclose(f);
1683 }
1684
1685 if(just_preview)
1686 {
1687 puts("Statistics preview generated (-p switch) - now exiting ...");
1688 exit(0);
1689 }
1690
1691 /*-----------------------------------------------------------------*/
1692 puts("Generating iptables and tc classes ...");
1693 /*-----------------------------------------------------------------*/
1694
1695 i=0;
1696 printf("%-22s %-15s mark\n","name","ip");
1697
1698 for_selected(ip,ips,ip->mark>0)
1699 {
1700
1701 if(idxs)
1702 {
1703 char *buf;
1704 duplicate(ip->addr,buf);
1705 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1706
1707 string(chain_forward,6+strlen(buf));
1708 strcpy(chain_forward,"forw_");
1709 strcat(chain_forward,buf);
1710
1711 string(chain_postrouting,6+strlen(buf));
1712 strcpy(chain_postrouting,"post_");
1713 strcat(chain_postrouting,buf);
1714
1715 free(buf);
1716 }
1717 else
1718 {
1719 chain_forward="FORWARD";
1720 chain_postrouting="POSTROUTING";
1721 }
1722
1723 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1724
1725 /* -------------------------------------------------------- mark download */
1726
1727 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);
1728 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1729 /* -m limit --limit 1/s */
1730 save_line(str);
1731
1732 if(qos_proxy)
1733 {
1734 sprintf(str,"-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",chain_postrouting,proxy_ip,proxy_port,ip->addr,lan,mark_iptables,ip->mark);
1735 /*sprintf(str,"-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,proxy_ip,proxy_port,ip->addr,lan,ip->mark);*/
1736 save_line(str);
1737 }
1738
1739 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);
1740 save_line(str);
1741
1742 /* -------------------------------------------------------- mark upload */
1743 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);
1744 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1745 save_line(str);
1746
1747 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);
1748 save_line(str);
1749
1750 if(ip->min)
1751 {
1752 /* -------------------------------------------------------- download class */
1753 printf("(down: %dk-%dk ", ip->min, ip->max);
1754
1755 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1756 safe_run(str);
1757
1758 if (strcmpi(ip->keyword->leaf_discipline, "none"))
1759 {
1760 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1761 safe_run(str);
1762 }
1763 if (filter_type == 1)
1764 {
1765 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, ip->mark, ip->mark);
1766 safe_run(str);
1767 }
1768
1769 /* -------------------------------------------------------- upload class */
1770 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1771 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1772
1773 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1774 tc, wan, ip->group, ip->mark,
1775 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1776 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1777 safe_run(str);
1778
1779 if (strcmpi(ip->keyword->leaf_discipline, "none"))
1780 {
1781 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s",tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1782 safe_run(str);
1783 }
1784 if (filter_type == 1)
1785 {
1786 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc, wan, ip->mark, ip->mark);
1787 safe_run(str);
1788 }
1789 }
1790 else
1791 printf("(sharing %s)\n", ip->sharing);
1792 i++;
1793 }
1794
1795 if(idxs)
1796 {
1797 chain_forward = "forw_common";
1798 chain_postrouting = "post_common";
1799 }
1800 else
1801 {
1802 chain_forward = "FORWARD";
1803 chain_postrouting = "POSTROUTING";
1804 }
1805 /* -------------------------------- classify or reject free download */
1806 {
1807 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
1808 if(free_min) final_chain = "ACCEPT";
1809 if(qos_proxy)
1810 {
1811 if(free_min)
1812 {
1813 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
1814 save_line(str);
1815 }
1816 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
1817 save_line(str);
1818 }
1819 if(free_min)
1820 {
1821 sprintf(str,"-A %s -o %s -j %s%d",chain_postrouting,lan,mark_iptables,3);
1822 save_line(str);
1823 }
1824 sprintf(str,"-A %s -o %s -j %s",chain_postrouting,lan,final_chain);
1825 save_line(str);
1826 /* ------------------------------- classify or reject free upload */
1827 if(free_min)
1828 {
1829 sprintf(str,"-A %s -o %s -j %s%d",chain_forward,wan,mark_iptables,3);
1830 save_line(str);
1831 }
1832 sprintf(str,"-A %s -o %s -j %s",chain_forward,wan,final_chain);
1833 save_line(str);
1834 }
1835
1836 if(free_min) /* allocate free bandwith if it is not zero... */
1837 {
1838 /*-----------------------------------------------------------------*/
1839 puts("Generating free bandwith classes ...");
1840 /*-----------------------------------------------------------------*/
1841 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1842 tc,lan,parent,free_min,free_max,burst,lowest_priority);
1843 safe_run(str);
1844 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1845 tc,wan,parent,free_min,free_max,burst,lowest_priority);
1846 safe_run(str);
1847 /* tc SFQ */
1848 if (strcmpi(qos_leaf, "none"))
1849 {
1850 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);
1851 safe_run(str);
1852
1853 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);
1854 safe_run(str);
1855 }
1856 /* tc handle 1 fw flowid */
1857 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);
1858 safe_run(str);
1859
1860 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);
1861 safe_run(str);
1862 }
1863 printf("Total IP count: %d\n", i);
1864 run_restore();
1865 if (log_file) fclose(log_file);
1866 return 0;
1867 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1868 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1869 }
This page took 1.452821 seconds and 4 git commands to generate.