d241618fcc351c084294e9e9e293cc637bd6617e
[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 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\" 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\" 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 <td colspan=\"4\" style=\"text-align: left\">Total:</td>\
943 <td style=\"text-align: right\"><strong>%ld&nbsp;GB</strong></td>\
944 <td style=\"text-align: right\"><strong>%Ld&nbsp;kb/s</strong></td></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>\n\
1025 <th>All users, all traffic</th>\n\
1026 <th style=\"text-align: right\">%d</th>\n\
1027 <th style=\"text-align: right\">100 %%</th>\n\
1028 <th style=\"text-align: right\">%ld G</th>\n\
1029 <th style=\"text-align: right\">100 %%</th></tr>\n",i-1,total);
1030 fputs("</thead></table>\n", f);
1031 }
1032
1033 fprintf(f, stats_html_signature, version);
1034 fclose(f);
1035 puts("done.");
1036 }
1037 else
1038 {
1039 perror(str);
1040 }
1041 }
1042
1043 void append_log(struct IP *self) /*using global variables*/
1044 {
1045 char *d, *str;
1046 FILE *f;
1047
1048 date(d); /* this is typical cll1.h macro - prints current date */
1049 string(str,STRLEN);
1050 sprintf(str,"%s/%s.log", log_dir, self->name);
1051 f=fopen(str,"a");
1052 if(f > 0)
1053 {
1054 fprintf(f,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1055 time(NULL), self->name, self->traffic, self->direct, self->proxy,
1056 self->upload, self->min, self->max, self->desired, self->lmsid, d); /* d = date*/
1057 fclose(f);
1058 }
1059 else
1060 {
1061 perror(str);
1062 }
1063 }
1064
1065
1066 /*-----------------------------------------------------------------*/
1067 /* Are you looking for int main(int argc, char **argv) ? :-)) */
1068 /*-----------------------------------------------------------------*/
1069
1070 program
1071 {
1072 int i=0;
1073 FILE *f=NULL;
1074 char *str, *ptr, *d;
1075 char *substring;
1076 int class_count=0,ip_count=0;
1077 int parent=1;
1078 int just_flush=FALSE;
1079 int nodelay=FALSE;
1080 int just_preview=FALSE; /* preview - generate just stats */
1081 int just_logs=FALSE; /* just parse logs */
1082 int run=FALSE;
1083 int total=0;
1084
1085 char *chain_forward, *chain_postrouting;
1086 char *althosts=NULL;
1087
1088 printf("\n\
1089 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1090 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1091 iptables-restore & burst tunning & classify modification by Ludva\n\
1092 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
1093
1094 /*----- Boring... we have to check command line options first: ----*/
1095
1096 arguments
1097 {
1098 argument("-c") { nextargument(config); }
1099 argument("-h") { nextargument(althosts);}
1100 argument("-d") { run=TRUE; dry_run=TRUE; }
1101 argument("-f") { run=TRUE; just_flush=TRUE; }
1102 argument("-9") { run=TRUE; just_flush=9; }
1103 argument("-p") { run=TRUE; just_preview=TRUE; }
1104 argument("-r") { run=TRUE; }
1105 argument("-n") { run=TRUE; nodelay=TRUE; }
1106 argument("-l") { just_logs=TRUE; }
1107 argument("-m") { just_logs=TRUE; }
1108 argument("-y") { just_logs=TRUE; }
1109 argument("-?") { help(); exit(0); }
1110 argument("--help") { help(); exit(0); }
1111 argument("-v") { exit(0); }
1112 argument("--version") { exit(0); }
1113 }
1114
1115 if(dry_run)
1116 {
1117 puts("*** THIS IS JUST DRY RUN ! ***\n");
1118 }
1119
1120 date(d); /* this is typical cll1.h macro - prints current date */
1121
1122 /*-----------------------------------------------------------------*/
1123 printf("Parsing configuration file %s ...\n", config);
1124 /*-----------------------------------------------------------------*/
1125 get_config(config);
1126
1127 if(just_logs)
1128 {
1129 parse_ip_log(argc,argv);
1130 exit(0);
1131 }
1132 else if(not run)
1133 {
1134 help();
1135 exit(0);
1136 }
1137
1138 if(althosts)
1139 {
1140 hosts=althosts;
1141 }
1142
1143 if(just_flush<9)
1144 {
1145 /*-----------------------------------------------------------------*/
1146 puts("Parsing iptables verbose output ...");
1147 /*-----------------------------------------------------------------*/
1148 get_traffic_statistics();
1149 }
1150
1151 /*-----------------------------------------------------------------*/
1152 printf("Parsing class defintion file %s ...\n", hosts);
1153 /*-----------------------------------------------------------------*/
1154 int groupidx = FIRSTGROUPID;
1155 parse(hosts)
1156 {
1157 str=_;
1158
1159 if(*str<'0' || *str>'9')
1160 {
1161 /* any line starting with non-number is comment ...*/
1162 continue;
1163 }
1164
1165 //Does this IP share QoS class with some other ?
1166 substring=strstr(str,"sharing-");
1167 if(substring)
1168 {
1169 substring+=8; //"sharing-"
1170 parse_ip(str);
1171 ip_count++;
1172 ip->sharing=substring;
1173 ip->keyword=defaultkeyword; /* settings for default keyword */
1174 while(*substring && *substring!='\n')
1175 {
1176 substring++;
1177 }
1178 *substring=0;
1179 }
1180 else
1181 {
1182 //Do we have to create new QoS class for this IP ?
1183
1184 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))
1185 {
1186 parse_ip(str);
1187 ip_count++;
1188 ip->keyword=keyword;
1189 keyword->ip_count++;
1190 ip->prio=keyword->default_prio;
1191 substring+=strlen(keyword->key)+1;
1192 ptr=substring;
1193 while(*ptr && *ptr!='-')
1194 {
1195 ptr++;
1196 }
1197 if(*ptr=='-')
1198 {
1199 *ptr=0;
1200 ip->max = ip->desired=atoi(ptr+1);
1201 }
1202 ip->min = atoi(substring);
1203 if(ip->min <= 0)
1204 {
1205 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
1206 str, free_min);
1207 ip->min = free_min;
1208 }
1209 if(ip->max <= ip->min)
1210 {
1211 ip->fixedprio = 1;
1212 ip->max = ip->min+ip->keyword->reserve_min;
1213 }
1214 else
1215 {
1216 ip->max -= ip->keyword->reserve_max;
1217 if(ip->max<ip->min)
1218 {
1219 ip->max=ip->min;
1220 }
1221 }
1222 ip->mark=FIRSTIPCLASS+1+class_count++;
1223
1224 if_exists(group,groups,group->min==ip->min)
1225 {
1226 group->count++;
1227 group->desired += ip->min;
1228 ip->group = group->id;
1229 }
1230 else
1231 {
1232 create(group,Group);
1233 group->min = ip->min;
1234 group->id = groupidx++;
1235 ip->group = group->id;
1236
1237 if(group->min<8) group->min=8;
1238 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1239 /* it is because class IDs are derived from min. bandwidth. - xCh */
1240 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1241
1242 group->count=1;
1243 group->desired=ip->min;
1244 insert(group,groups,desc_order_by,min);
1245 }
1246 }//endif keyword-
1247 }//endif sharing-
1248 }
1249 fail
1250 {
1251 perror(hosts);
1252 exit(-1);
1253 }
1254 done;
1255
1256 /*-----------------------------------------------------------------*/
1257 /* cll1.h - let's allocate brand new character buffer... */
1258 /*-----------------------------------------------------------------*/
1259 string(str,STRLEN);
1260
1261 /*-----------------------------------------------------------------*/
1262 puts("Resolving shared connections ...");
1263 /*-----------------------------------------------------------------*/
1264 for_each(ip,ips) if(ip->sharing)
1265 {
1266 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))
1267 {
1268 sharedip->traffic+=ip->traffic;
1269 ip->traffic=0;
1270 ip->mark=sharedip->mark;
1271 ip->lmsid=sharedip->lmsid;
1272 break;
1273 }
1274 if(!sharedip)
1275 {
1276 printf("Unresolved shared connection: %s %s sharing-%s\n",
1277 ip->addr, ip->name, ip->sharing);
1278 }
1279 }
1280
1281 if(enable_credit && just_flush<9)
1282 {
1283 /*-----------------------------------------------------------------*/
1284 printf("Parsing credit file %s ...\n", credit);
1285 /*-----------------------------------------------------------------*/
1286 parse(credit)
1287 {
1288 ptr=parse_datafile_line(_);
1289 if(ptr)
1290 {
1291 if_exists(ip,ips,eq(ip->addr,_))
1292 {
1293 sscanf(ptr,"%Lu",&(ip->credit));
1294 }
1295 }
1296 }
1297 done;
1298 }
1299
1300 if(!just_preview)
1301 {
1302 /*-----------------------------------------------------------------*/
1303 puts("Initializing iptables and tc classes ...");
1304 /*-----------------------------------------------------------------*/
1305
1306 iptables_file=fopen(iptablesfile,"w");
1307 if(iptables_file == NULL)
1308 {
1309 puts("Cannot open iptablesfile!");
1310 exit(-1);
1311 }
1312
1313 log_file=fopen(cmdlog,"w");
1314 if(log_file == NULL)
1315 {
1316 puts("Cannot open logfile!");
1317 exit(-1);
1318 }
1319
1320 save_line(iptablespreamble);
1321 run_restore();
1322
1323 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
1324 safe_run(str);
1325
1326 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
1327 safe_run(str);
1328
1329 iptables_file=fopen(iptablesfile,"w");
1330 save_line(iptablespreamble);
1331
1332 if(qos_free_zone && *qos_free_zone!='0')
1333 {
1334 char *chain;
1335
1336 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
1337 save_line(str);
1338
1339 if(qos_proxy)
1340 {
1341 save_line(":post_noproxy - [0:0]");
1342 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
1343 save_line(str);
1344 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
1345 save_line(str);
1346 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
1347 save_line(str);
1348
1349 chain="post_noproxy";
1350 }
1351 else
1352 {
1353 chain="POSTROUTING";
1354 }
1355
1356 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1357 save_line(str);
1358 }
1359
1360 if(ip_count>idxtable_treshold1 && !just_flush)
1361 {
1362 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1363 char *subnet, *buf;
1364 /*-----------------------------------------------------------------*/
1365 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1366 /*-----------------------------------------------------------------*/
1367
1368 save_line(":post_common - [0:0]");
1369 save_line(":forw_common - [0:0]");
1370
1371 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1372 {
1373 buf=hash_id(ip->addr,bitmask);
1374 if_exists(idx,idxs,eq(idx->id,buf))
1375 {
1376 idx->children++;
1377 }
1378 else
1379 {
1380 create(idx,Index);
1381 idx->addr=ip->addr;
1382 idx->id=buf;
1383 idx->bitmask=bitmask;
1384 idx->parent=NULL;
1385 idx->children=0;
1386 idxcount++;
1387 push(idx,idxs);
1388 }
1389 }
1390
1391 /* brutal perfomance optimalization */
1392 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1393 {
1394 bitmask-=idxtable_bitmask2;
1395 idxcount=0;
1396
1397 for_each(idx,idxs) if(idx->parent == NULL)
1398 {
1399 buf=hash_id(idx->addr,bitmask);
1400 if_exists(metaindex,idxs,eq(metaindex->id,buf))
1401 {
1402 metaindex->children++;
1403 }
1404 else
1405 {
1406 create(metaindex,Index);
1407 metaindex->addr=idx->addr;
1408 metaindex->id=buf;
1409 metaindex->bitmask=bitmask;
1410 metaindex->parent=NULL;
1411 metaindex->children=0;
1412 idxcount++;
1413 push(metaindex,idxs);
1414 }
1415 idx->parent=metaindex;
1416 }
1417 }
1418
1419 /* this should slightly optimize throughout ... */
1420 sort(idx,idxs,desc_order_by,children);
1421 sort(idx,idxs,order_by,bitmask);
1422
1423 i=0;
1424 for_each(idx,idxs)
1425 {
1426 subnet=subnet_id(idx->addr,idx->bitmask);
1427 printf("%d: %s/%d\n",
1428 ++i, subnet, idx->bitmask);
1429
1430 sprintf(str,":post_%s - [0:0]", idx->id);
1431 save_line(str);
1432
1433 sprintf(str,":forw_%s - [0:0]", idx->id);
1434 save_line(str);
1435
1436 if(idx->parent)
1437 {
1438 string(buf,strlen(idx->parent->id)+6);
1439 sprintf(buf,"post_%s",idx->parent->id);
1440 }
1441 else
1442 {
1443 buf="POSTROUTING";
1444 }
1445
1446 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1447 save_line(str);
1448
1449 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1450 save_line(str);
1451
1452 if(idx->parent)
1453 {
1454 string(buf,strlen(idx->parent->id)+6);
1455 sprintf(buf,"forw_%s",idx->parent->id);
1456 }
1457 else
1458 {
1459 buf="FORWARD";
1460 }
1461
1462 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1463 save_line(str);
1464
1465 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1466 save_line(str);
1467 }
1468 printf("Total indexed iptables chains created: %d\n", i);
1469
1470 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1471 save_line(str);
1472
1473 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1474 save_line(str);
1475 }
1476
1477 }
1478
1479 if(just_flush)
1480 {
1481 fclose(iptables_file);
1482 if(log_file)
1483 {
1484 fclose(log_file);
1485 }
1486 puts("Just flushed iptables and tc classes - now exiting ...");
1487 exit(0);
1488 }
1489
1490 if(!just_preview)
1491 {
1492 if(!dry_run && !nodelay && qos_free_delay)
1493 {
1494 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1495 sleep(qos_free_delay);
1496 }
1497
1498 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1499 tc,lan,htb_r2q);
1500 safe_run(str);
1501
1502 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1503 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
1504 safe_run(str);
1505
1506 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1507 tc,lan,line,line,burst_main,highest_priority);
1508 safe_run(str);
1509
1510 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1511 safe_run(str);
1512
1513 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1514 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
1515 safe_run(str);
1516
1517 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1518 tc,wan,up,up,burst_main,highest_priority);
1519 safe_run(str);
1520 }
1521
1522 /*-----------------------------------------------------------------*/
1523 puts("Locating heavy downloaders and generating root classes ...");
1524 /*-----------------------------------------------------------------*/
1525 sort(ip,ips,desc_order_by,traffic);
1526
1527 /*-----------------------------------------------------------------*/
1528 /* sub-scope - local variables */
1529 {
1530 long long int rate = line;
1531 long long int max = line;
1532 int group_count = 0;
1533 FILE *credit_file = NULL;
1534
1535 if(!just_preview && !dry_run && enable_credit)
1536 {
1537 credit_file = fopen(credit,"w");
1538 }
1539
1540 for_each(group,groups)
1541 {
1542 if(!just_preview)
1543 {
1544 //download
1545 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",
1546 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
1547 safe_run(str);
1548
1549 //upload
1550 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",
1551 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
1552 safe_run(str);
1553 }
1554
1555 if(group_count++ < max_nesting)
1556 {
1557 parent = group->id;
1558 }
1559
1560 rate -= digital_divide*group->min;
1561 if(rate < group->min)
1562 {
1563 rate = group->min;
1564 }
1565
1566 /*shaping of aggresive downloaders, with credit file support */
1567 if(use_credit)
1568 {
1569 int group_rate = group->min, priority_sequence = lowest_priority;
1570
1571 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
1572 {
1573 if( ip->keyword->data_limit && !ip->fixedprio
1574 && ( ip->traffic>ip->credit
1575 + (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))) )
1576 {
1577 if(group_rate<ip->max)
1578 {
1579 ip->max=group_rate;
1580 }
1581 group_rate+=magic_treshold;
1582 ip->prio=lowest_priority;
1583 if(ip->prio<highest_priority+2)
1584 {
1585 ip->prio=highest_priority+2;
1586 }
1587 }
1588 else
1589 {
1590 if( ip->keyword->data_prio
1591 && !ip->fixedprio
1592 && ( ip->traffic>ip->credit
1593 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1594 {
1595 ip->prio=priority_sequence--;
1596 if(ip->prio<highest_priority+1)
1597 {
1598 ip->prio=highest_priority+1;
1599 }
1600 }
1601
1602 if(credit_file)
1603 {
1604 unsigned long long lcredit=0;
1605
1606 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1607 {
1608 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1609 }
1610 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1611 }
1612 }
1613 }
1614 }
1615 }
1616 if(credit_file)
1617 {
1618 fclose(credit_file);
1619 }
1620 }
1621
1622 if(just_preview)
1623 {
1624 f=fopen(preview,"w");
1625 ptr=preview;
1626 }
1627 else if(!dry_run && !just_flush)
1628 {
1629 /*-----------------------------------------------------------------*/
1630 printf("Writing daily statistics %s ... ", json);
1631 /*-----------------------------------------------------------------*/
1632 f=fopen(json, "w");
1633 if(f > 0)
1634 {
1635 int jsoncount=0;
1636 fprintf(f, "{\n");
1637 for_each(ip, ips)
1638 {
1639 if(jsoncount)
1640 {
1641 fprintf(f, ",\n");
1642 }
1643 if(ip->traffic || ip->direct || ip->proxy || ip->upload)
1644 {
1645 fprintf(f, " %d:{ \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu }",
1646 ip->lmsid, ip->addr, ip->traffic, ip->direct, ip->proxy, ip->upload);
1647 }
1648 jsoncount++;
1649 }
1650 fprintf(f, "}\n");
1651 fclose(f);
1652 puts("done.");
1653 }
1654 else
1655 {
1656 perror(json);
1657 }
1658 f=fopen(html,"w");
1659 ptr=html;
1660 }
1661
1662 if(f)
1663 {
1664 int count=1;
1665 i=0;
1666
1667 /*-----------------------------------------------------------------*/
1668 printf("Sorting data and generating statistics page %s ...\n", ptr);
1669 /*-----------------------------------------------------------------*/
1670
1671 if(use_jquery_popups)
1672 {
1673 fprintf(f,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url);
1674 }
1675 fputs("<table class=\"decorated last\">\n\
1676 <caption>Bandwidth classes</caption>\n\
1677 <thead><tr>\n\
1678 <th style=\"text-align: right\">#</th>\n\
1679 <th style=\"text-align: right\">group</th>\n\
1680 <th style=\"text-align: right\">IPs</th>\n\
1681 <th style=\"text-align: right\">requested</th>\n",f);
1682 fprintf(f,"<th colspan=\"%d\">data limits</th>\n", keywordcount);
1683 fputs("</tr></thead><tbody>\n",f);
1684
1685 row_odd_even = 0;
1686 for_each(group, groups)
1687 {
1688 #ifdef DEBUG
1689 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group->min,group->count,group->desired);
1690 #endif
1691 fprintf(f, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1692 tr_odd_even(), count, group->min);
1693 fprintf(f, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1694 group->count, group->desired);
1695
1696 for_each(keyword, keywords) if(keyword->ip_count)
1697 {
1698 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d&nbsp;MB</span></td>",
1699 keyword->html_color, group->min*keyword->data_limit);
1700 }
1701 i += group->desired;
1702 total += group->count;
1703 count++;
1704 }
1705 #ifdef DEBUG
1706 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1707 count, i, i/line);
1708 #endif
1709 fprintf(f,"</tr></tbody>\n\
1710 <thead><tr>\n\
1711 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line);
1712 fprintf(f,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total,i);
1713
1714 for_each(keyword, keywords) if(keyword->ip_count)
1715 {
1716 fprintf(f,"<th style=\"text-align: right\">%d IPs</th>",keyword->ip_count);
1717 }
1718 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i/line));
1719 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount, total);
1720
1721 fputs("</thead></table>\n",f);
1722 }
1723 else if(!dry_run && !just_flush)
1724 {
1725 perror(html);
1726 }
1727
1728 i=0;
1729 if(f)
1730 {
1731 unsigned long long total_traffic=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1732 int active_classes=0;
1733 int colspan=12;
1734 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1735 int limit_count=0, prio_count=0;
1736 int popup_button=0;
1737
1738 if(qos_proxy)
1739 {
1740 colspan++;
1741 }
1742
1743 fprintf(f,"<p><table class=\"decorated last\">\n<caption>%s",title);
1744 fprintf(f," (%s)</caption>\n", d);
1745 fputs("<thead><tr>\n<th colspan=\"3\">&nbsp;</th>\n",f);
1746 fputs("<th style=\"text-align: right\">credit</th>\n\
1747 <th style=\"text-align: right\">FUP</th>\n\
1748 <th style=\"text-align: right\">total</th>\n\
1749 <th style=\"text-align: right\">down</th>\n",f);
1750 if(qos_proxy)
1751 {
1752 fputs("<th style=\"text-align: right\">proxy</th>\n",f);
1753 }
1754 fputs("<th style=\"text-align: right\">up</th>\n\
1755 <th style=\"text-align: right\">min</th>\n\
1756 <th style=\"text-align: right\">max</th>\n\
1757 <th style=\"text-align: right\">limit</th>\n\
1758 <th>&nbsp;</th>\n\
1759 </tr><tr>\n\
1760 <th style=\"text-align: right\">#</th>\n\
1761 <th>hostname [+sharing]</th>\n\
1762 <th style=\"text-align: right\">LMS</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\">MB</th>\n\
1768 <th style=\"text-align: right\">kb/s</th>\n\
1769 <th style=\"text-align: right\">kb/s</th>\n\
1770 <th style=\"text-align: right\">kb/s</th>\n\
1771 <th>prio</th>\n\
1772 </tr></thead><tbody>\n",f);
1773
1774 row_odd_even = 0;
1775 for_each(ip,ips) if(!use_jquery_popups || !ip->sharing)
1776 {
1777 char *f1="", *f2="";
1778 i++;
1779
1780 if(ip->max < ip->desired)
1781 {
1782 f1="<span style=\"color:red\">";
1783 f2="</span>";
1784 limit_count++;
1785 }
1786 else if(ip->prio > highest_priority+1)
1787 {
1788 f1="<span style=\"color:brown\">";
1789 f2="</span>";
1790 prio_count++;
1791 }
1792
1793 #ifdef DEBUG
1794 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1795 #endif
1796 /* hostnames -------------------------------------- */
1797 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",
1798 tr_odd_even(), ip->name, i, log_url, ip->name, ip->name);
1799
1800 if(use_jquery_popups)
1801 {
1802 fprintf(f,"<span id=\"sharing_%d\" style=\"display:none\">",i);
1803 popup_button=0;
1804 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1805 {
1806 fprintf(f,"<br /><a class=\"blue\" href=\"%s%s.log\">%s</a>\n", log_url, sharedip->name, sharedip->name);
1807 popup_button++;
1808 }
1809 fputs("</span>\n",f);
1810 if(popup_button)
1811 {
1812 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>",
1813 i, i, i, popup_button);
1814 }
1815 }
1816 fputs("</td>\n",f);
1817 /* ----------------------------------------------- */
1818
1819 if(found_lmsid)
1820 {
1821 fputs("<td style=\"text-align: right\">",f);
1822 if(ip->lmsid > 0)
1823 {
1824 fprintf(f,"<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url, ip->lmsid, ip->lmsid);
1825 }
1826 else if(ip->lmsid == 0)
1827 {
1828 fputs("-------",f);
1829 }
1830 fputs("</td>\n",f);
1831 }
1832 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->credit);
1833 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1834 ip->keyword->html_color,
1835 ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1836 fprintf(f,"<td style=\"text-align: right\">%s%Lu%s", f1, ip->traffic, f2);
1837
1838 /* download --------------------------------------- */
1839 fprintf(f,"</td><td style=\"text-align: right\">%Lu", ip->direct);
1840 if(use_jquery_popups)
1841 {
1842 fprintf(f,"<span id=\"download_%d\" style=\"display:none\">",i);
1843 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1844 {
1845 fprintf(f,"<br />%Lu", sharedip->direct);
1846 }
1847 fputs("</span>\n",f);
1848 }
1849 fputs("</td>\n",f);
1850 /* ----------------------------------------------- */
1851
1852 if(qos_proxy)
1853 {
1854 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->proxy);
1855 }
1856 /* upload ---------------------------------------- */
1857 fprintf(f,"<td style=\"text-align: right\">%Lu", ip->upload);
1858 if(use_jquery_popups)
1859 {
1860 fprintf(f,"<span id=\"upload_%d\" style=\"display:none\">",i);
1861 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))
1862 {
1863 fprintf(f,"<br />%Lu", sharedip->upload);
1864 if(!just_preview)
1865 {
1866 append_log(sharedip);
1867 }
1868 }
1869 fputs("</span>\n",f);
1870 }
1871 fputs("</td>\n",f);
1872 /* ----------------------------------------------- */
1873
1874 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1875 <td style=\"text-align: right\">%d</td>\n\
1876 <td style=\"text-align: right\">%s%d%s</td>\n\
1877 <td>%s%d%s</td></tr>\n",
1878 ip->min, ip->desired,
1879 f1, ip->max, f2,
1880 f1, ip->prio, f2);
1881
1882 total_traffic+=ip->traffic;
1883 total_direct+=ip->direct;
1884 total_proxy+=ip->proxy;
1885 total_upload+=ip->upload;
1886 if(ip->traffic>0)
1887 {
1888 active_classes++;
1889 tmp_sum+=ip->traffic;
1890 create(sum,Sum);
1891 sum->l=tmp_sum;
1892 sum->i=active_classes;
1893 insert(sum,sums,order_by,i);
1894 }
1895
1896 if(!just_preview)
1897 {
1898 append_log(ip);
1899 }
1900 }
1901 fprintf(f,"</tbody><thead><tr>\n\
1902 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan-7, i);
1903 fprintf(f,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic, total_direct);
1904 if(qos_proxy)
1905 {
1906 fprintf(f,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy);
1907 }
1908 fprintf(f,"<th style=\"text-align: right\">%Lu</th>", total_upload);
1909 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);
1910
1911 row_odd_even = 0;
1912 if(active_classes>10)
1913 {
1914 int top20_count=0,top20_perc1=0;
1915 long long top20_perc2=0;
1916 unsigned long long top20_sum=0l;
1917
1918 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f);
1919 fputs("<thead><tr>\n\
1920 <th>Analytic category</th>\n\
1921 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1922 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1923 </tr></thead><tbody>\n",f);
1924
1925 if_exists(sum,sums,sum->l>=total_traffic/4)
1926 {
1927 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1928 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);
1929 }
1930
1931 if_exists(sum,sums,sum->i==10)
1932 {
1933 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1934 fprintf(f,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1935 <td style=\"text-align: right\">%d %%</td>\n\
1936 <td style=\"text-align: right\">%Lu MB</td>\n\
1937 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1938 (100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1939 }
1940
1941 if_exists(sum,sums,sum->l>=total_traffic/2)
1942 {
1943 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1944 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1945 <td style=\"text-align: right\">%d %%</td>\n\
1946 <td style=\"text-align: right\">%Lu MB</td>\n\
1947 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1948 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1949 }
1950
1951 if_exists(sum,sums,sum->l>=4*total_traffic/5)
1952 {
1953 fprintf(f,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1954 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1955 <td style=\"text-align: right\">%d %%</td>\n\
1956 <td style=\"text-align: right\">%Lu MB</td>\n\
1957 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1958 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1959 }
1960
1961 if_exists(sum,sums,sum->i>=(active_classes+1)/5)
1962 {
1963 fprintf(f,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1964 top20_count=sum->i;
1965 top20_perc1=(100*sum->i+50)/active_classes;
1966 top20_sum=sum->l;
1967 top20_perc2=(100*sum->l+50)/total_traffic;
1968 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1969 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1970 <td style=\"text-align: right\">%Lu MB</td>\n\
1971 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1972 top20_count,top20_perc1,top20_sum,top20_perc2);
1973 }
1974
1975 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1976 {
1977 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1978 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1979 <td style=\"text-align: right\">%d %%</td>\n\
1980 <td style=\"text-align: right\">%Lu MB</td>\n\
1981 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1982 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1983 }
1984
1985 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1986 {
1987 fprintf(f,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1988 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1989 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1990 <td style=\"text-align: right\">%Lu MB</td>\n\
1991 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1992 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1993 }
1994
1995 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1996 {
1997 fprintf(f,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1998 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1999 <td style=\"text-align: right\">%d %%</td>\n\
2000 <td style=\"text-align: right\">%Lu MB</td>\n\
2001 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
2002 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
2003 }
2004
2005 fprintf(f,"<tr><thead><th><a class=\"blue\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url);
2006 fprintf(f,"<th style=\"text-align: right\">%d</th>\n\
2007 <th style=\"text-align: right\">100 %%</th>\n\
2008 <th style=\"text-align: right\">%Lu M</th>\n\
2009 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes,total_traffic);
2010 fputs("</thead></table>\n", f);
2011
2012 /* write basic ERP data to log directory */
2013 if(!just_preview)
2014 {
2015 FILE *iplog;
2016 sprintf(str,"%s/ERP.log",log_dir);
2017 iplog=fopen(str,"a");
2018 if(iplog)
2019 {
2020 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",
2021 time(NULL), top20_count, top20_perc1, top20_sum, top20_perc2,
2022 active_classes, total_traffic, i, limit_count, prio_count, d); /* d = date*/
2023 fclose(iplog);
2024 }
2025 else
2026 {
2027 perror(str);
2028 }
2029 }
2030 }
2031
2032 fprintf(f, stats_html_signature, version);
2033 fclose(f);
2034 }
2035
2036 if(just_preview)
2037 {
2038 puts("Statistics preview generated (-p switch) - now exiting ...");
2039 exit(0);
2040 }
2041
2042 i=0;
2043 #ifdef DEBUG
2044 printf("%-22s %-15s mark\n","name","ip");
2045 #endif
2046
2047 printf("Writing %s ... ", classmap);
2048 f = fopen(classmap, "w");
2049 if(f < 0)
2050 {
2051 perror(classmap);
2052 }
2053
2054 /*-----------------------------------------------------------------*/
2055 puts("Generating iptables and tc classes ... ");
2056 /*-----------------------------------------------------------------*/
2057
2058 for_each(ip, ips) if(ip->mark > 0)
2059 {
2060 if(idxs)
2061 {
2062 char *buf;
2063 duplicate(ip->addr,buf);
2064 buf=hash_id(ip->addr,32-idxtable_bitmask1);
2065
2066 string(chain_forward,6+strlen(buf));
2067 strcpy(chain_forward,"forw_");
2068 strcat(chain_forward,buf);
2069
2070 string(chain_postrouting,6+strlen(buf));
2071 strcpy(chain_postrouting,"post_");
2072 strcat(chain_postrouting,buf);
2073
2074 free(buf);
2075 }
2076 else
2077 {
2078 chain_forward="FORWARD";
2079 chain_postrouting="POSTROUTING";
2080 }
2081
2082 #ifdef DEBUG
2083 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
2084 #endif
2085
2086 /* -------------------------------------------------------- mark download */
2087
2088 sprintf(str, "-A %s -d %s/32 -o %s -j %s%d",
2089 chain_postrouting, ip->addr, lan, mark_iptables, ip->mark);
2090 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
2091 /* -m limit --limit 1/s */
2092 save_line(str);
2093
2094 if(qos_proxy)
2095 {
2096 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
2097 chain_postrouting, proxy_ip, proxy_port, ip->addr, lan, mark_iptables, ip->mark);
2098 /*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);*/
2099 save_line(str);
2100 }
2101
2102 sprintf(str, "-A %s -d %s/32 -o %s -j ACCEPT",
2103 chain_postrouting, ip->addr, lan);
2104 save_line(str);
2105
2106 /* -------------------------------------------------------- mark upload */
2107 sprintf(str, "-A %s -s %s/32 -o %s -j %s%d",
2108 chain_forward, ip->addr, wan, mark_iptables, ip->mark);
2109 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
2110 save_line(str);
2111
2112 sprintf(str, "-A %s -s %s/32 -o %s -j ACCEPT",
2113 chain_forward, ip->addr, wan);
2114 save_line(str);
2115
2116 if(ip->min)
2117 {
2118 /* -------------------------------------------------------- download class */
2119 #ifdef DEBUG
2120 printf("(down: %dk-%dk ", ip->min, ip->max);
2121 #endif
2122
2123 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2124 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
2125 safe_run(str);
2126
2127 if(strcmpi(ip->keyword->leaf_discipline, "none"))
2128 {
2129 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
2130 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
2131 safe_run(str);
2132 }
2133
2134 if(filter_type == 1)
2135 {
2136 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2137 tc, lan, ip->mark, ip->mark);
2138 safe_run(str);
2139 }
2140
2141 /* -------------------------------------------------------- upload class */
2142 #ifdef DEBUG
2143 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
2144 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
2145 #endif
2146
2147 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2148 tc, wan, ip->group, ip->mark,
2149 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
2150 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
2151 safe_run(str);
2152
2153 if(strcmpi(ip->keyword->leaf_discipline, "none"))
2154 {
2155 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
2156 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
2157 safe_run(str);
2158 }
2159
2160 if(filter_type == 1)
2161 {
2162 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2163 tc, wan, ip->mark, ip->mark);
2164 safe_run(str);
2165 }
2166
2167 if(f)
2168 {
2169 fprintf(f, "%s %d", ip->addr, ip->mark);
2170 }
2171 }
2172 else
2173 {
2174 #ifdef DEBUG
2175 printf("(sharing %s)\n", ip->sharing);
2176 #endif
2177 }
2178 i++;
2179 }
2180 if(f)
2181 {
2182 puts("done.");
2183 fclose(f);
2184 }
2185
2186 if(idxs)
2187 {
2188 chain_forward = "forw_common";
2189 chain_postrouting = "post_common";
2190 }
2191 else
2192 {
2193 chain_forward = "FORWARD";
2194 chain_postrouting = "POSTROUTING";
2195 }
2196 /* -------------------------------- classify or reject free download */
2197 {
2198 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
2199 if(free_min)
2200 {
2201 final_chain = "ACCEPT";
2202 }
2203 if(qos_proxy)
2204 {
2205 if(free_min)
2206 {
2207 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
2208 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
2209 save_line(str);
2210 }
2211 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
2212 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
2213 save_line(str);
2214 }
2215 if(free_min)
2216 {
2217 sprintf(str,"-A %s -o %s -j %s%d", chain_postrouting, lan, mark_iptables, 3);
2218 save_line(str);
2219 }
2220 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
2221 save_line(str);
2222 /* ------------------------------- classify or reject free upload */
2223 if(free_min)
2224 {
2225 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);
2226 save_line(str);
2227 }
2228 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);
2229 save_line(str);
2230 }
2231
2232 if(free_min) /* allocate free bandwith if it is not zero... */
2233 {
2234 /*-----------------------------------------------------------------*/
2235 puts("Generating free bandwith classes ...");
2236 /*-----------------------------------------------------------------*/
2237 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2238 tc, lan, parent, free_min, free_max,burst, lowest_priority);
2239 safe_run(str);
2240 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2241 tc, wan, parent, free_min, free_max, burst, lowest_priority);
2242 safe_run(str);
2243 /* tc SFQ */
2244 if(strcmpi(qos_leaf, "none"))
2245 {
2246 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);
2247 safe_run(str);
2248
2249 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);
2250 safe_run(str);
2251 }
2252 /* tc handle 1 fw flowid */
2253 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);
2254 safe_run(str);
2255
2256 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);
2257 safe_run(str);
2258 }
2259 printf("Total IP count: %d\n", i);
2260 run_restore();
2261 if(log_file)
2262 {
2263 fclose(log_file);
2264 }
2265 return 0;
2266 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2267 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
2268 }
This page took 1.826395 seconds and 3 git commands to generate.