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