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