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