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