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