9e658fef50d9d983bb423f4f1c8a53cc84e853cc
[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, 20080407
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.9.1"; /*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 char *ls = "/bin/ls"; /* this is not user configurable :-) */
45
46 char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */
47 char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
48
49 char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
50 char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */
51 char *html = "/var/www/traffic.html"; /* hall of fame filename */
52 char *preview = "/var/www/preview.html"; /* hall of fame preview */
53 char *cmdlog = "/var/log/prometheuslog"; /* command log filename */
54 char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */
55 char *log_url = "logs/"; /* log directory relative URI prefix (partial URL) */
56 char *html_log_dir = "/var/www/logs/html/";
57
58 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
59
60 void help(void)
61 {
62 puts("Command line switches:\n\
63 \n\
64 -?, --help this help screen\n\
65 -v, --version show version number of this utility and exit\n\
66 -c filename force alternative /etc/prometheus.conf filename\n\
67 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
68 -f just flush iptables and tc classes and exit (stop shaping)\n\
69 -9 emergency iptables flush (do not read data transfer statistics)\n\
70 -p just generate preview of data transfer statistics and exit\n\
71 -n no delay (overrides qos-free-delay keyword)\n\
72 -d dry run (preview tc and iptables commands on stdout)\n\
73 -l Mmm YYYY generate HTML summary of traffic logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
74 -m generate HTML summary of traffic logs for yesterday's month\n\
75 -y generate HTML summary of traffic logs for yesterday's year\n");
76 /* not yet implemented:
77 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
78 -r just reload configuration (...and keep data transfer statistics)\n\
79 */
80 }
81
82 /* === Configuraration file values defaults - stored in global variables ==== */
83
84 int filter_type=1; /*1 mark, 2 classify*/
85 char *mark="MARK";
86 char *mark_iptables="MARK --set-mark ";
87 int dry_run=0; /* preview - use puts() instead of system() */
88 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]";
89 FILE *iptables_file=NULL;
90 int enable_credit=1; /* enable credit file */
91 int use_credit=0; /* use credit file (if enabled)*/
92 char *title="Hall of Fame - Greatest Suckers"; /* hall of fame title */
93 int hall_of_fame=1; /* enable hall of fame */
94 char *lan="eth0"; /* LAN interface */
95 char *lan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */
96 char *wan="eth1"; /* WAN/ISP interface */
97 char *wan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */
98 char *qos_leaf="sfq perturb 5"; /* leaf discipline */
99 char *qos_free_zone=NULL; /* QoS free zone */
100 int qos_proxy=1; /* include proxy port to QoS */
101 int include_upload=1; /* upload+download=total traffic */
102 char *proxy_ip="192.168.1.1/32"; /* our IP with proxy port */
103 int proxy_port=3128; /* proxy port number */
104 long long int line=1024; /* WAN/ISP download in kbps */
105 long long int up=1024; /* WAN/ISP upload in kbps */
106 int free_min=32; /* minimum guaranted bandwidth for all undefined hosts */
107 int free_max=64; /* maximum allowed bandwidth for all undefined hosts */
108 int qos_free_delay=0; /* seconds to sleep before applying new QoS rules */
109 int digital_divide=2; /* controls digital divide weirdness ratio, 1...3 */
110 int max_nesting=3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
111 int htb_r2q=1;
112 int burst=8; /* HTB burst (in kbits) */
113 int burst_main=64;
114 int burst_group=32;
115 int magic_priorities=8; /* number of priority levels (soft shaping) */
116 int magic_treshold=8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
117 int keywordcount=0;
118
119 /* not yet implemented:
120 int fixed_packets=0; maximum number of pps per IP address (not class!)
121 int packet_limit=5; maximum number of pps to htn CEIL, not rate !!!
122 */
123 FILE *log_file=NULL;
124
125 char *kwd="via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
126
127 const int idxtable_treshold1=24; /* this is no longer configurable */
128 const int idxtable_treshold2=12; /* this is no longer configurable */
129 const int idxtable_bitmask1=3; /* this is no longer configurable */
130 const int idxtable_bitmask2=3; /* this is no longer configurable */
131
132 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
133
134 struct IP
135 {
136 char *addr;
137 char *name;
138 char *sharing;
139 int min;
140 int desired;
141 int max;
142 int mark;
143 int prio;
144 int fixedprio;
145 int group;
146 unsigned long long direct;
147 unsigned long long proxy;
148 unsigned long long upload;
149 unsigned long long traffic;
150 unsigned long long credit;
151 unsigned long pktsup;
152 unsigned long pktsdown;
153 struct Keyword *keyword;
154 list(IP);
155 } *ips=NULL, *ip, *sharedip;
156
157 struct Group
158 {
159 int min;
160 int count;
161 int desired;
162 int id;
163 list(Group);
164 } *groups=NULL, *group;
165
166 struct Index
167 {
168 char *addr;
169 char *id;
170 struct Index *parent;
171 int bitmask;
172 int children;
173 list(Index);
174 } *idxs=NULL, *idx, *metaindex;
175
176 struct Keyword
177 {
178 char *key;
179
180 int asymetry_ratio; /* ratio for ADSL-like upload */
181 int asymetry_fixed; /* fixed treshold for ADSL-like upload */
182 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
183 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
184 long fixed_limit; /* fixed data limit for setting lower HTB ceil */
185 long fixed_prio; /* fixed data lmit for setting lower HTB prio */
186 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */
187 int reserve_max; /* malus for nominal HTB ceil (in kbps) */
188 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
189 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
190 int default_prio; /* default HTB priority for this keyword */
191 char *html_color;
192 int ip_count;
193 char *leaf_discipline;
194
195 list(Keyword);
196 } *keyword,*defaultkeyword=NULL,*keywords=NULL;
197
198 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
199
200 void TheIP(void)
201 {
202 create(ip,IP);
203 ip->name="";
204 ip->addr="";
205 ip->sharing=NULL;
206 ip->prio=1;
207 ip->fixedprio=0;
208 ip->mark=ip->min=ip->max=ip->desired=ip->credit=0;
209 ip->upload=ip->proxy=ip->direct=ip->traffic=0;
210 ip->pktsup=ip->pktsdown=0;
211 ip->keyword=keywords;
212 push(ip,ips);
213 }
214
215 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
216
217 char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)
218 {
219 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
220 int dot=0,n;
221 char *ip,*outip,*outptr,*fmt;
222
223 duplicate(inip,ip);
224 /* debug printf("(%s,%d) -> ",ip,bitmask); */
225
226 if(ip && *ip && bitmask>=0 && bitmask<=32)
227 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
228 else
229 /* should never exit here */
230 return "undefined";
231 outptr=outip;
232 while(ip && *ip)
233 {
234 if(*ip=='.')
235 {
236 if(dot<(bitmask/8-1))
237 {
238 if(format_as_chainname)
239 *outptr='_';
240 else
241 *outptr='.';
242 outptr++;
243 dot++;
244 }
245 else
246 {
247 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/
248 if(cutdot)*cutdot='\0';
249 if(format_as_chainname)
250 fmt="_%d_%d";
251 else
252 fmt=".%d";
253 if(bitmask%8)
254 n=atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));
255 else
256 n=0;
257
258 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
259 sprintf(outptr,fmt,n,bitmask);
260 if(!format_as_chainname) while(bitmask<24)
261 {
262 strcat(outip,".0");
263 bitmask+=8;
264 }
265 /* debug printf("[%s]\n",outip); */
266 return outip;
267 }
268 }
269 else
270 {
271 *outptr=*ip;
272 outptr++;
273 }
274 ip++;
275 }
276 /*should never exit here*/
277 *outptr='\0';
278 return outip;
279 }
280
281 char *hash_id(char *ip,int bitmask)
282 { return very_ugly_ipv4_code(ip,bitmask,1); }
283
284 char *subnet_id(char *ip,int bitmask)
285 { return very_ugly_ipv4_code(ip,bitmask,0); }
286
287 /* ================= Let's parse configuration file here =================== */
288
289 void reject_config_and_exit(char *filename)
290 {
291 printf("Configuration file %s rejected - abnormal exit.",filename);
292 exit(-1);
293 }
294
295 void get_config(char *config_filename)
296 {
297 char *cnf="mark";
298
299 printf("Configured keywords: ");
300 parse(config_filename)
301 {
302 option("keyword",kwd);
303 if(kwd)
304 {
305 printf("%s ",kwd);
306
307 create(keyword,Keyword);
308 keyword->key=kwd;
309 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
310 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
311 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
312 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
313 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
314 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
315 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
316 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
317 /* obsolete:
318 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
319 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide
320 */
321 keyword->default_prio=1;
322 keyword->html_color="000000";
323 keyword->ip_count=0;
324 keyword->leaf_discipline="";
325
326 push(keyword,keywords);
327 if(!defaultkeyword) defaultkeyword=keyword;
328 keywordcount++;
329
330 kwd=NULL;
331 }
332 else every(keyword,keywords)
333 {
334 int l=strlen(keyword->key);
335
336
337 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
338 {
339 char *tmptr=_; /* <---- l+1 ----> */
340 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
341 ioption("asymetry-ratio",keyword->asymetry_ratio);
342 ioption("asymetry-treshold",keyword->asymetry_fixed);
343 ioption("magic-relative-limit",keyword->data_limit);
344 ioption("magic-relative-prio",keyword->data_prio);
345 loption("magic-fixed-limit",keyword->fixed_limit);
346 loption("magic-fixed-prio",keyword->fixed_prio);
347 ioption("htb-default-prio",keyword->default_prio);
348 ioption("htb-rate-bonus",keyword->reserve_min);
349 ioption("htb-ceil-malus",keyword->reserve_max);
350 /* obsolete:
351 ioption("htb-ceil-divide",keyword->divide_max);
352 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
353 */
354 option("leaf-discipline",keyword->leaf_discipline);
355 option("html-color",keyword->html_color);
356 _=tmptr;
357
358 if(keyword->data_limit || keyword->fixed_limit ||
359 keyword->data_prio || keyword->fixed_prio)
360 use_credit=1;
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-html-directory",html_log_dir);
385 option("log-traffic-url-path",log_url);
386 option("qos-free-zone",qos_free_zone);
387 ioption("qos-free-delay",qos_free_delay);
388 ioption("qos-proxy-enable",qos_proxy);
389 option("qos-proxy-ip",proxy_ip);
390 option("htb-leaf-discipline",qos_leaf);
391 ioption("qos-proxy-port",proxy_port);
392 ioption("free-rate",free_min);
393 ioption("free-ceil",free_max);
394 ioption("htb-burst",burst);
395 ioption("htb-burst-main",burst_main);
396 ioption("htb-burst-group",burst_group);
397 ioption("htb-nesting-limit",max_nesting);
398 ioption("htb-r2q",htb_r2q);
399 ioption("magic-include-upload",include_upload);
400 ioption("magic-priorities",magic_priorities);
401 ioption("magic-treshold",magic_treshold);
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 struct IpLog
632 {
633 char *name;
634 long traffic;
635 list(IpLog);
636 } *iplog,*iplogs;
637
638 void parse_ip_log(int argc, char **argv)
639 {
640 char *month,*year,*str,*name,*ptr,*ptr2;
641 long traffic,traffic_month,total=0;
642 int col,col2,y_ok,m_ok,accept_month,i=1,any_month=0;
643 char mstr[4],ystr[5];
644 FILE *f;
645
646 string(str,STRLEN);
647
648 if(argv[1][1]=='l') /* -l */
649 {
650 if(argc<4)
651 {
652 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
653 exit(-1);
654 }
655 else
656 {
657 month=argv[2];
658 if(eq(month,"Year")) any_month=1;
659 year=argv[3];
660 }
661 }
662 else
663 {
664 time_t t = time(NULL) - 3600*24 ; /* yesterday's timestamp*/
665 struct tm *timep = localtime(&t);
666
667 if(argv[1][1]=='m') /* -m yestarday - month */
668 {
669 strftime(mstr, 4, "%b", timep);
670 month=mstr;
671 strftime(ystr, 5, "%Y", timep);
672 year=ystr;
673 }
674 else /* -y yesterday - year */
675 {
676 month="Year";
677 any_month=1;
678 strftime(ystr, 5, "%Y", timep);
679 year=ystr;
680 }
681 }
682 printf("Analysing traffic for %s %s ...\n",month,year);
683
684 sprintf(str,"%s %s/*.log",ls,log_dir);
685 shell(str);
686 input(str,STRLEN)
687 {
688 ptr=strrchr(str,'\n');
689 if(ptr) *ptr='\0';
690 printf("Parsing %s ...",str);
691 accept_month=0;
692 traffic_month=0;
693 parse(str)
694 {
695 y_ok=m_ok=0;
696 valid_columns(ptr,_,'\t',col) switch(col)
697 {
698 case 2: name=ptr;break;
699 case 3: traffic=atol(ptr);break;
700 case 7: valid_columns(ptr2,ptr,' ',col2) switch(col2)
701 {
702 case 2: if(any_month || eq(ptr2,month)) m_ok=1; break;
703 case 5: if(eq(ptr2,year)) y_ok=1; break;
704 }
705 }
706 if(y_ok && m_ok)
707 {
708 traffic_month+=traffic;
709 accept_month=1;
710 }
711 }
712 done;
713 if(accept_month)
714 {
715 create(iplog,IpLog);
716 iplog->name=name;
717 iplog->traffic=traffic_month;
718 insert(iplog,iplogs,desc_order_by,traffic);
719 printf(" %ld MB\n",iplog->traffic);
720 }
721 else
722 puts(" no records.");
723 }
724 sprintf(str,"%s/%s-%s.html",html_log_dir,year,month);
725 printf("Writing %s ...",str);
726 f=fopen(str,"w");
727 if(f)
728 {
729 fprintf(f,"<table border><tr><th colspan=\"4\">Data transfers - %s %s</th></tr>\n ",month,year);
730 every(iplog,iplogs)
731 if(iplog->traffic)
732 {
733 fprintf(f,"<tr><td align=\"right\">%d</td><th>%s</td><td align=\"right\">%ld MB</td><th align=\"right\">%ld GB</th></tr>\n",i++,iplog->name,iplog->traffic,iplog->traffic>>10);
734 total+=iplog->traffic>>10;
735 }
736 fprintf(f,"<tr><th colspan=\"3\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th></tr>\n",total);
737 fputs("</table>\n",f);
738 fclose(f);
739 puts(" done.");
740 }
741 }
742
743
744 /*-----------------------------------------------------------------*/
745 /* Are you looking for int main (int argc, char **argv) ? :-)) */
746 /*-----------------------------------------------------------------*/
747
748 program
749 {
750 int i=0;
751 FILE *f=NULL;
752 char *str, *ptr, *d;
753 char *substring;
754 int class_count=0,ip_count=0;
755 int parent=1;
756 int just_flush=0;
757 int nodelay=0;
758 int just_preview=0; /* preview - generate just stats */
759 char *chain_forward, *chain_postrouting;
760 char *althosts=NULL;
761
762 printf("\n\
763 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
764 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
765 iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\
766 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
767
768 /*----- Boring... we have to check command line options first: ----*/
769
770 arguments
771 {
772 argument("-c") { nextargument(config); }
773 argument("-h") { nextargument(althosts);}
774 argument("-d") { dry_run=1; }
775 argument("-f") { just_flush=1; }
776 argument("-9") { just_flush=9; }
777 argument("-p") { just_preview=1; }
778 argument("-n") { nodelay=1; }
779 argument("-l") { parse_ip_log(argc,argv); exit(0); }
780 argument("-m") { parse_ip_log(argc,argv); exit(0); }
781 argument("-y") { parse_ip_log(argc,argv); exit(0); }
782 argument("-?") { help(); exit(0); }
783 argument("--help") { help(); exit(0); }
784 argument("-v") { exit(0); }
785 argument("--version") { exit(0); }
786 }
787
788 if(dry_run)
789 puts("*** THIS IS JUST DRY RUN ! ***\n");
790
791 date(d); /* this is typical cll1.h macro */
792
793 /*-----------------------------------------------------------------*/
794 printf("Parsing configuration file %s ...\n", config);
795 /*-----------------------------------------------------------------*/
796 get_config(config);
797
798 if(althosts) hosts=althosts;
799
800 if(just_flush<9)
801 {
802 /*-----------------------------------------------------------------*/
803 puts("Parsing iptables verbose output ...");
804 /*-----------------------------------------------------------------*/
805 get_traffic_statistics();
806 }
807
808 /*-----------------------------------------------------------------*/
809 printf("Parsing class defintion file %s ...\n", hosts);
810 /*-----------------------------------------------------------------*/
811 int groupidx = FIRSTGROUPID;
812 parse(hosts)
813 {
814 str=_;
815
816 if(*str<'0' || *str>'9')
817 continue;
818
819 //Does this IP share QoS class with some other ?
820 substring=strstr(str,"sharing-");
821 if(substring)
822 {
823 substring+=8; //"sharing-"
824 parse_ip(str);
825 ip_count++;
826 ip->sharing=substring;
827 ip->keyword=defaultkeyword; /* settings for default keyword */
828 while(*substring && *substring!='\n')
829 substring++;
830 *substring=0;
831 }
832 else
833 {
834 //Do we have to create new QoS class for this IP ?
835
836 find(keyword,keywords,(substring=strstr(str,keyword->key)))
837 {
838 parse_ip(str);
839 ip_count++;
840 ip->keyword=keyword;
841 keyword->ip_count++;
842 ip->prio=keyword->default_prio;
843 substring+=strlen(keyword->key)+1;
844 ptr=substring;
845 while(*ptr && *ptr!='-')
846 ptr++;
847 if(*ptr=='-')
848 {
849 *ptr=0;
850 ip->max=ip->desired=atoi(ptr+1);
851 }
852 ip->min=atoi(substring);
853 if(ip->min<=0)
854 {
855 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str,free_min);
856 ip->min=free_min;
857 }
858 if(ip->max<=ip->min)
859 {
860 ip->fixedprio=1;
861 ip->max=ip->min+ip->keyword->reserve_min;
862 }
863 else
864 {
865 ip->max-=ip->keyword->reserve_max;
866
867 /*
868 if(ip->keyword->divide_max>1)
869 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
870 if(ip->keyword->htb_ceil_bonus_divide>0)
871 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
872 */
873 if(ip->max<ip->min)
874 ip->max=ip->min;
875 }
876 ip->mark=FIRSTIPCLASS+1+class_count++;
877
878 find(group,groups,group->min==ip->min)
879 {
880 group->count++;
881 group->desired+=ip->min;
882 ip->group = group->id;
883 }
884 else
885 {
886 create(group,Group);
887 group->min=ip->min;
888 group->id = groupidx++;
889 ip->group = group->id;
890
891 if(group->min<8) group->min=8;
892 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
893 /* it is because class IDs are derived from min. bandwidth. - xCh */
894 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
895
896 group->count=1;
897 group->desired=ip->min;
898 insert(group,groups,desc_order_by,min);
899 }
900 }//endif keyword-
901 }//endif sharing-
902 }
903 fail
904 {
905 perror(hosts);
906 exit(-1);
907 }
908 done;
909
910 /*-----------------------------------------------------------------*/
911 /* cll1.h - let's allocate brand new character buffer... */
912 /*-----------------------------------------------------------------*/
913 string(str,STRLEN);
914
915 /*-----------------------------------------------------------------*/
916 puts("Resolving shared connections ...");
917 /*-----------------------------------------------------------------*/
918 search(ip,ips,ip->sharing)
919 {
920 search(sharedip,ips,eq(sharedip->name,ip->sharing))
921 {
922 sharedip->traffic+=ip->traffic;
923 ip->traffic=0;
924 ip->mark=sharedip->mark;
925 break;
926 }
927 if(!sharedip)
928 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);
929 }
930
931 if(enable_credit && just_flush<9)
932 {
933 /*-----------------------------------------------------------------*/
934 printf("Parsing credit file %s ...\n", credit);
935 /*-----------------------------------------------------------------*/
936 parse(credit)
937 {
938 ptr=parse_datafile_line(_);
939 if(ptr)
940 {
941 find(ip,ips,eq(ip->addr,_))
942 sscanf(ptr,"%Lu",&(ip->credit));
943 }
944 }
945 done;
946 }
947
948 if(!just_preview)
949 {
950 /*-----------------------------------------------------------------*/
951 puts("Initializing iptables and tc classes ...");
952 /*-----------------------------------------------------------------*/
953
954 iptables_file=fopen(iptablesfile,"w");
955 if (iptables_file == NULL) {
956 puts("Cannot open iptablesfile!");
957 exit(-1);
958 }
959
960 log_file=fopen(cmdlog,"w");
961 if (log_file == NULL) {
962 puts("Cannot open logfile!");
963 exit(-1);
964 }
965
966 save_line(iptablespreamble);
967 run_restore();
968
969 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
970 safe_run(str);
971
972 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
973 safe_run(str);
974
975 iptables_file=fopen(iptablesfile,"w");
976 save_line(iptablespreamble);
977
978 if(qos_free_zone && *qos_free_zone!='0')
979 {
980 char *chain;
981
982 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
983 save_line(str);
984
985 if(qos_proxy)
986 {
987 save_line(":post_noproxy - [0:0]");
988 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
989 save_line(str);
990 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
991 save_line(str);
992 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
993 save_line(str);
994
995 chain="post_noproxy";
996 }
997 else
998 chain="POSTROUTING";
999
1000 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1001 save_line(str);
1002 }
1003
1004 if(ip_count>idxtable_treshold1 && !just_flush)
1005 {
1006 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1007 char *subnet, *buf;
1008 /*-----------------------------------------------------------------*/
1009 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1010 /*-----------------------------------------------------------------*/
1011
1012 save_line(":post_common - [0:0]");
1013 save_line(":forw_common - [0:0]");
1014
1015 search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1016 {
1017 buf=hash_id(ip->addr,bitmask);
1018 find(idx,idxs,eq(idx->id,buf))
1019 idx->children++;
1020 else
1021 {
1022 create(idx,Index);
1023 idx->addr=ip->addr;
1024 idx->id=buf;
1025 idx->bitmask=bitmask;
1026 idx->parent=NULL;
1027 idx->children=0;
1028 idxcount++;
1029 push(idx,idxs);
1030 }
1031 }
1032
1033 /* brutal perfomance optimalization */
1034 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1035 {
1036 bitmask-=idxtable_bitmask2;
1037 idxcount=0;
1038 search(idx,idxs,idx->parent==NULL)
1039 {
1040 buf=hash_id(idx->addr,bitmask);
1041 find(metaindex,idxs,eq(metaindex->id,buf))
1042 metaindex->children++;
1043 else
1044 {
1045 create(metaindex,Index);
1046 metaindex->addr=idx->addr;
1047 metaindex->id=buf;
1048 metaindex->bitmask=bitmask;
1049 metaindex->parent=NULL;
1050 metaindex->children=0;
1051 idxcount++;
1052 push(metaindex,idxs);
1053 }
1054 idx->parent=metaindex;
1055 }
1056 }
1057
1058 /* this should slightly optimize throughout ... */
1059 sort(idx,idxs,desc_order_by,children);
1060 sort(idx,idxs,order_by,bitmask);
1061
1062 i=0;
1063 every(idx,idxs)
1064 {
1065 subnet=subnet_id(idx->addr,idx->bitmask);
1066 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);
1067
1068 sprintf(str,":post_%s - [0:0]", idx->id);
1069 save_line(str);
1070
1071 sprintf(str,":forw_%s - [0:0]", idx->id);
1072 save_line(str);
1073
1074 if(idx->parent)
1075 {
1076 string(buf,strlen(idx->parent->id)+6);
1077 sprintf(buf,"post_%s",idx->parent->id);
1078 }
1079 else
1080 buf="POSTROUTING";
1081
1082 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1083 save_line(str);
1084
1085 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1086 save_line(str);
1087
1088 if(idx->parent)
1089 {
1090 string(buf,strlen(idx->parent->id)+6);
1091 sprintf(buf,"forw_%s",idx->parent->id);
1092 }
1093 else
1094 buf="FORWARD";
1095
1096 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1097 save_line(str);
1098
1099 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1100 save_line(str);
1101 }
1102 printf("Total indexed iptables chains created: %d\n", i);
1103
1104 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1105 save_line(str);
1106
1107 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1108 save_line(str);
1109 }
1110
1111 }
1112
1113 if(just_flush)
1114 {
1115 fclose(iptables_file);
1116 if (log_file) fclose(log_file);
1117 puts("Just flushed iptables and tc classes - now exiting ...");
1118 exit(0);
1119 }
1120
1121 if(!just_preview)
1122 {
1123 if(!dry_run && !nodelay && qos_free_delay)
1124 {
1125 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1126 sleep(qos_free_delay);
1127 }
1128
1129 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);
1130 safe_run(str);
1131
1132 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);
1133 safe_run(str);
1134
1135 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);
1136 safe_run(str);
1137
1138 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1139 safe_run(str);
1140
1141 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);
1142 safe_run(str);
1143
1144 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);
1145 safe_run(str);
1146 }
1147
1148 /*-----------------------------------------------------------------*/
1149 puts("Locating suckers and generating root classes ...");
1150 /*-----------------------------------------------------------------*/
1151 sort(ip,ips,desc_order_by,traffic);
1152
1153
1154 /*-----------------------------------------------------------------*/
1155 /* sub-scope - local variables */
1156 {
1157 long long int rate=line;
1158 long long int max=line;
1159 int group_count=0;
1160 FILE *credit_file=NULL;
1161
1162 if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");
1163
1164 every(group,groups)
1165 {
1166 if(!just_preview)
1167 {
1168
1169 //download
1170 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",
1171 tc, lan, parent, group->id, rate, max, burst_group, group->desired);
1172 safe_run(str);
1173
1174 //upload
1175 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",
1176 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, group->desired);
1177 safe_run(str);
1178 }
1179
1180 if(group_count++<max_nesting) parent=group->id;
1181
1182 rate-=digital_divide*group->min;
1183 if(rate<group->min)rate=group->min;
1184
1185 /*shaping of aggresive downloaders, with credit file support */
1186 if(use_credit)
1187 {
1188 int group_rate=group->min, priority_sequence=magic_priorities+1;
1189
1190 search(ip, ips, ip->min==group->min && ip->max>ip->min)
1191 {
1192 if( ip->keyword->data_limit && !ip->fixedprio &&
1193 ip->traffic>ip->credit+
1194 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )
1195 {
1196 if(group_rate<ip->max) ip->max=group_rate;
1197 group_rate+=magic_treshold;
1198 ip->prio=magic_priorities+2;
1199 if(ip->prio<3) ip->prio=3;
1200 }
1201 else
1202 {
1203 if( ip->keyword->data_prio && !ip->fixedprio &&
1204 ip->traffic>ip->credit+
1205 (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )
1206 {
1207 ip->prio=priority_sequence--;
1208 if(ip->prio<2) ip->prio=2;
1209 }
1210
1211 if(credit_file)
1212 {
1213 unsigned long long lcredit=0;
1214
1215 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1216 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1217 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1218 }
1219 }
1220 }
1221
1222 }
1223 }
1224 if(credit_file)fclose(credit_file);
1225 }
1226
1227 if(just_preview)
1228 {
1229 f=fopen(preview,"w");
1230 ptr=preview;
1231 }
1232 else if(!dry_run && !just_flush)
1233 {
1234 /*-----------------------------------------------------------------*/
1235 printf("Writing data transfer database ...\n");
1236 /*-----------------------------------------------------------------*/
1237 f=fopen("/var/run/prometheus.previous","w");
1238 if(f)
1239 {
1240 search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)
1241 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);
1242 fclose(f);
1243 }
1244
1245 f=fopen(html,"w");
1246 ptr=html;
1247 }
1248
1249 if(f)
1250 {
1251 int total=0;
1252 int count=1;
1253 i=0;
1254
1255 /*-----------------------------------------------------------------*/
1256 printf("Sorting data and generating statistics page %s ...\n",ptr);
1257 /*-----------------------------------------------------------------*/
1258
1259 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);
1260 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);
1261 fputs("</tr>\n",f);
1262 every(group,groups)
1263 {
1264 #ifdef DEBUG
1265 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);
1266 #endif
1267 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);
1268 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);
1269
1270 every(keyword,keywords)
1271 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit);
1272
1273 i+=group->desired;
1274 total+=group->count;
1275 count++;
1276 }
1277 #ifdef DEBUG
1278 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);
1279 #endif
1280 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);
1281 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);
1282
1283 every(keyword,keywords)
1284 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count);
1285
1286 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));
1287 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);
1288
1289 fputs("</table>\n",f);
1290 }
1291 else if(!dry_run && !just_flush)
1292 perror(html);
1293
1294 i=1;
1295 if(f)
1296 {
1297 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1298 int active_classes=0;
1299 int colspan;
1300 FILE *iplog;
1301 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1302
1303 if(qos_proxy)
1304 colspan=12;
1305 else
1306 colspan=11;
1307
1308 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);
1309 fprintf(f," (%s)</th></tr>\n", d);
1310 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1311 <td align=\"right\">credit</td>\
1312 <td align=\"right\">limit</td>\
1313 <td align=\"right\">total</td>\
1314 <td align=\"right\">direct</td>\n",f);
1315 if(qos_proxy)
1316 fputs("<td align=\"right\">proxy</td>\n",f);
1317 fputs("<td align=\"right\">upload</td>\
1318 <td align=\"right\">minimum</td>\
1319 <td align=\"right\">desired</td>\
1320 <td align=\"right\">maximum</td>\
1321 <td>prio</td></tr>\n",f);
1322
1323 every(ip,ips)
1324 {
1325 char *f1="", *f2="";
1326 if(ip->max<ip->desired)
1327 {
1328 f1="<font color=\"red\">";
1329 f2="</font>";
1330 }
1331 else if(ip->prio>1)
1332 {
1333 f1="<font color=\"brown\">";
1334 f2="</font>";
1335 }
1336
1337 #ifdef DEBUG
1338 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1339 #endif
1340 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",
1341 ip->name, i, log_url, ip->name, ip->name, ip->credit);
1342 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)));
1343 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);
1344 if(qos_proxy)
1345 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);
1346 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);
1347 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);
1348 total+=ip->traffic;
1349 total_direct+=ip->direct;
1350 total_proxy+=ip->proxy;
1351 total_upload+=ip->upload;
1352 if(ip->traffic>0)
1353 {
1354 active_classes++;
1355 tmp_sum+=ip->traffic;
1356 create(sum,Sum);
1357 sum->l=tmp_sum;
1358 sum->i=active_classes;
1359 insert(sum,sums,order_by,i);
1360 }
1361
1362 i++;
1363
1364 if(!just_preview)
1365 {
1366 sprintf(str,"%s/%s.log",log_dir,ip->name);
1367 iplog=fopen(str,"a");
1368 if(iplog)
1369 {
1370 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%s",
1371 time(NULL),ip->name,ip->traffic,ip->direct,ip->proxy,ip->upload,ip->min,ip->min,d); /* d = date*/
1372 fclose(iplog);
1373 }
1374 }
1375
1376 }
1377 fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1378 fprintf(f,"<th align=\"right\">%Lu M</th>\
1379 <th align=\"right\">%Lu M</th>\n", total, total_direct);
1380 if(qos_proxy)
1381 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);
1382 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);
1383 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);
1384
1385 if(active_classes>10)
1386 {
1387 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
1388 fputs("<tr><td>Analytic category</td>\n",f);
1389 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
1390
1391 find(sum,sums,sum->l>=total/4)
1392 {
1393 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
1394 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);
1395 }
1396
1397 find(sum,sums,sum->i==10)
1398 {
1399 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
1400 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);
1401 }
1402
1403 find(sum,sums,sum->l>=total/2)
1404 {
1405 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
1406 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);
1407 }
1408
1409 find(sum,sums,sum->l>=4*total/5)
1410 {
1411 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
1412 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);
1413 }
1414
1415 find (sum,sums,sum->i>=(active_classes+1)/5)
1416 {
1417 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
1418 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);
1419 }
1420
1421 find(sum,sums,sum->i>=(active_classes+1)/4)
1422 {
1423 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
1424 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);
1425 }
1426
1427 find(sum,sums,sum->i>=(active_classes+1)/2)
1428 {
1429 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
1430 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);
1431 }
1432
1433 find(sum,sums,sum->i>=4*(active_classes+1)/5)
1434 {
1435 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
1436 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);
1437 }
1438
1439 fprintf(f,"<tr><td>All users, all traffic</td>\n");
1440 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);
1441 fputs("</table>\n",f);
1442 }
1443 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);
1444 fclose(f);
1445 }
1446
1447 if(just_preview)
1448 {
1449 puts("Statistics preview generated (-p switch) - now exiting ...");
1450 exit(0);
1451 }
1452
1453 /*-----------------------------------------------------------------*/
1454 puts("Generating iptables and tc classes ...");
1455 /*-----------------------------------------------------------------*/
1456
1457 i=0;
1458 printf("%-22s %-15s mark\n","name","ip");
1459 search(ip,ips,ip->mark>0)
1460 {
1461
1462 if(idxs)
1463 {
1464 char *buf;
1465 duplicate(ip->addr,buf);
1466 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1467
1468 string(chain_forward,6+strlen(buf));
1469 strcpy(chain_forward,"forw_");
1470 strcat(chain_forward,buf);
1471
1472 string(chain_postrouting,6+strlen(buf));
1473 strcpy(chain_postrouting,"post_");
1474 strcat(chain_postrouting,buf);
1475
1476 free(buf);
1477 }
1478 else
1479 {
1480 chain_forward="FORWARD";
1481 chain_postrouting="POSTROUTING";
1482 }
1483
1484 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1485
1486 /* -------------------------------------------------------- mark download */
1487
1488 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);
1489 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1490 /* -m limit --limit 1/s */
1491 save_line(str);
1492
1493 if(qos_proxy)
1494 {
1495 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);
1496 /*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);*/
1497 save_line(str);
1498 }
1499
1500 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);
1501 save_line(str);
1502
1503 /* -------------------------------------------------------- mark upload */
1504 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);
1505 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1506 save_line(str);
1507
1508 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);
1509 save_line(str);
1510
1511 if(ip->min)
1512 {
1513 /* -------------------------------------------------------- download class */
1514 printf("(down: %dk-%dk ", ip->min, ip->max);
1515
1516 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);
1517 safe_run(str);
1518
1519 if (strcmpi(ip->keyword->leaf_discipline, "none")){
1520 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*/
1521 safe_run(str);
1522 }
1523
1524 if (filter_type == 1){
1525 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, ip->mark, ip->mark);
1526 safe_run(str);
1527 }
1528
1529 /* -------------------------------------------------------- upload class */
1530 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1531 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1532
1533 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1534 tc, wan, ip->group, ip->mark,
1535 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1536 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1537 safe_run(str);
1538
1539 if (strcmpi(ip->keyword->leaf_discipline, "none")){
1540 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*/
1541 safe_run(str);
1542 }
1543
1544 if (filter_type == 1){
1545 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc, wan, ip->mark, ip->mark);
1546 safe_run(str);
1547 }
1548 }
1549 else
1550 printf("(sharing %s)\n", ip->sharing);
1551 i++;
1552 }
1553
1554
1555 if(idxs)
1556 {
1557 chain_forward="forw_common";
1558 chain_postrouting="post_common";
1559 }
1560 else
1561 {
1562 chain_forward="FORWARD";
1563 chain_postrouting="POSTROUTING";
1564 }
1565
1566 /* -------------------------------------------------------- mark download */
1567
1568 if(qos_proxy)
1569 {
1570 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j MARK --set-mark 3",chain_postrouting,proxy_ip,proxy_port,lan);
1571 save_line(str);
1572 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",chain_postrouting,proxy_ip,proxy_port,lan);
1573 save_line(str);
1574 }
1575 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_postrouting,lan);
1576 save_line(str);
1577 sprintf(str,"-A %s -o %s -j ACCEPT",chain_postrouting,lan);
1578 save_line(str);
1579
1580 /* -------------------------------------------------------- mark upload */
1581 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_forward,wan);
1582 save_line(str);
1583 sprintf(str,"-A %s -o %s -j ACCEPT",chain_forward,wan);
1584 save_line(str);
1585
1586 printf("Total IP count: %d\n", i);
1587
1588 /*-----------------------------------------------------------------*/
1589 puts("Generating free bandwith classes ...");
1590 /*-----------------------------------------------------------------*/
1591
1592 /* ---------------------------------------- tc - free bandwith shared class */
1593 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);
1594 safe_run(str);
1595
1596 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);
1597 safe_run(str);
1598
1599 /* tc SFQ */
1600 if (strcmpi(qos_leaf, "none")){
1601 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);
1602 safe_run(str);
1603
1604 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);
1605 safe_run(str);
1606 }
1607
1608 /* tc handle 1 fw flowid */
1609 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);
1610 safe_run(str);
1611
1612 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);
1613 safe_run(str);
1614
1615 run_restore();
1616
1617 if (log_file) fclose(log_file);
1618 return 0;
1619
1620 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1621 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1622 }
This page took 2.591684 seconds and 4 git commands to generate.