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