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