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