beaffcb78b2b4266e82ff7a14dbce57b312a0b8e
[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, 20121011
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 512
30 #undef DEBUG
31
32 #include "cll1-0.6.2.h"
33 #include "ipstruct.h"
34
35 const char *version = "0.8.3-g";
36
37 /* Version numbers: 0.8.3 is development releases ("beta"), 0.8.4 will be "stable" */
38 /* Debian(RPM) package versions/patchlevels: 0.7.9-2, 0.8.0-1, 0.8.0-2, etc. */
39 /* C source code development versions ("beta"): 0.7.9-a, 0.8.1-b, etc. */
40 /* C source code release versions: 0.8.0, 0.8.2, 0.8.4, etc. */
41
42 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";
43
44 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
45
46 void help(void)
47 {
48 puts("Command line switches:\n\
49 \n\
50 -d Dry run (preview tc and iptables commands on stdout)\n\
51 -r Run (reset all statistics and start shaping - daily usage)\n\
52 -p just generate Preview of data transfer statistics and exit (after -r)\n\
53 -s start Shaping FUP limits (keeps data transfer stat like -p) (after -r)\n\
54 -n run Now (like -r delay - overrides qos-free-delay keyword, after boot)\n\
55 -f just Flush iptables and tc classes and exit (stop shaping, no QiS)\n\
56 -9 emergency iptables flush (like -f, but dumps data transfer statistics)\n\
57 \n\
58 -c filename force alternative /etc/prometheus/prometheus.conf filename\n\
59 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
60 -l Mmm YYYY generate HTML summary of Logged traffic (Mmm=Jan-Dec) (and exit)\n\
61 -m generate HTML summary of traffic for yesterday's Month (and exit)\n\
62 -y generate HTML summary of traffic for yesterday's Year (and exit)\n\
63 -? --help show this help scree (and exit)\n\
64 -v --version show Version number of this utility (and exit)\n");
65 }
66
67 /* ======= All path names are defined here (for RPM patch) ======= */
68
69 const char *tc = "/sbin/tc"; /* requires tc with HTB support */
70 const char *iptables = "/sbin/iptables"; /* requires iptables utility */
71 const char *iptablessave = "/sbin/iptables-save"; /* not yet required */
72 const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */
73 const char *ls = "/bin/ls"; /* this is not user configurable :-) */
74
75 char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */
76 char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
77
78 char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
79 char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */
80 char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */
81 char *html = "/var/www/traffic.html"; /* hall of fame - html version */
82 char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */
83 char *json = "/var/www/logs/traffic.json"; /* hall of fame - json version */
84 char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */
85 char *cmdlog = "/var/log/prometheuslog"; /* command log filename */
86 char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */
87 char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */
88 char *html_log_dir = "/var/www/logs/html/";
89
90 char *jquery_url = "http://code.jquery.com/jquery-latest.js";
91 char *lms_url = "/lms/?m=customerinfo&amp;id=";
92 int use_jquery_popups = 1;
93 int row_odd_even = 0; /*<tr class="odd/even"> */
94
95 /* === Configuraration file values defaults - stored in global variables ==== */
96
97 int filter_type = 1; /*1 mark, 2 classify*/
98 char *mark = "MARK";
99 char *mark_iptables = "MARK --set-mark ";
100 int dry_run = 0; /* preview - use puts() instead of system() */
101 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]";
102 FILE *iptables_file = NULL;
103 int enable_credit = 1; /* enable credit file */
104 int use_credit = 0; /* use credit file (if enabled)*/
105 char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */
106 int hall_of_fame = 1; /* enable hall of fame */
107 char *lan = "eth0"; /* LAN interface */
108 char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
109 char *wan = "eth1"; /* WAN/ISP interface */
110 char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
111 char *qos_leaf = "sfq perturb 5"; /* leaf discipline */
112 char *qos_free_zone = NULL; /* QoS free zone */
113 int qos_proxy = 1; /* include proxy port to QoS */
114 int found_lmsid = 0; /* show links to users in LMS information system */
115 int include_upload = 1; /* upload+download=total traffic */
116 char *proxy_ip = "192.168.1.1/32"; /* our IP with proxy port */
117 int proxy_port = 3128; /* proxy port number */
118 long long int line = 1024; /* WAN/ISP download in kbps */
119 long long int up = 1024; /* WAN/ISP upload in kbps */
120 int free_min = 32; /* minimum guaranted bandwidth for all undefined hosts */
121 int free_max = 64; /* maximum allowed bandwidth for all undefined hosts */
122 int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */
123 int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */
124 int max_nesting = 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
125 int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */
126 int burst = 8; /* HTB burst (in kbits) */
127 int burst_main = 64;
128 int burst_group = 32;
129 int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
130 int keywordcount = 0;
131 int class_count = 0;
132 int ip_count = 0;
133 /* not yet implemented:
134 int fixed_packets = 0; maximum number of pps per IP address (not class!)
135 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
136 */
137 FILE *log_file = NULL;
138 char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
139
140 const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */
141 const int lowest_priority = 7; /* lowest HTB priority (HTB built-in value is 7) */
142 const int idxtable_treshold1 = 24; /* this is no longer configurable */
143 const int idxtable_treshold2 = 12; /* this is no longer configurable */
144 const int idxtable_bitmask1 = 3; /* this is no longer configurable */
145 const int idxtable_bitmask2 = 3; /* this is no longer configurable */
146
147 struct IP *ips = NULL, *ip, *sharedip;
148 struct Group *groups = NULL, *group;
149 struct Keyword *keyword, *defaultkeyword=NULL, *keywords=NULL;
150
151 void parse_ip_log(int argc, char **argv);
152 /* implementid in parselog.c */
153
154 void parse_hosts(char *hosts);
155 /* implementid in parsehosts.c */
156
157 const char *tr_odd_even(void)
158 {
159 row_odd_even = 1 - row_odd_even;
160 if(row_odd_even)
161 {
162 return "<tr class=\"even\">\n";
163 }
164 else
165 {
166 return "<tr class=\"odd\">\n";
167 }
168 }
169
170 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
171
172 struct Index
173 {
174 char *addr;
175 char *id;
176 struct Index *parent;
177 int bitmask;
178 int children;
179 list(Index);
180 } *idxs=NULL, *idx, *metaindex;
181
182 void TheIP(void);
183 /* function implemented in parsehosts.c */
184
185 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
186
187 char *index_id(char *ip, int bitmask);
188 /* function implemented in ipv4subnets.c */
189
190 char *subnet_id(char *ip, int bitmask);
191 /* function implemented in ipv4subnets.c */
192
193 /* ================= Let's parse configuration file here ================ */
194
195 void reject_config_and_exit(char *filename)
196 {
197 printf("Configuration file %s rejected - abnormal exit.",filename);
198 exit(-1);
199 }
200
201 void get_config(char *config_filename)
202 {
203 char *cnf="mark";
204
205 printf("Configured keywords: ");
206 parse(config_filename)
207 {
208 option("keyword",kwd);
209 if(kwd)
210 {
211 printf("%s ",kwd);
212
213 create(keyword,Keyword);
214 keyword->key=kwd;
215 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
216 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
217 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
218 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
219 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
220 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
221 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
222 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
223 keyword->default_prio=highest_priority+1;
224 keyword->html_color="000000";
225 keyword->ip_count=0;
226 keyword->leaf_discipline="";
227
228 push(keyword,keywords);
229 if(!defaultkeyword) defaultkeyword=keyword;
230 keywordcount++;
231
232 kwd=NULL;
233 }
234 else
235 {
236 for_each(keyword,keywords)
237 {
238 int l=strlen(keyword->key);
239
240 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
241 {
242 char *tmptr=_; /* <---- l+1 ----> */
243 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
244 ioption("asymetry-ratio",keyword->asymetry_ratio);
245 ioption("asymetry-treshold",keyword->asymetry_fixed);
246 ioption("magic-relative-limit",keyword->data_limit);
247 ioption("magic-relative-prio",keyword->data_prio);
248 loption("magic-fixed-limit",keyword->fixed_limit);
249 loption("magic-fixed-prio",keyword->fixed_prio);
250 ioption("htb-default-prio",keyword->default_prio);
251 ioption("htb-rate-bonus",keyword->reserve_min);
252 ioption("htb-ceil-malus",keyword->reserve_max);
253 option("leaf-discipline",keyword->leaf_discipline);
254 option("html-color",keyword->html_color);
255 _=tmptr;
256
257 if(keyword->data_limit || keyword->fixed_limit ||
258 keyword->data_prio || keyword->fixed_prio)
259 {
260 use_credit=1;
261 }
262 }
263 }
264 }
265
266 option("tc",tc);
267 option("iptables",iptables);
268 option("iptables-save",iptablessave); /* new */
269 option("iptables-restore",iptablesrestore); /* new */
270 option("iptables-in-filename",iptablesfile); /* new */
271 option("hosts",hosts);
272 option("lan-interface",lan);
273 option("wan-interface",wan);
274 option("lan-medium",lan_medium);
275 option("wan-medium",wan_medium);
276 lloption("wan-download",line);
277 lloption("wan-upload",up);
278 ioption("hall-of-fame-enable",hall_of_fame);
279 option("hall-of-fame-title",title);
280 option("hall-of-fame-filename",html);
281 option("json-filename",json);
282 option("hall-of-fame-preview",preview);
283 option("json-preview",json_preview);
284 option("log-filename",cmdlog);
285 option("credit-filename",credit);
286 option("classmap-filename",classmap);
287 ioption("credit-enable",enable_credit);
288 option("log-traffic-directory",log_dir);
289 option("log-traffic-html-directory",html_log_dir);
290 option("log-traffic-url-path",log_url);
291 option("jquery-url",jquery_url);
292 option("lms-url",lms_url);
293 ioption("use-jquery-popups",use_jquery_popups);
294 option("qos-free-zone",qos_free_zone);
295 ioption("qos-free-delay",qos_free_delay);
296 ioption("qos-proxy-enable",qos_proxy);
297 option("qos-proxy-ip",proxy_ip);
298 option("htb-leaf-discipline",qos_leaf);
299 ioption("qos-proxy-port",proxy_port);
300 ioption("free-rate",free_min);
301 ioption("free-ceil",free_max);
302 ioption("htb-burst",burst);
303 ioption("htb-burst-main",burst_main);
304 ioption("htb-burst-group",burst_group);
305 ioption("htb-nesting-limit",max_nesting);
306 ioption("htb-r2q",htb_r2q);
307 ioption("magic-include-upload",include_upload);
308 ioption("magic-treshold",magic_treshold);
309 option("filter-type", cnf);
310 /* not yet implemented:
311 ioption("magic-fixed-packets",fixed_packets);
312 ioption("magic-relative-packets",packet_limit);
313 */
314 }
315 fail
316 {
317 perror(config_filename);
318 puts("Warning - using built-in defaults instead ...");
319 }
320 done; /* ugly macro end */
321 printf("\n");
322
323 /* leaf discipline for keywords */
324 for_each(keyword,keywords)
325 {
326 if(!strcmpi(keyword->leaf_discipline, ""))
327 {
328 keyword->leaf_discipline = qos_leaf;
329 }
330 }
331
332 if(strcmpi(cnf, "mark"))
333 {
334 filter_type = 2;
335 mark = "CLASSIFY";
336 mark_iptables = "CLASSIFY --set-class 1:";
337 }
338 else
339 {
340 filter_type = 1;
341 mark = "MARK";
342 mark_iptables = "MARK --set-mark ";
343 }
344
345 /* are supplied values meaningful ?*/
346 if(line<=0 || up<=0)
347 {
348 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
349 reject_config_and_exit(config_filename);
350 }
351 }
352
353 /* ===================== traffic analyser - uses iptables ================ */
354
355 void get_traffic_statistics(void)
356 {
357 char *str,*cmd;
358 int downloadflag=0;
359
360 textfile(Pipe,str) *line,*lines=NULL;
361 string(str,STRLEN);
362 string(cmd,STRLEN);
363
364 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
365 shell(cmd);
366 input(str,STRLEN)
367 {
368 create(line,Pipe);
369 line->str=str;
370 string(str,STRLEN);
371 append(line,lines);
372 }
373
374 for_each(line,lines)
375 {
376 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
377 unsigned long long traffic=0;
378 unsigned long pkts=0;
379 char *ipaddr=NULL,*ptr;
380
381 /* debug puts(line->str); */
382 valid_columns(ptr,line->str,' ',col)
383 if(valid) switch(col)
384 {
385 case 1: if(eq(ptr,"Chain"))
386 {
387 setchainname=1;
388 }
389 else if(eq(ptr,"pkts"))
390 {
391 valid=0;
392 }
393 else
394 {
395 sscanf(ptr,"%lu",&pkts);
396 }
397 break;
398 case 2: if(setchainname)
399 {
400 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
401 {
402 downloadflag = 1;
403 }
404 else
405 {
406 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
407 {
408 downloadflag = 0;
409 }
410 }
411 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
412 {
413 commonflag = 1;
414 }
415 }
416 else
417 {
418 sscanf(ptr,"%Lu",&traffic);
419 traffic += (1<<19);
420 traffic >>= 20;
421 }
422 break;
423 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)
424 {
425 accept=eq(ptr,mark);
426 }
427 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
428 break;
429 case 8: if(downloadflag)
430 {
431 if(strstr(proxy_ip,ptr))
432 {
433 proxyflag=1;
434 }
435 }
436 else
437 {
438 ipaddr=ptr;
439 }
440 break;
441 case 9: if(downloadflag)ipaddr=ptr;break;
442 }
443
444 if(accept && traffic>0 && ipaddr)
445 {
446 if(proxyflag)
447 {
448 printf("(proxy) ");
449 }
450 else if(!downloadflag)
451 {
452 printf("(upload) ");
453 }
454 printf("IP %s: %Lu MB (%ld pkts)\n", ipaddr, traffic, pkts);
455
456 if_exists(ip,ips,eq(ip->addr,ipaddr));
457 else
458 {
459 TheIP();
460 ip->addr=ipaddr;
461 if(eq(ip->addr,"0.0.0.0/0"))
462 {
463 ip->name="(unregistered)";
464 ip->min=free_min;
465 ip->max=ip->desired=free_max;
466 }
467 }
468
469 if(downloadflag)
470 {
471 if(proxyflag)
472 {
473 ip->proxy=traffic;
474 }
475 else
476 {
477 ip->traffic+=traffic;
478 }
479 ip->direct=ip->traffic-ip->upload-ip->proxy;
480 ip->pktsdown=pkts;
481 }
482 else
483 {
484 ip->upload=traffic;
485 ip->pktsup=pkts;
486 if(include_upload)
487 {
488 ip->traffic+=traffic;
489 }
490 else
491 {
492 if(traffic>ip->traffic)
493 {
494 ip->traffic=traffic;
495 }
496 }
497 }
498 }
499 }
500 free(cmd);
501 }
502
503 /* ========== This function executes, logs OR ALSO prints command ========== */
504
505 void safe_run(char *cmd)
506 {
507 if(dry_run)
508 {
509 printf("\n=>%s\n",cmd);
510 }
511 else
512 {
513 system(cmd);
514 }
515 if(log_file)
516 {
517 fprintf(log_file,"%s\n",cmd);
518 }
519 }
520
521 void save_line(char *line)
522 {
523 fprintf(iptables_file,"%s\n",line);
524 }
525
526 void run_restore(void)
527 {
528 char *restor;
529 string(restor,STRLEN);
530
531 /*-----------------------------------------------------------------*/
532 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);
533 /*-----------------------------------------------------------------*/
534
535 save_line("COMMIT");
536 fclose(iptables_file);
537 if(dry_run)
538 {
539 parse(iptablesfile)
540 {
541 printf("%s\n",_);
542 }
543 done; /* ugly macro end */
544 }
545
546 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);
547 safe_run(restor);
548
549 free(restor);
550 }
551
552 char *parse_datafile_line(char *str)
553 {
554 char *ptr=strchr(str,' ');
555
556 if(ptr)
557 {
558 *ptr=0;
559 ptr++;
560 return ptr;
561 }
562 else
563 {
564 return NULL;
565 }
566 }
567
568 void append_log(struct IP *self) /*using global variables*/
569 {
570 char *d, *str;
571 FILE *f;
572
573 date(d); /* this is typical cll1.h macro - prints current date */
574 string(str,STRLEN);
575 sprintf(str,"%s/%s.log", log_dir, self->name);
576 f=fopen(str,"a");
577 if(f > 0)
578 {
579 fprintf(f,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
580 time(NULL), self->name, self->traffic, self->direct, self->proxy,
581 self->upload, self->min, self->max, self->desired, self->lmsid, d); /* d = date*/
582 fclose(f);
583 }
584 else
585 {
586 perror(str);
587 }
588 }
589
590 /*-----------------------------------------------------------------*/
591 /* Are you looking for int main(int argc, char **argv) ? :-)) */
592 /*-----------------------------------------------------------------*/
593
594 program
595 {
596 int i=0; /* just plain old Fortran style integer :-) */
597 FILE *f=NULL; /* everything is just stream of bytes... */
598 char *str, *ptr, *d; /* LET A$=B$ :-) */
599 char *substring;
600
601 int parent=1;
602 int just_flush=FALSE; /* deactivates all previous actions */
603 int nodelay=FALSE;
604 int just_preview=FALSE; /* preview - generate just stats */
605 int start_shaping=FALSE; /* apply FUP - requires classmap file */
606 int just_logs=FALSE; /* just parse logs */
607 int run=FALSE;
608 int total=0;
609
610 char *chain_forward, *chain_postrouting;
611 char *althosts=NULL;
612
613 printf("\n\
614 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
615 Version %s - Copyright (C)2005-2012 Michael Polak, Arachne Labs\n\
616 iptables-restore & burst tunning & classify modification by Ludva\n\
617 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
618
619 /*----- Boring... we have to check command line options first: ----*/
620 arguments
621 {
622 argument("-c") { nextargument(config); }
623 argument("-h") { nextargument(althosts);}
624 argument("-d") { run=TRUE; dry_run=TRUE; }
625 argument("-f") { run=TRUE; just_flush=TRUE; }
626 argument("-9") { run=TRUE; just_flush=9; }
627 argument("-p") { run=TRUE; just_preview=TRUE; }
628 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }
629 argument("-r") { run=TRUE; }
630 argument("-n") { run=TRUE; nodelay=TRUE; }
631 argument("-l") { just_logs=TRUE; }
632 argument("-m") { just_logs=TRUE; }
633 argument("-y") { just_logs=TRUE; }
634 argument("-?") { help(); exit(0); }
635 argument("--help") { help(); exit(0); }
636 argument("-v") { exit(0); }
637 argument("--version") { exit(0); }
638 }
639
640 if(dry_run)
641 {
642 puts("*** THIS IS JUST DRY RUN ! ***\n");
643 }
644
645 date(d); /* this is typical cll1.h macro - prints current date */
646
647 /*-----------------------------------------------------------------*/
648 printf("Parsing configuration file %s ...\n", config);
649 /*-----------------------------------------------------------------*/
650 get_config(config);
651
652 if(just_logs)
653 {
654 parse_ip_log(argc,argv);
655 exit(0);
656 }
657 else if(not run)
658 {
659 help();
660 exit(0);
661 }
662
663 if(althosts)
664 {
665 hosts=althosts;
666 }
667
668 if(just_flush<9)
669 {
670 /*-----------------------------------------------------------------*/
671 puts("Parsing iptables verbose output ...");
672 /*-----------------------------------------------------------------*/
673 get_traffic_statistics();
674 }
675
676 /*-----------------------------------------------------------------*/
677 printf("Parsing class defintion file %s ...\n", hosts);
678 /*-----------------------------------------------------------------*/
679 parse_hosts(hosts);
680
681 /*-----------------------------------------------------------------*/
682 /* cll1.h - let's allocate brand new character buffer... */
683 /*-----------------------------------------------------------------*/
684 string(str,STRLEN);
685
686 /*-----------------------------------------------------------------*/
687 puts("Resolving shared connections ...");
688 /*-----------------------------------------------------------------*/
689 for_each(ip,ips) if(ip->sharing)
690 {
691 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))
692 {
693 sharedip->traffic+=ip->traffic;
694 ip->traffic=0;
695 ip->mark=sharedip->mark;
696 ip->lmsid=sharedip->lmsid;
697 break;
698 }
699 if(not sharedip)
700 {
701 printf("Unresolved shared connection: %s %s sharing-%s\n",
702 ip->addr, ip->name, ip->sharing);
703 }
704 }
705
706 if(enable_credit && just_flush<9)
707 {
708 /*-----------------------------------------------------------------*/
709 printf("Parsing credit file %s ...\n", credit);
710 /*-----------------------------------------------------------------*/
711 parse(credit)
712 {
713 ptr=parse_datafile_line(_);
714 if(ptr)
715 {
716 if_exists(ip,ips,eq(ip->addr,_))
717 {
718 sscanf(ptr,"%Lu",&(ip->credit));
719 }
720 }
721 }
722 done; /* ugly macro end */
723 }
724
725 if(!just_preview)
726 {
727 /*-----------------------------------------------------------------*/
728 puts("Initializing iptables and tc classes ...");
729 /*-----------------------------------------------------------------*/
730
731 iptables_file=fopen(iptablesfile,"w");
732 if(iptables_file == NULL)
733 {
734 puts("Cannot open iptablesfile!");
735 exit(-1);
736 }
737
738 log_file=fopen(cmdlog,"w");
739 if(log_file == NULL)
740 {
741 puts("Cannot open logfile!");
742 exit(-1);
743 }
744
745 save_line(iptablespreamble);
746 run_restore();
747
748 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
749 safe_run(str);
750
751 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
752 safe_run(str);
753
754 iptables_file=fopen(iptablesfile,"w");
755 save_line(iptablespreamble);
756
757 if(qos_free_zone && *qos_free_zone!='0')
758 {
759 char *chain;
760
761 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
762 save_line(str);
763
764 if(qos_proxy)
765 {
766 save_line(":post_noproxy - [0:0]");
767 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);
768 save_line(str);
769 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);
770 save_line(str);
771 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
772 save_line(str);
773
774 chain="post_noproxy";
775 }
776 else
777 {
778 chain="POSTROUTING";
779 }
780
781 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
782 save_line(str);
783 }
784
785 if(ip_count>idxtable_treshold1 && !just_flush)
786 {
787 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
788 char *subnet, *buf;
789 /*-----------------------------------------------------------------*/
790 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
791 /*-----------------------------------------------------------------*/
792
793 save_line(":post_common - [0:0]");
794 save_line(":forw_common - [0:0]");
795
796 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
797 {
798 buf=index_id(ip->addr,bitmask);
799 if_exists(idx,idxs,eq(idx->id,buf))
800 {
801 idx->children++;
802 }
803 else
804 {
805 create(idx,Index);
806 idx->addr=ip->addr;
807 idx->id=buf;
808 idx->bitmask=bitmask;
809 idx->parent=NULL;
810 idx->children=0;
811 idxcount++;
812 push(idx,idxs);
813 }
814 }
815
816 /* brutal perfomance optimalization */
817 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
818 {
819 bitmask-=idxtable_bitmask2;
820 idxcount=0;
821
822 for_each(idx,idxs) if(idx->parent == NULL)
823 {
824 buf=index_id(idx->addr,bitmask);
825 if_exists(metaindex,idxs,eq(metaindex->id,buf))
826 {
827 metaindex->children++;
828 }
829 else
830 {
831 create(metaindex,Index);
832 metaindex->addr=idx->addr;
833 metaindex->id=buf;
834 metaindex->bitmask=bitmask;
835 metaindex->parent=NULL;
836 metaindex->children=0;
837 idxcount++;
838 push(metaindex,idxs);
839 }
840 idx->parent=metaindex;
841 }
842 }
843
844 /* this should slightly optimize throughout ... */
845 sort(idx,idxs,desc_order_by,children);
846 sort(idx,idxs,order_by,bitmask);
847
848 i=0;
849 for_each(idx,idxs)
850 {
851 subnet=subnet_id(idx->addr,idx->bitmask);
852 printf("%d: %s/%d\n",
853 ++i, subnet, idx->bitmask);
854
855 sprintf(str,":post_%s - [0:0]", idx->id);
856 save_line(str);
857
858 sprintf(str,":forw_%s - [0:0]", idx->id);
859 save_line(str);
860
861 if(idx->parent)
862 {
863 string(buf,strlen(idx->parent->id)+6);
864 sprintf(buf,"post_%s",idx->parent->id);
865 }
866 else
867 {
868 buf="POSTROUTING";
869 }
870
871 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
872 save_line(str);
873
874 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
875 save_line(str);
876
877 if(idx->parent)
878 {
879 string(buf,strlen(idx->parent->id)+6);
880 sprintf(buf,"forw_%s",idx->parent->id);
881 }
882 else
883 {
884 buf="FORWARD";
885 }
886
887 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
888 save_line(str);
889
890 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
891 save_line(str);
892 }
893 printf("Total indexed iptables chains created: %d\n", i);
894
895 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
896 save_line(str);
897
898 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
899 save_line(str);
900 }
901
902 }
903
904 if(just_flush)
905 {
906 fclose(iptables_file);
907 if(log_file)
908 {
909 fclose(log_file);
910 }
911 puts("Just flushed iptables and tc classes - now exiting ...");
912 exit(0);
913 }
914
915 if(!just_preview)
916 {
917 if(!dry_run && !nodelay && qos_free_delay)
918 {
919 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
920 sleep(qos_free_delay);
921 }
922
923 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
924 tc,lan,htb_r2q);
925 safe_run(str);
926
927 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
928 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
929 safe_run(str);
930
931 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
932 tc,lan,line,line,burst_main,highest_priority);
933 safe_run(str);
934
935 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
936 safe_run(str);
937
938 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
939 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
940 safe_run(str);
941
942 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
943 tc,wan,up,up,burst_main,highest_priority);
944 safe_run(str);
945 }
946
947 /*-----------------------------------------------------------------*/
948 puts("Locating heavy downloaders and generating root classes ...");
949 /*-----------------------------------------------------------------*/
950 sort(ip,ips,desc_order_by,traffic);
951
952 /*-----------------------------------------------------------------*/
953 /* sub-scope - local variables */
954 {
955 long long int rate = line;
956 long long int max = line;
957 int group_count = 0;
958 FILE *credit_file = NULL;
959
960 if(!just_preview && !dry_run && enable_credit)
961 {
962 credit_file = fopen(credit,"w");
963 }
964
965 for_each(group,groups)
966 {
967 if(!just_preview)
968 {
969 //download
970 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",
971 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
972 safe_run(str);
973
974 //upload
975 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",
976 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
977 safe_run(str);
978 }
979
980 if(group_count++ < max_nesting)
981 {
982 parent = group->id;
983 }
984
985 rate -= digital_divide*group->min;
986 if(rate < group->min)
987 {
988 rate = group->min;
989 }
990
991 /*shaping of aggresive downloaders, with credit file support */
992 if(use_credit)
993 {
994 int group_rate = group->min, priority_sequence = lowest_priority;
995
996 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
997 {
998 if( ip->keyword->data_limit && !ip->fixedprio
999 && ( ip->traffic>ip->credit
1000 + (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))) )
1001 {
1002 if(group_rate<ip->max)
1003 {
1004 ip->max=group_rate;
1005 }
1006 group_rate+=magic_treshold;
1007 ip->prio=lowest_priority;
1008 if(ip->prio<highest_priority+2)
1009 {
1010 ip->prio=highest_priority+2;
1011 }
1012 }
1013 else
1014 {
1015 if( ip->keyword->data_prio
1016 && !ip->fixedprio
1017 && ( ip->traffic>ip->credit
1018 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1019 {
1020 ip->prio=priority_sequence--;
1021 if(ip->prio<highest_priority+1)
1022 {
1023 ip->prio=highest_priority+1;
1024 }
1025 }
1026
1027 if(credit_file)
1028 {
1029 unsigned long long lcredit=0;
1030
1031 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1032 {
1033 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1034 }
1035 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1036 }
1037 }
1038 }
1039 }
1040 }
1041 if(credit_file)
1042 {
1043 fclose(credit_file);
1044 }
1045 }
1046
1047 if(just_preview)
1048 {
1049 if(start_shaping)
1050 {
1051 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap);
1052 parse(classmap)
1053 {
1054 ptr=strchr(_,' ');
1055 if(ptr)
1056 {
1057 *ptr=0;
1058 ptr++;
1059 if_exists(ip,ips,eq(ip->addr,_))
1060 {
1061 ip->mark=atoi(ptr);
1062 if(ip->max < ip->desired) /* apply FUP limit immediately.... */
1063 {
1064 printf("Applying limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1065 printf("(down: %dk-%dk ", ip->min, ip->max);
1066 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1067 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1068 safe_run(str);
1069 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1070 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1071 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1072 tc, wan, ip->group, ip->mark,
1073 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1074 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1075 safe_run(str);
1076 }
1077 }
1078 }
1079 }
1080 fail
1081 {
1082 perror(classmap);
1083 puts("Warning - classmap file not fund, just generating preview ...");
1084 start_shaping=FALSE;
1085 }
1086 done; /* ugly macro end */
1087 }
1088 html=preview;
1089 json=json_preview;
1090 }
1091
1092 if(!dry_run && !just_flush)
1093 {
1094 /*-----------------------------------------------------------------*/
1095 printf("Writing json overview %s ... ", json);
1096 /*-----------------------------------------------------------------*/
1097 f=fopen(json, "w");
1098 if(f > 0)
1099 {
1100 int jsoncount=0;
1101 fprintf(f, "{\n");
1102 for_each(ip, ips)
1103 {
1104 if( ip->lmsid > 0
1105 && (ip->traffic || ip->direct || ip->proxy || ip->upload))
1106 {
1107 if(jsoncount)
1108 {
1109 fprintf(f, ",\n");
1110 }
1111 fprintf(f, " \"%s\":{ \"lms\": %d, \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu, \"min\":%d, \"max\":%d, \"limit\":%d }",
1112 ip->name, ip->lmsid, ip->addr, ip->traffic, ip->direct, ip->proxy, ip->upload, ip->min, ip->desired, ip->max);
1113 jsoncount++;
1114 }
1115 }
1116 fprintf(f, "}\n");
1117 fclose(f);
1118 puts("done.");
1119 }
1120 else
1121 {
1122 perror(json);
1123 }
1124 }
1125
1126 f=fopen(html,"w");
1127 if(f > 0)
1128 {
1129 int count=1;
1130 i=0;
1131
1132 /*-----------------------------------------------------------------*/
1133 printf("Sorting data and generating statistics page %s ...\n", html);
1134 /*-----------------------------------------------------------------*/
1135
1136 if(use_jquery_popups)
1137 {
1138 fprintf(f,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url);
1139 }
1140 fputs("<table class=\"decorated last\">\n\
1141 <caption>Bandwidth classes</caption>\n\
1142 <thead><tr>\n\
1143 <th style=\"text-align: right\">#</th>\n\
1144 <th style=\"text-align: right\">group</th>\n\
1145 <th style=\"text-align: right\">IPs</th>\n\
1146 <th style=\"text-align: right\">requested</th>\n",f);
1147 fprintf(f,"<th colspan=\"%d\">data limits</th>\n", keywordcount);
1148 fputs("</tr></thead><tbody>\n",f);
1149
1150 row_odd_even = 0;
1151 for_each(group, groups)
1152 {
1153 #ifdef DEBUG
1154 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group->min,group->count,group->desired);
1155 #endif
1156 fprintf(f, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1157 tr_odd_even(), count, group->min);
1158 fprintf(f, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1159 group->count, group->desired);
1160
1161 for_each(keyword, keywords) if(keyword->ip_count)
1162 {
1163 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d&nbsp;MB</span></td>",
1164 keyword->html_color, group->min*keyword->data_limit);
1165 }
1166 i += group->desired;
1167 total += group->count;
1168 count++;
1169 }
1170 #ifdef DEBUG
1171 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1172 count, i, i/line);
1173 #endif
1174 fprintf(f,"</tr></tbody>\n\
1175 <thead><tr>\n\
1176 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line);
1177 fprintf(f,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total,i);
1178
1179 for_each(keyword, keywords) if(keyword->ip_count)
1180 {
1181 fprintf(f,"<th style=\"text-align: right\">%d IPs</th>",keyword->ip_count);
1182 }
1183 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i/line));
1184 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount, total);
1185
1186 fputs("</thead></table>\n",f);
1187 }
1188 else if(!dry_run && !just_flush)
1189 {
1190 perror(html);
1191 }
1192
1193 i=0;
1194 if(f > 0)
1195 {
1196 unsigned long long total_traffic=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1197 int active_classes=0;
1198 int colspan=12;
1199 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1200 int limit_count=0, prio_count=0;
1201 int popup_button=0;
1202
1203 if(qos_proxy)
1204 {
1205 colspan++;
1206 }
1207
1208 fprintf(f,"<p><table class=\"decorated last\">\n<caption>%s",title);
1209 fprintf(f," (%s)</caption>\n", d);
1210 fputs("<thead><tr>\n<th colspan=\"3\">&nbsp;</th>\n",f);
1211 fputs("<th style=\"text-align: right\">credit</th>\n\
1212 <th style=\"text-align: right\">FUP</th>\n\
1213 <th style=\"text-align: right\">total</th>\n\
1214 <th style=\"text-align: right\">down</th>\n",f);
1215 if(qos_proxy)
1216 {
1217 fputs("<th style=\"text-align: right\">proxy</th>\n",f);
1218 }
1219 fputs("<th style=\"text-align: right\">up</th>\n\
1220 <th style=\"text-align: right\">min</th>\n\
1221 <th style=\"text-align: right\">max</th>\n\
1222 <th style=\"text-align: right\">limit</th>\n\
1223 <th>&nbsp;</th>\n\
1224 </tr><tr>\n\
1225 <th style=\"text-align: right\">#</th>\n\
1226 <th>hostname [+sharing]</th>\n\
1227 <th style=\"text-align: right\">LMS</th>\n\
1228 <th style=\"text-align: right\">MB</th>\n\
1229 <th style=\"text-align: right\">MB</th>\n\
1230 <th style=\"text-align: right\">MB</th>\n\
1231 <th style=\"text-align: right\">MB</th>\n\
1232 <th style=\"text-align: right\">MB</th>\n\
1233 <th style=\"text-align: right\">kb/s</th>\n\
1234 <th style=\"text-align: right\">kb/s</th>\n\
1235 <th style=\"text-align: right\">kb/s</th>\n\
1236 <th>prio</th>\n\
1237 </tr></thead><tbody>\n",f);
1238
1239 row_odd_even = 0;
1240 for_each(ip,ips) if(!use_jquery_popups || !ip->sharing)
1241 {
1242 char *f1="", *f2="";
1243 i++;
1244
1245 if(ip->max < ip->desired)
1246 {
1247 f1="<span style=\"color:red\">";
1248 f2="</span>";
1249 limit_count++;
1250 }
1251 else if(ip->prio > highest_priority+1)
1252 {
1253 f1="<span style=\"color:brown\">";
1254 f2="</span>";
1255 prio_count++;
1256 }
1257
1258 #ifdef DEBUG
1259 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1260 #endif
1261 /* hostnames -------------------------------------- */
1262 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",
1263 tr_odd_even(), ip->name, i, log_url, ip->name, ip->name);
1264
1265 if(use_jquery_popups)
1266 {
1267 fprintf(f,"<span id=\"sharing_%d\" style=\"display:none\">",i);
1268 popup_button=0;
1269 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1270 {
1271 fprintf(f,"<br /><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n", log_url, sharedip->name, sharedip->name);
1272 popup_button++;
1273 }
1274 fputs("</span>\n",f);
1275 if(popup_button)
1276 {
1277 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>",
1278 i, i, i, popup_button);
1279 }
1280 }
1281 fputs("</td>\n",f);
1282 /* ----------------------------------------------- */
1283
1284 if(found_lmsid)
1285 {
1286 fputs("<td style=\"text-align: right\">",f);
1287 if(ip->lmsid > 0)
1288 {
1289 fprintf(f,"<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url, ip->lmsid, ip->lmsid);
1290 }
1291 else if(ip->lmsid == 0)
1292 {
1293 fputs("-------",f);
1294 }
1295 fputs("</td>\n",f);
1296 }
1297 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->credit);
1298 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1299 ip->keyword->html_color,
1300 ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1301 fprintf(f,"<td style=\"text-align: right\">%s%Lu%s", f1, ip->traffic, f2);
1302
1303 /* download --------------------------------------- */
1304 fprintf(f,"</td><td style=\"text-align: right\">%Lu", ip->direct);
1305 if(use_jquery_popups)
1306 {
1307 fprintf(f,"<span id=\"download_%d\" style=\"display:none\">",i);
1308 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1309 {
1310 fprintf(f,"<br />%Lu", sharedip->direct);
1311 }
1312 fputs("</span>\n",f);
1313 }
1314 fputs("</td>\n",f);
1315 /* ----------------------------------------------- */
1316
1317 if(qos_proxy)
1318 {
1319 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->proxy);
1320 }
1321 /* upload ---------------------------------------- */
1322 fprintf(f,"<td style=\"text-align: right\">%Lu", ip->upload);
1323 if(use_jquery_popups)
1324 {
1325 fprintf(f,"<span id=\"upload_%d\" style=\"display:none\">",i);
1326 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))
1327 {
1328 fprintf(f,"<br />%Lu", sharedip->upload);
1329 }
1330 fputs("</span>\n",f);
1331 }
1332 fputs("</td>\n",f);
1333 /* ----------------------------------------------- */
1334
1335 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1336 <td style=\"text-align: right\">%d</td>\n\
1337 <td style=\"text-align: right\">%s%d%s</td>\n\
1338 <td>%s%d%s</td></tr>\n",
1339 ip->min, ip->desired,
1340 f1, ip->max, f2,
1341 f1, ip->prio, f2);
1342
1343 total_traffic+=ip->traffic;
1344 total_direct+=ip->direct;
1345 total_proxy+=ip->proxy;
1346 total_upload+=ip->upload;
1347 if(ip->traffic>0)
1348 {
1349 active_classes++;
1350 tmp_sum+=ip->traffic;
1351 create(sum,Sum);
1352 sum->l=tmp_sum;
1353 sum->i=active_classes;
1354 insert(sum,sums,order_by,i);
1355 }
1356
1357 if(!just_preview)
1358 {
1359 append_log(ip);
1360 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))
1361 {
1362 append_log(sharedip);
1363 }
1364 }
1365 }
1366 fprintf(f,"</tbody><thead><tr>\n\
1367 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan-7, i);
1368 fprintf(f,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic, total_direct);
1369 if(qos_proxy)
1370 {
1371 fprintf(f,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy);
1372 }
1373 fprintf(f,"<th style=\"text-align: right\">%Lu</th>", total_upload);
1374 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);
1375
1376 row_odd_even = 0;
1377 if(active_classes>10)
1378 {
1379 int top20_count=0,top20_perc1=0;
1380 long long top20_perc2=0;
1381 unsigned long long top20_sum=0l;
1382
1383 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f);
1384 fputs("<thead><tr>\n\
1385 <th>Analytic category</th>\n\
1386 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1387 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1388 </tr></thead><tbody>\n",f);
1389
1390 if_exists(sum,sums,sum->l>=total_traffic/4)
1391 {
1392 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1393 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1394 <td style=\"text-align: right\">%d %%</td>\n\
1395 <td style=\"text-align: right\">%Lu MB</td>\n\
1396 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1397 sum->i, (100*sum->i+50)/active_classes, sum->l, (100*sum->l+50)/total_traffic);
1398 }
1399
1400 if_exists(sum,sums,sum->i==10)
1401 {
1402 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1403 fprintf(f,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1404 <td style=\"text-align: right\">%d %%</td>\n\
1405 <td style=\"text-align: right\">%Lu MB</td>\n\
1406 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1407 (100*sum->i+50)/active_classes, sum->l, (100*sum->l+50)/total_traffic);
1408 }
1409
1410 if_exists(sum,sums,sum->l>=total_traffic/2)
1411 {
1412 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1413 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1414 <td style=\"text-align: right\">%d %%</td>\n\
1415 <td style=\"text-align: right\">%Lu MB</td>\n\
1416 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1417 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1418 }
1419
1420 if_exists(sum,sums,sum->l>=4*total_traffic/5)
1421 {
1422 fprintf(f,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1423 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1424 <td style=\"text-align: right\">%d %%</td>\n\
1425 <td style=\"text-align: right\">%Lu MB</td>\n\
1426 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1427 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1428 }
1429
1430 if_exists(sum,sums,sum->i>=(active_classes+1)/5)
1431 {
1432 fprintf(f,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1433 top20_count=sum->i;
1434 top20_perc1=(100*sum->i+50)/active_classes;
1435 top20_sum=sum->l;
1436 top20_perc2=(100*sum->l+50)/total_traffic;
1437 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1438 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1439 <td style=\"text-align: right\">%Lu MB</td>\n\
1440 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1441 top20_count,top20_perc1,top20_sum,top20_perc2);
1442 }
1443
1444 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1445 {
1446 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1447 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1448 <td style=\"text-align: right\">%d %%</td>\n\
1449 <td style=\"text-align: right\">%Lu MB</td>\n\
1450 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1451 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1452 }
1453
1454 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1455 {
1456 fprintf(f,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1457 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1458 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1459 <td style=\"text-align: right\">%Lu MB</td>\n\
1460 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1461 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1462 }
1463
1464 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1465 {
1466 fprintf(f,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1467 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1468 <td style=\"text-align: right\">%d %%</td>\n\
1469 <td style=\"text-align: right\">%Lu MB</td>\n\
1470 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
1471 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1472 }
1473
1474 fprintf(f,"<thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url);
1475 fprintf(f,"<th style=\"text-align: right\">%d</th>\n\
1476 <th style=\"text-align: right\">100 %%</th>\n\
1477 <th style=\"text-align: right\">%Lu MB</th>\n\
1478 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes,total_traffic);
1479 fputs("</thead></table>\n", f);
1480
1481 /* write basic ERP data to log directory */
1482 if(!just_preview)
1483 {
1484 FILE *iplog;
1485 sprintf(str,"%s/ERP.log",log_dir);
1486 iplog=fopen(str,"a");
1487 if(iplog)
1488 {
1489 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",
1490 time(NULL), top20_count, top20_perc1, top20_sum, top20_perc2,
1491 active_classes, total_traffic, i, limit_count, prio_count, d); /* d = date*/
1492 fclose(iplog);
1493 }
1494 else
1495 {
1496 perror(str);
1497 }
1498 }
1499 }
1500
1501 fprintf(f, stats_html_signature, version);
1502 fclose(f);
1503 }
1504
1505 if(just_preview)
1506 {
1507 char swchar='p';
1508 if(start_shaping)
1509 {
1510 swchar='s';
1511 }
1512 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);
1513 exit(0);
1514 }
1515
1516 i=0;
1517 #ifdef DEBUG
1518 printf("%-22s %-15s mark\n","name","ip");
1519 #endif
1520
1521 printf("Writing %s ... ", classmap);
1522 f = fopen(classmap, "w");
1523 if(f < 0)
1524 {
1525 perror(classmap);
1526 }
1527
1528 /*-----------------------------------------------------------------*/
1529 puts("Generating iptables and tc classes ... ");
1530 /*-----------------------------------------------------------------*/
1531
1532 for_each(ip, ips) if(ip->mark > 0)
1533 {
1534 if(idxs)
1535 {
1536 char *buf;
1537 duplicate(ip->addr,buf);
1538 buf=index_id(ip->addr,32-idxtable_bitmask1);
1539
1540 string(chain_forward,6+strlen(buf));
1541 strcpy(chain_forward,"forw_");
1542 strcat(chain_forward,buf);
1543
1544 string(chain_postrouting,6+strlen(buf));
1545 strcpy(chain_postrouting,"post_");
1546 strcat(chain_postrouting,buf);
1547
1548 free(buf);
1549 }
1550 else
1551 {
1552 chain_forward="FORWARD";
1553 chain_postrouting="POSTROUTING";
1554 }
1555
1556 #ifdef DEBUG
1557 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1558 #endif
1559
1560 /* -------------------------------------------------------- mark download */
1561
1562 sprintf(str, "-A %s -d %s/32 -o %s -j %s%d",
1563 chain_postrouting, ip->addr, lan, mark_iptables, ip->mark);
1564 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1565 /* -m limit --limit 1/s */
1566 save_line(str);
1567
1568 if(qos_proxy)
1569 {
1570 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
1571 chain_postrouting, proxy_ip, proxy_port, ip->addr, lan, mark_iptables, ip->mark);
1572 /*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);*/
1573 save_line(str);
1574 }
1575
1576 sprintf(str, "-A %s -d %s/32 -o %s -j ACCEPT",
1577 chain_postrouting, ip->addr, lan);
1578 save_line(str);
1579
1580 /* -------------------------------------------------------- mark upload */
1581 sprintf(str, "-A %s -s %s/32 -o %s -j %s%d",
1582 chain_forward, ip->addr, wan, mark_iptables, ip->mark);
1583 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1584 save_line(str);
1585
1586 sprintf(str, "-A %s -s %s/32 -o %s -j ACCEPT",
1587 chain_forward, ip->addr, wan);
1588 save_line(str);
1589
1590 if(ip->min)
1591 {
1592 /* -------------------------------------------------------- download class */
1593 #ifdef DEBUG
1594 printf("(down: %dk-%dk ", ip->min, ip->max);
1595 #endif
1596
1597 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1598 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1599 safe_run(str);
1600
1601 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1602 {
1603 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1604 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1605 safe_run(str);
1606 }
1607
1608 if(filter_type == 1)
1609 {
1610 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1611 tc, lan, ip->mark, ip->mark);
1612 safe_run(str);
1613 }
1614
1615 /* -------------------------------------------------------- upload class */
1616 #ifdef DEBUG
1617 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1618 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1619 #endif
1620
1621 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1622 tc, wan, ip->group, ip->mark,
1623 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1624 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1625 safe_run(str);
1626
1627 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1628 {
1629 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1630 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1631 safe_run(str);
1632 }
1633
1634 if(filter_type == 1)
1635 {
1636 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1637 tc, wan, ip->mark, ip->mark);
1638 safe_run(str);
1639 }
1640
1641 if(f > 0)
1642 {
1643 fprintf(f, "%s %d\n", ip->addr, ip->mark);
1644 }
1645 }
1646 else
1647 {
1648 #ifdef DEBUG
1649 printf("(sharing %s)\n", ip->sharing);
1650 #endif
1651 }
1652 i++;
1653 }
1654 if(f > 0)
1655 {
1656 puts("done.");
1657 fclose(f);
1658 }
1659
1660 if(idxs)
1661 {
1662 chain_forward = "forw_common";
1663 chain_postrouting = "post_common";
1664 }
1665 else
1666 {
1667 chain_forward = "FORWARD";
1668 chain_postrouting = "POSTROUTING";
1669 }
1670 /* -------------------------------- classify or reject free download */
1671 {
1672 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
1673 if(free_min)
1674 {
1675 final_chain = "ACCEPT";
1676 }
1677 if(qos_proxy)
1678 {
1679 if(free_min)
1680 {
1681 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
1682 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
1683 save_line(str);
1684 }
1685 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
1686 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
1687 save_line(str);
1688 }
1689 if(free_min)
1690 {
1691 sprintf(str,"-A %s -o %s -j %s%d", chain_postrouting, lan, mark_iptables, 3);
1692 save_line(str);
1693 }
1694 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
1695 save_line(str);
1696 /* ------------------------------- classify or reject free upload */
1697 if(free_min)
1698 {
1699 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);
1700 save_line(str);
1701 }
1702 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);
1703 save_line(str);
1704 }
1705
1706 if(free_min) /* allocate free bandwith if it is not zero... */
1707 {
1708 /*-----------------------------------------------------------------*/
1709 puts("Generating free bandwith classes ...");
1710 /*-----------------------------------------------------------------*/
1711 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1712 tc, lan, parent, free_min, free_max,burst, lowest_priority);
1713 safe_run(str);
1714 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1715 tc, wan, parent, free_min, free_max, burst, lowest_priority);
1716 safe_run(str);
1717 /* tc SFQ */
1718 if(strcmpi(qos_leaf, "none"))
1719 {
1720 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);
1721 safe_run(str);
1722
1723 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);
1724 safe_run(str);
1725 }
1726 /* tc handle 1 fw flowid */
1727 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);
1728 safe_run(str);
1729
1730 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);
1731 safe_run(str);
1732 }
1733 printf("Total IP count: %d\n", i);
1734 run_restore();
1735 if(log_file)
1736 {
1737 fclose(log_file);
1738 }
1739 return 0;
1740 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1741 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1742 }
This page took 1.534695 seconds and 3 git commands to generate.