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