cleanup, code readability, etc.
[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 = "<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></small>\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 border=\"1\"><thead><tr class=\"bgGrey\"><th colspan=\"2\">%s %s</th><th align=\"right\">lms</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr></thead><tbody>\n ",
903 month, year);
904
905 row_odd_even = 0;
906 for_each(iplog, iplogs)
907 {
908 if(iplog->traffic)
909 {
910 fprintf(f, "%s<td align=\"right\">%d</td><td align=\"left\"><a href=\"%s%s.log\">%s</td></td><td align=\"right\">",
911 tr_odd_even(), i++, log_url, iplog->name, iplog->name);
912 if(iplog->lmsid > 0)
913 {
914 /*base URL will be configurable soon ... */
915 fprintf(f, "<a href=\"%s%d\">%04d</a>\n", lms_url, iplog->lmsid, iplog->lmsid);
916 }
917 else if(iplog->lmsid == 0)
918 {
919 fputs("-------",f);
920 }
921 fprintf(f, "<td align=\"right\">%ld&nbsp;M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
922 iplog->traffic, iplog->traffic>>10, iplog->guaranted);
923 total+=iplog->traffic>>10;
924 iplog->i=i;
925 iplog->l=total;
926 }
927 }
928 fprintf(f,"<tr class=\"bgGrey\"><th colspan=\"4\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total, line);
929 fputs("</tbody></table>\n", f);
930
931 row_odd_even = 0;
932 if(i>10)
933 {
934 fputs("<a name=\"erp\"></a><p><table border=\"0\"><thead><caption>Enterprise Resource Planning (ERP)</caption></tr>\n",f);
935 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f);
936 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n</thead><tbody>\n",f);
937
938 if_exists(iplog,iplogs,iplog->l>=total/4)
939 {
940 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
941 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
942 }
943
944 if_exists(iplog,iplogs,iplog->i==10)
945 {
946 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
947 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
948 }
949
950 if_exists(iplog,iplogs,iplog->l>=total/2)
951 {
952 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
953 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
954 }
955
956 if_exists(iplog,iplogs,iplog->l>=4*total/5)
957 {
958 fprintf(f,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
959 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
960 }
961
962 if_exists (iplog,iplogs,iplog->i>=i/5)
963 {
964 fprintf(f,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
965 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
966 }
967
968 if_exists(iplog,iplogs,iplog->i>=i/4)
969 {
970 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
971 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
972 }
973
974 if_exists(iplog,iplogs,iplog->i>=i/2)
975 {
976 fprintf(f,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
977 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
978 }
979
980 if_exists(iplog,iplogs,iplog->i>=4*i/5)
981 {
982 fprintf(f,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
983 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));
984 }
985
986 fprintf(f,"<tr class=\"bgGrey\"><td>All users, all traffic</td>\n");
987 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%ld G</th><th align=\"right\">100 %%</th></tr>\n",i-1,total);
988 fputs("</tbody></table>\n", f);
989 }
990
991 fprintf(f, stats_html_signature, version);
992 fclose(f);
993 puts(" done.");
994 }
995 }
996
997 /*-----------------------------------------------------------------*/
998 /* Are you looking for int main(int argc, char **argv) ? :-)) */
999 /*-----------------------------------------------------------------*/
1000
1001 program
1002 {
1003 int i=0;
1004 FILE *f=NULL;
1005 char *str, *ptr, *d;
1006 char *substring;
1007 int class_count=0,ip_count=0;
1008 int parent=1;
1009 int just_flush=FALSE;
1010 int nodelay=FALSE;
1011 int just_preview=FALSE; /* preview - generate just stats */
1012 int just_logs=FALSE; /* just parse logs */
1013 int run=FALSE;
1014 int total=0;
1015
1016 char *chain_forward, *chain_postrouting;
1017 char *althosts=NULL;
1018
1019 printf("\n\
1020 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1021 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1022 iptables-restore & burst tunning & classify modification by Ludva\n\
1023 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
1024
1025 /*----- Boring... we have to check command line options first: ----*/
1026
1027 arguments
1028 {
1029 argument("-c") { nextargument(config); }
1030 argument("-h") { nextargument(althosts);}
1031 argument("-d") { run=TRUE; dry_run=TRUE; }
1032 argument("-f") { run=TRUE; just_flush=TRUE; }
1033 argument("-9") { run=TRUE; just_flush=9; }
1034 argument("-p") { run=TRUE; just_preview=TRUE; }
1035 argument("-r") { run=TRUE; }
1036 argument("-n") { run=TRUE; nodelay=TRUE; }
1037 argument("-l") { just_logs=TRUE; }
1038 argument("-m") { just_logs=TRUE; }
1039 argument("-y") { just_logs=TRUE; }
1040 argument("-?") { help(); exit(0); }
1041 argument("--help") { help(); exit(0); }
1042 argument("-v") { exit(0); }
1043 argument("--version") { exit(0); }
1044 }
1045
1046 if(dry_run)
1047 {
1048 puts("*** THIS IS JUST DRY RUN ! ***\n");
1049 }
1050
1051 date(d); /* this is typical cll1.h macro - prints current date */
1052
1053 /*-----------------------------------------------------------------*/
1054 printf("Parsing configuration file %s ...\n", config);
1055 /*-----------------------------------------------------------------*/
1056 get_config(config);
1057
1058 if(just_logs)
1059 {
1060 parse_ip_log(argc,argv);
1061 exit(0);
1062 }
1063 else if(not run)
1064 {
1065 help();
1066 exit(0);
1067 }
1068
1069 if(althosts)
1070 {
1071 hosts=althosts;
1072 }
1073
1074 if(just_flush<9)
1075 {
1076 /*-----------------------------------------------------------------*/
1077 puts("Parsing iptables verbose output ...");
1078 /*-----------------------------------------------------------------*/
1079 get_traffic_statistics();
1080 }
1081
1082 /*-----------------------------------------------------------------*/
1083 printf("Parsing class defintion file %s ...\n", hosts);
1084 /*-----------------------------------------------------------------*/
1085 int groupidx = FIRSTGROUPID;
1086 parse(hosts)
1087 {
1088 str=_;
1089
1090 if(*str<'0' || *str>'9')
1091 {
1092 /* any line starting with non-number is comment ...*/
1093 continue;
1094 }
1095
1096 //Does this IP share QoS class with some other ?
1097 substring=strstr(str,"sharing-");
1098 if(substring)
1099 {
1100 substring+=8; //"sharing-"
1101 parse_ip(str);
1102 ip_count++;
1103 ip->sharing=substring;
1104 ip->keyword=defaultkeyword; /* settings for default keyword */
1105 while(*substring && *substring!='\n')
1106 {
1107 substring++;
1108 }
1109 *substring=0;
1110 }
1111 else
1112 {
1113 //Do we have to create new QoS class for this IP ?
1114
1115 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))
1116 {
1117 parse_ip(str);
1118 ip_count++;
1119 ip->keyword=keyword;
1120 keyword->ip_count++;
1121 ip->prio=keyword->default_prio;
1122 substring+=strlen(keyword->key)+1;
1123 ptr=substring;
1124 while(*ptr && *ptr!='-')
1125 {
1126 ptr++;
1127 }
1128 if(*ptr=='-')
1129 {
1130 *ptr=0;
1131 ip->max = ip->desired=atoi(ptr+1);
1132 }
1133 ip->min = atoi(substring);
1134 if(ip->min <= 0)
1135 {
1136 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",
1137 str, free_min);
1138 ip->min = free_min;
1139 }
1140 if(ip->max <= ip->min)
1141 {
1142 ip->fixedprio = 1;
1143 ip->max = ip->min+ip->keyword->reserve_min;
1144 }
1145 else
1146 {
1147 ip->max -= ip->keyword->reserve_max;
1148 if(ip->max<ip->min)
1149 {
1150 ip->max=ip->min;
1151 }
1152 }
1153 ip->mark=FIRSTIPCLASS+1+class_count++;
1154
1155 if_exists(group,groups,group->min==ip->min)
1156 {
1157 group->count++;
1158 group->desired += ip->min;
1159 ip->group = group->id;
1160 }
1161 else
1162 {
1163 create(group,Group);
1164 group->min = ip->min;
1165 group->id = groupidx++;
1166 ip->group = group->id;
1167
1168 if(group->min<8) group->min=8;
1169 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1170 /* it is because class IDs are derived from min. bandwidth. - xCh */
1171 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1172
1173 group->count=1;
1174 group->desired=ip->min;
1175 insert(group,groups,desc_order_by,min);
1176 }
1177 }//endif keyword-
1178 }//endif sharing-
1179 }
1180 fail
1181 {
1182 perror(hosts);
1183 exit(-1);
1184 }
1185 done;
1186
1187 /*-----------------------------------------------------------------*/
1188 /* cll1.h - let's allocate brand new character buffer... */
1189 /*-----------------------------------------------------------------*/
1190 string(str,STRLEN);
1191
1192 /*-----------------------------------------------------------------*/
1193 puts("Resolving shared connections ...");
1194 /*-----------------------------------------------------------------*/
1195 for_each(ip,ips) if(ip->sharing)
1196 {
1197 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))
1198 {
1199 sharedip->traffic+=ip->traffic;
1200 ip->traffic=0;
1201 ip->mark=sharedip->mark;
1202 ip->lmsid=sharedip->lmsid;
1203 break;
1204 }
1205 if(!sharedip)
1206 {
1207 printf("Unresolved shared connection: %s %s sharing-%s\n",
1208 ip->addr, ip->name, ip->sharing);
1209 }
1210 }
1211
1212 if(enable_credit && just_flush<9)
1213 {
1214 /*-----------------------------------------------------------------*/
1215 printf("Parsing credit file %s ...\n", credit);
1216 /*-----------------------------------------------------------------*/
1217 parse(credit)
1218 {
1219 ptr=parse_datafile_line(_);
1220 if(ptr)
1221 {
1222 if_exists(ip,ips,eq(ip->addr,_))
1223 {
1224 sscanf(ptr,"%Lu",&(ip->credit));
1225 }
1226 }
1227 }
1228 done;
1229 }
1230
1231 if(!just_preview)
1232 {
1233 /*-----------------------------------------------------------------*/
1234 puts("Initializing iptables and tc classes ...");
1235 /*-----------------------------------------------------------------*/
1236
1237 iptables_file=fopen(iptablesfile,"w");
1238 if(iptables_file == NULL)
1239 {
1240 puts("Cannot open iptablesfile!");
1241 exit(-1);
1242 }
1243
1244 log_file=fopen(cmdlog,"w");
1245 if(log_file == NULL)
1246 {
1247 puts("Cannot open logfile!");
1248 exit(-1);
1249 }
1250
1251 save_line(iptablespreamble);
1252 run_restore();
1253
1254 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
1255 safe_run(str);
1256
1257 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
1258 safe_run(str);
1259
1260 iptables_file=fopen(iptablesfile,"w");
1261 save_line(iptablespreamble);
1262
1263 if(qos_free_zone && *qos_free_zone!='0')
1264 {
1265 char *chain;
1266
1267 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
1268 save_line(str);
1269
1270 if(qos_proxy)
1271 {
1272 save_line(":post_noproxy - [0:0]");
1273 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
1274 save_line(str);
1275 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
1276 save_line(str);
1277 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
1278 save_line(str);
1279
1280 chain="post_noproxy";
1281 }
1282 else
1283 {
1284 chain="POSTROUTING";
1285 }
1286
1287 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1288 save_line(str);
1289 }
1290
1291 if(ip_count>idxtable_treshold1 && !just_flush)
1292 {
1293 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1294 char *subnet, *buf;
1295 /*-----------------------------------------------------------------*/
1296 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1297 /*-----------------------------------------------------------------*/
1298
1299 save_line(":post_common - [0:0]");
1300 save_line(":forw_common - [0:0]");
1301
1302 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1303 {
1304 buf=hash_id(ip->addr,bitmask);
1305 if_exists(idx,idxs,eq(idx->id,buf))
1306 {
1307 idx->children++;
1308 }
1309 else
1310 {
1311 create(idx,Index);
1312 idx->addr=ip->addr;
1313 idx->id=buf;
1314 idx->bitmask=bitmask;
1315 idx->parent=NULL;
1316 idx->children=0;
1317 idxcount++;
1318 push(idx,idxs);
1319 }
1320 }
1321
1322 /* brutal perfomance optimalization */
1323 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1324 {
1325 bitmask-=idxtable_bitmask2;
1326 idxcount=0;
1327
1328 for_each(idx,idxs) if(idx->parent == NULL)
1329 {
1330 buf=hash_id(idx->addr,bitmask);
1331 if_exists(metaindex,idxs,eq(metaindex->id,buf))
1332 {
1333 metaindex->children++;
1334 }
1335 else
1336 {
1337 create(metaindex,Index);
1338 metaindex->addr=idx->addr;
1339 metaindex->id=buf;
1340 metaindex->bitmask=bitmask;
1341 metaindex->parent=NULL;
1342 metaindex->children=0;
1343 idxcount++;
1344 push(metaindex,idxs);
1345 }
1346 idx->parent=metaindex;
1347 }
1348 }
1349
1350 /* this should slightly optimize throughout ... */
1351 sort(idx,idxs,desc_order_by,children);
1352 sort(idx,idxs,order_by,bitmask);
1353
1354 i=0;
1355 for_each(idx,idxs)
1356 {
1357 subnet=subnet_id(idx->addr,idx->bitmask);
1358 printf("%d: %s/%d\n",
1359 ++i, subnet, idx->bitmask);
1360
1361 sprintf(str,":post_%s - [0:0]", idx->id);
1362 save_line(str);
1363
1364 sprintf(str,":forw_%s - [0:0]", idx->id);
1365 save_line(str);
1366
1367 if(idx->parent)
1368 {
1369 string(buf,strlen(idx->parent->id)+6);
1370 sprintf(buf,"post_%s",idx->parent->id);
1371 }
1372 else
1373 {
1374 buf="POSTROUTING";
1375 }
1376
1377 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1378 save_line(str);
1379
1380 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1381 save_line(str);
1382
1383 if(idx->parent)
1384 {
1385 string(buf,strlen(idx->parent->id)+6);
1386 sprintf(buf,"forw_%s",idx->parent->id);
1387 }
1388 else
1389 {
1390 buf="FORWARD";
1391 }
1392
1393 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1394 save_line(str);
1395
1396 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1397 save_line(str);
1398 }
1399 printf("Total indexed iptables chains created: %d\n", i);
1400
1401 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1402 save_line(str);
1403
1404 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1405 save_line(str);
1406 }
1407
1408 }
1409
1410 if(just_flush)
1411 {
1412 fclose(iptables_file);
1413 if(log_file) fclose(log_file);
1414 puts("Just flushed iptables and tc classes - now exiting ...");
1415 exit(0);
1416 }
1417
1418 if(!just_preview)
1419 {
1420 if(!dry_run && !nodelay && qos_free_delay)
1421 {
1422 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1423 sleep(qos_free_delay);
1424 }
1425
1426 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1427 tc,lan,htb_r2q);
1428 safe_run(str);
1429
1430 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1431 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
1432 safe_run(str);
1433
1434 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1435 tc,lan,line,line,burst_main,highest_priority);
1436 safe_run(str);
1437
1438 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1439 safe_run(str);
1440
1441 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1442 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
1443 safe_run(str);
1444
1445 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1446 tc,wan,up,up,burst_main,highest_priority);
1447 safe_run(str);
1448 }
1449
1450 /*-----------------------------------------------------------------*/
1451 puts("Locating heavy downloaders and generating root classes ...");
1452 /*-----------------------------------------------------------------*/
1453 sort(ip,ips,desc_order_by,traffic);
1454
1455 /*-----------------------------------------------------------------*/
1456 /* sub-scope - local variables */
1457 {
1458 long long int rate = line;
1459 long long int max = line;
1460 int group_count = 0;
1461 FILE *credit_file = NULL;
1462
1463 if(!just_preview && !dry_run && enable_credit)
1464 {
1465 credit_file = fopen(credit,"w");
1466 }
1467
1468 for_each(group,groups)
1469 {
1470 if(!just_preview)
1471 {
1472 //download
1473 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",
1474 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
1475 safe_run(str);
1476
1477 //upload
1478 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",
1479 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
1480 safe_run(str);
1481 }
1482
1483 if(group_count++ < max_nesting)
1484 {
1485 parent = group->id;
1486 }
1487
1488 rate -= digital_divide*group->min;
1489 if(rate < group->min)
1490 {
1491 rate = group->min;
1492 }
1493
1494 /*shaping of aggresive downloaders, with credit file support */
1495 if(use_credit)
1496 {
1497 int group_rate = group->min, priority_sequence = lowest_priority;
1498
1499 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
1500 {
1501 if( ip->keyword->data_limit && !ip->fixedprio
1502 && ( ip->traffic>ip->credit
1503 + (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))) )
1504 {
1505 if(group_rate<ip->max)
1506 {
1507 ip->max=group_rate;
1508 }
1509 group_rate+=magic_treshold;
1510 ip->prio=lowest_priority;
1511 if(ip->prio<highest_priority+2)
1512 {
1513 ip->prio=highest_priority+2;
1514 }
1515 }
1516 else
1517 {
1518 if( ip->keyword->data_prio
1519 && !ip->fixedprio
1520 && ( ip->traffic>ip->credit
1521 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1522 {
1523 ip->prio=priority_sequence--;
1524 if(ip->prio<highest_priority+1)
1525 {
1526 ip->prio=highest_priority+1;
1527 }
1528 }
1529
1530 if(credit_file)
1531 {
1532 unsigned long long lcredit=0;
1533
1534 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1535 {
1536 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1537 }
1538 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1539 }
1540 }
1541 }
1542 }
1543 }
1544 if(credit_file)
1545 {
1546 fclose(credit_file);
1547 }
1548 }
1549
1550 if(just_preview)
1551 {
1552 f=fopen(preview,"w");
1553 ptr=preview;
1554 }
1555 else if(!dry_run && !just_flush)
1556 {
1557 /*-----------------------------------------------------------------*/
1558 printf("Writing data transfer database ...\n");
1559 /*-----------------------------------------------------------------*/
1560 f=fopen("/var/run/prometheus.previous","w");
1561 if(f)
1562 {
1563 for_each(ip,ips)
1564 {
1565 if(ip->traffic || ip->direct || ip->proxy || ip->upload)
1566 {
1567 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",
1568 ip->addr, ip->traffic, ip->direct, ip->proxy, ip->upload);
1569 }
1570 }
1571 fclose(f);
1572 }
1573
1574 f=fopen(html,"w");
1575 ptr=html;
1576 }
1577
1578 if(f)
1579 {
1580 int count=1;
1581 i=0;
1582
1583 /*-----------------------------------------------------------------*/
1584 printf("Sorting data and generating statistics page %s ...\n", ptr);
1585 /*-----------------------------------------------------------------*/
1586
1587 if(use_jquery_popups)
1588 {
1589 fprintf(f,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url);
1590 }
1591 fputs("<table border=\"0\">\n<thead><tr class=\"bgGrey\"><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f);
1592 fprintf(f,"<th colspan=\"%d\">data limits</th>\n", keywordcount);
1593 fputs("</tr></thead><tbody>\n",f);
1594
1595 row_odd_even = 0;
1596 for_each(group, groups)
1597 {
1598 #ifdef DEBUG
1599 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);
1600 #endif
1601 fprintf(f, "%s<td align=\"right\">%d</td><td align=\"right\">%d&nbsp;k</td>",
1602 tr_odd_even(), count, group->min);
1603 fprintf(f, "<td align=\"right\">%d</td><td align=\"right\">%d&nbsp;k</td>",
1604 group->count, group->desired);
1605
1606 for_each(keyword, keywords)
1607 {
1608 fprintf(f,"<td align=\"right\"><span style=\"color:#%s\">%d&nbsp;M</span></td>",
1609 keyword->html_color, group->min*keyword->data_limit);
1610 }
1611 i += group->desired;
1612 total += group->count;
1613 count++;
1614 }
1615 #ifdef DEBUG
1616 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",
1617 count, i, i/line);
1618 #endif
1619 fprintf(f,"<tr class=\"bgGrey\"><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);
1620 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);
1621
1622 for_each(keyword, keywords)
1623 {
1624 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count);
1625 }
1626 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i/line));
1627 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount, total);
1628
1629 fputs("</tbody></table>\n",f);
1630 }
1631 else if(!dry_run && !just_flush)
1632 {
1633 perror(html);
1634 }
1635
1636 i=0;
1637 if(f)
1638 {
1639 unsigned long long total_traffic=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1640 int active_classes=0;
1641 int colspan=11;
1642 FILE *iplog;
1643 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1644 int limit_count=0, prio_count=0;
1645 int popup_button=0;
1646
1647 if(qos_proxy)
1648 {
1649 colspan++;
1650 }
1651 if(found_lmsid)
1652 {
1653 colspan++;
1654 }
1655
1656 fprintf(f,"<p><table border>\n<thead><caption>%s",title);
1657 fprintf(f," (%s)</caption>\n", d);
1658 fputs("<tr class=\"bgGrey\"><td align=\"right\">#</td><td>hostname</td>",f);
1659 if(found_lmsid)
1660 {
1661 fputs("<td align=\"right\">lms</td>\n",f);
1662 }
1663 fputs("<td align=\"right\">credit</td>\
1664 <td align=\"right\">limit</td>\
1665 <td align=\"right\">total</td>\
1666 <td align=\"right\">direct</td>\n",f);
1667 if(qos_proxy)
1668 {
1669 fputs("<td align=\"right\">proxy</td>\n",f);
1670 }
1671 fputs("<td align=\"right\">upload</td>\
1672 <td align=\"right\">minimum</td>\
1673 <td align=\"right\">desired</td>\
1674 <td align=\"right\">maximum</td>\
1675 <td>prio</td></tr>\n\
1676 </thead><tbody>\n",f);
1677
1678 row_odd_even = 0;
1679 for_each(ip,ips) if(!use_jquery_popups || !ip->sharing)
1680 {
1681 char *f1="", *f2="";
1682 i++;
1683
1684 if(ip->max < ip->desired)
1685 {
1686 f1="<span style=\"color:red\">";
1687 f2="</span>";
1688 limit_count++;
1689 }
1690 else if(ip->prio > highest_priority+1)
1691 {
1692 f1="<span style=\"color:brown\">";
1693 f2="</span>";
1694 prio_count++;
1695 }
1696
1697 #ifdef DEBUG
1698 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1699 #endif
1700 /* hostnames -------------------------------------- */
1701 fprintf(f,"%s<td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a>\n",
1702 tr_odd_even(), ip->name, i, log_url, ip->name, ip->name);
1703 if(use_jquery_popups)
1704 {
1705 fprintf(f,"<span id=\"sharing_%d\" style=\"display:none\">",i);
1706 popup_button=0;
1707 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1708 {
1709 fprintf(f,"<br /><a href=\"%s%s.log\">%s</a>\n", log_url, sharedip->name, sharedip->name);
1710 popup_button++;
1711 }
1712 fputs("</span>\n",f);
1713 if(popup_button)
1714 {
1715 fprintf(f,"<span>[<a href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1716 i, i, i, popup_button);
1717 }
1718 }
1719 fputs("</td>\n",f);
1720 /* ----------------------------------------------- */
1721
1722 if(found_lmsid)
1723 {
1724 fputs("<td align=\"right\">",f);
1725 if(ip->lmsid > 0)
1726 {
1727 /*base URL will be configurable soon ... */
1728 fprintf(f,"<a href=\"%s%d\">%04d</a>\n", lms_url, ip->lmsid, ip->lmsid);
1729 }
1730 else if(ip->lmsid == 0)
1731 {
1732 fputs("-------",f);
1733 }
1734 fputs("</td>\n",f);
1735 }
1736 fprintf(f,"<td align=\"right\">%Lu&nbsp;M</td>\n", ip->credit);
1737 fprintf(f,"<td align=\"right\"><span style=\"color:#%s\">%Lu&nbsp;M</span></td>",
1738 ip->keyword->html_color,
1739 ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1740 fprintf(f,"<td align=\"right\">%s%Lu&nbsp;M%s", f1, ip->traffic, f2);
1741
1742 /* download --------------------------------------- */
1743 fprintf(f,"</td><td align=\"right\">%Lu&nbsp;M", ip->direct);
1744 if(use_jquery_popups)
1745 {
1746 fprintf(f,"<span id=\"download_%d\" style=\"display:none\">",i);
1747 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1748 {
1749 fprintf(f,"<br />%Lu&nbsp;M", sharedip->direct);
1750 }
1751 fputs("</span>\n",f);
1752 }
1753 fputs("</td>\n",f);
1754 /* ----------------------------------------------- */
1755
1756 if(qos_proxy)
1757 {
1758 fprintf(f,"<td align=\"right\">%Lu&nbsp;M</td>\n", ip->proxy);
1759 }
1760 /* upload ---------------------------------------- */
1761 fprintf(f,"<td align=\"right\">%Lu&nbsp;M", ip->upload);
1762 if(use_jquery_popups)
1763 {
1764 fprintf(f,"<span id=\"upload_%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->upload);
1768 }
1769 fputs("</span>\n",f);
1770 }
1771 fputs("</td>\n",f);
1772 /* ----------------------------------------------- */
1773
1774 fprintf(f,"<td align=\"right\">%d&nbsp;k</td><td align=\"right\">%d&nbsp;k</td><td align=\"right\">%s%d&nbsp;k%s</td><td>%s%d%s</td></tr>\n",
1775 ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);
1776
1777 total_traffic+=ip->traffic;
1778 total_direct+=ip->direct;
1779 total_proxy+=ip->proxy;
1780 total_upload+=ip->upload;
1781 if(ip->traffic>0)
1782 {
1783 active_classes++;
1784 tmp_sum+=ip->traffic;
1785 create(sum,Sum);
1786 sum->l=tmp_sum;
1787 sum->i=active_classes;
1788 insert(sum,sums,order_by,i);
1789 }
1790
1791 if(!just_preview)
1792 {
1793 sprintf(str,"%s/%s.log",log_dir,ip->name);
1794 iplog=fopen(str,"a");
1795 if(iplog)
1796 {
1797 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1798 time(NULL), ip->name, ip->traffic, ip->direct, ip->proxy,
1799 ip->upload, ip->min, ip->max, ip->desired, ip->lmsid, d); /* d = date*/
1800 fclose(iplog);
1801 }
1802 }
1803 }
1804 fprintf(f,"<tr class=\"bgGrey\"><th colspan=\"%d\" align=\"left\">%d CLASSES</th>", colspan-7, i);
1805 fprintf(f,"<th align=\"right\">%Lu&nbsp;M</th><th align=\"right\">%Lu&nbsp;M</th>\n", total_traffic, total_direct);
1806 if(qos_proxy)
1807 {
1808 fprintf(f,"<th align=\"right\">%Lu&nbsp;M</th>\n", total_proxy);
1809 }
1810 fprintf(f,"<th align=\"right\">%Lu&nbsp;M</th>", total_upload);
1811 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);
1812
1813 row_odd_even = 0;
1814 if(active_classes>10)
1815 {
1816 int top20_count=0,top20_perc1=0;
1817 long long top20_perc2=0;
1818 unsigned long long top20_sum=0l;
1819
1820 fputs("<a name=\"erp\"></a><p><table border><thead><caption>Enterprise Resource Planning (ERP)</caption>\n",f);
1821 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f);
1822 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr></thead><tbody>\n",f);
1823
1824 if_exists(sum,sums,sum->l>=total_traffic/4)
1825 {
1826 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1827 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1828 }
1829
1830 if_exists(sum,sums,sum->i==10)
1831 {
1832 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1833 fprintf(f,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1834 }
1835
1836 if_exists(sum,sums,sum->l>=total_traffic/2)
1837 {
1838 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1839 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1840 }
1841
1842 if_exists(sum,sums,sum->l>=4*total_traffic/5)
1843 {
1844 fprintf(f,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1845 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></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>=(active_classes+1)/5)
1849 {
1850 fprintf(f,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1851 top20_count=sum->i;
1852 top20_perc1=(100*sum->i+50)/active_classes;
1853 top20_sum=sum->l;
1854 top20_perc2=(100*sum->l+50)/total_traffic;
1855 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",top20_count,top20_perc1,top20_sum,top20_perc2);
1856 }
1857
1858 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1859 {
1860 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1861 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1862 }
1863
1864 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1865 {
1866 fprintf(f,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1867 fprintf(f,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1868 }
1869
1870 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1871 {
1872 fprintf(f,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1873 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1874 }
1875
1876 fprintf(f,"<tr class=\"bgGrey\"><td><a href=\"%sERP.log\">All users, all traffic</a></td>\n", log_url);
1877 fprintf(f,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes,total_traffic);
1878 fputs("</tbody></table>\n", f);
1879
1880 /* write basic ERP data to log directory */
1881 if(!just_preview)
1882 {
1883 sprintf(str,"%s/ERP.log",log_dir);
1884 iplog=fopen(str,"a");
1885 if(iplog)
1886 {
1887 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",
1888 time(NULL), top20_count, top20_perc1, top20_sum, top20_perc2,
1889 active_classes, total_traffic, i, limit_count, prio_count, d); /* d = date*/
1890 fclose(iplog);
1891 }
1892 }
1893 }
1894
1895 fprintf(f, stats_html_signature, version);
1896 fclose(f);
1897 }
1898
1899 if(just_preview)
1900 {
1901 puts("Statistics preview generated (-p switch) - now exiting ...");
1902 exit(0);
1903 }
1904
1905 /*-----------------------------------------------------------------*/
1906 puts("Generating iptables and tc classes ...");
1907 /*-----------------------------------------------------------------*/
1908
1909 i=0;
1910 #ifdef DEBUG
1911 printf("%-22s %-15s mark\n","name","ip");
1912 #endif
1913
1914 for_each(ip,ips) if(ip->mark>0)
1915 {
1916 if(idxs)
1917 {
1918 char *buf;
1919 duplicate(ip->addr,buf);
1920 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1921
1922 string(chain_forward,6+strlen(buf));
1923 strcpy(chain_forward,"forw_");
1924 strcat(chain_forward,buf);
1925
1926 string(chain_postrouting,6+strlen(buf));
1927 strcpy(chain_postrouting,"post_");
1928 strcat(chain_postrouting,buf);
1929
1930 free(buf);
1931 }
1932 else
1933 {
1934 chain_forward="FORWARD";
1935 chain_postrouting="POSTROUTING";
1936 }
1937
1938 #ifdef DEBUG
1939 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1940 #endif
1941
1942 /* -------------------------------------------------------- mark download */
1943
1944 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);
1945 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1946 /* -m limit --limit 1/s */
1947 save_line(str);
1948
1949 if(qos_proxy)
1950 {
1951 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);
1952 /*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);*/
1953 save_line(str);
1954 }
1955
1956 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);
1957 save_line(str);
1958
1959 /* -------------------------------------------------------- mark upload */
1960 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);
1961 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1962 save_line(str);
1963
1964 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);
1965 save_line(str);
1966
1967 if(ip->min)
1968 {
1969 /* -------------------------------------------------------- download class */
1970 #ifdef DEBUG
1971 printf("(down: %dk-%dk ", ip->min, ip->max);
1972 #endif
1973
1974 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);
1975 safe_run(str);
1976
1977 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1978 {
1979 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*/
1980 safe_run(str);
1981 }
1982 if(filter_type == 1)
1983 {
1984 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, ip->mark, ip->mark);
1985 safe_run(str);
1986 }
1987
1988 /* -------------------------------------------------------- upload class */
1989 #ifdef DEBUG
1990 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1991 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1992 #endif
1993
1994 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1995 tc, wan, ip->group, ip->mark,
1996 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1997 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1998 safe_run(str);
1999
2000 if(strcmpi(ip->keyword->leaf_discipline, "none"))
2001 {
2002 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*/
2003 safe_run(str);
2004 }
2005 if(filter_type == 1)
2006 {
2007 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc, wan, ip->mark, ip->mark);
2008 safe_run(str);
2009 }
2010 }
2011 else
2012 {
2013 #ifdef DEBUG
2014 printf("(sharing %s)\n", ip->sharing);
2015 #endif
2016 }
2017 i++;
2018 }
2019
2020 if(idxs)
2021 {
2022 chain_forward = "forw_common";
2023 chain_postrouting = "post_common";
2024 }
2025 else
2026 {
2027 chain_forward = "FORWARD";
2028 chain_postrouting = "POSTROUTING";
2029 }
2030 /* -------------------------------- classify or reject free download */
2031 {
2032 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
2033 if(free_min) final_chain = "ACCEPT";
2034 if(qos_proxy)
2035 {
2036 if(free_min)
2037 {
2038 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);
2039 save_line(str);
2040 }
2041 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
2042 save_line(str);
2043 }
2044 if(free_min)
2045 {
2046 sprintf(str,"-A %s -o %s -j %s%d",chain_postrouting,lan,mark_iptables,3);
2047 save_line(str);
2048 }
2049 sprintf(str,"-A %s -o %s -j %s",chain_postrouting,lan,final_chain);
2050 save_line(str);
2051 /* ------------------------------- classify or reject free upload */
2052 if(free_min)
2053 {
2054 sprintf(str,"-A %s -o %s -j %s%d",chain_forward,wan,mark_iptables,3);
2055 save_line(str);
2056 }
2057 sprintf(str,"-A %s -o %s -j %s",chain_forward,wan,final_chain);
2058 save_line(str);
2059 }
2060
2061 if(free_min) /* allocate free bandwith if it is not zero... */
2062 {
2063 /*-----------------------------------------------------------------*/
2064 puts("Generating free bandwith classes ...");
2065 /*-----------------------------------------------------------------*/
2066 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2067 tc,lan,parent,free_min,free_max,burst,lowest_priority);
2068 safe_run(str);
2069 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2070 tc,wan,parent,free_min,free_max,burst,lowest_priority);
2071 safe_run(str);
2072 /* tc SFQ */
2073 if(strcmpi(qos_leaf, "none"))
2074 {
2075 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);
2076 safe_run(str);
2077
2078 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);
2079 safe_run(str);
2080 }
2081 /* tc handle 1 fw flowid */
2082 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);
2083 safe_run(str);
2084
2085 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);
2086 safe_run(str);
2087 }
2088 printf("Total IP count: %d\n", i);
2089 run_restore();
2090 if(log_file)
2091 {
2092 fclose(log_file);
2093 }
2094 return 0;
2095 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2096 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
2097 }
This page took 1.657469 seconds and 5 git commands to generate.