Ticket #1 bugfix: cll1.h verze 0.6.1
[svn/Prometheus-QoS/.git] / prometheus.c
1
2 /* ============================================================= */
3 /* === Prometheus QoS - you can "steal fire" from your ISP === */
4 /* === "fair-per-IP" quality of service (QoS) utility === */
5 /* === requires Linux 2.4.x or 2.6.x with HTB support === */
6 /* === Copyright(C) 2005-2007 Michael Polak (xChaos) === */
7 /* === Credits: CZFree.Net, Martin Devera, Netdave, Aquarius === */
8 /* ============================================================= */
9
10 /* Modified: xChaos, 20070502
11
12 Prometheus QoS is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2.1 of
15 the License, or (at your option) any later version.
16
17 Prometheus QoS is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with the Linux kernel source code; if not, write to
24 Michael Polak, Svojsikova 7, 169 00 Praha 6 Czech Republic */
25
26 #define STRLEN 256
27 #define MAX_GUARANTED_KBPS 2048
28 #undef DEBUG
29
30 #include "cll1.h"
31
32 const char *version="0.7.1";
33
34 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
35
36 void help(void)
37 {
38 puts("Command line switches:\n\
39 \n\
40 -?, --help this help screen\n\
41 -v, --version show version number of this utility and exit\n\
42 -c filename force alternative /etc/prometheus.conf filename\n\
43 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
44 -f just flush iptables and tc classes and exit (stop shaping)\n\
45 -9 emergency iptables flush (do not read data transfer statistics)\n\
46 -p just generate preview of data transfer statistics and exit\n\
47 -n no delay (overrides qos-free-delay keyword)\n\
48 -d dry run (preview tc and iptables commands on stdout)\n\
49 ");
50 }
51
52 /* === Configuraration file values defaults - stored in global variables ==== */
53
54 int dry_run=0; /* preview - use puts() instead of system() */
55 char *config="/etc/prometheus.conf"; /* main configuration file */
56 char *hosts="/etc/hosts"; /* line bandwidth definition file */
57 char *tc="/sbin/tc"; /* requires tc with HTB support */
58 char *iptables="/sbin/iptables"; /* requires iptables utility */
59 char *html="/var/www/traffic.html"; /* hall of fame filename */
60 char *preview="/var/www/preview.html"; /* hall of fame preview */
61 char *cmdlog="/var/log/prometheus"; /* command log filename */
62 char *credit="/var/run/prometheus.credit"; /* credit log file */
63 int enable_credit=1; /* enable credit file */
64 int use_credit=0; /* use credit file (if enabled)*/
65 char *log_dir="/var/www/html/logs/"; /* log directory pathname */
66 char *log_url="logs/"; /* log directory URL prefix */
67 char *title="Hall of Fame - Greatest Suckers"; /* hall of fame title */
68 int hall_of_fame=1; /* enable hall of fame */
69 char *lan="eth0"; /* LAN interface */
70 char *lan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */
71 char *wan="eth1"; /* WAN/ISP interface */
72 char *wan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */
73 char *qos_leaf="sfq perturb 5"; /* leaf discipline */
74 char *qos_free_zone=NULL; /* QoS free zone */
75 int qos_proxy=1; /* include proxy port to QoS */
76 int include_upload=1; /* upload+download=total traffic */
77 char *proxy_ip="192.168.1.1/32"; /* our IP with proxy port */
78 int proxy_port=3128; /* proxy port number */
79 int line=1024; /* WAN/ISP download in kbps */
80 int up=1024; /* WAN/ISP upload in kbps */
81 int free_min=32; /* minimum guaranted bandwidth for all undefined hosts */
82 int free_max=64; /* maximum allowed bandwidth for all undefined hosts */
83 int qos_free_delay=0; /* seconds to sleep before applying new QoS rules */
84 int digital_divide=2; /* controls digital divide weirdness ratio, 1...3 */
85 int max_nesting=3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
86 int burst=8; /* HTB burst (in kbits) */
87 int magic_priorities=8; /* number of priority levels (soft shaping) */
88 int magic_treshold=8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
89 int keywordcount=0;
90
91 /* not yet implemented:
92 int fixed_packets=0; maximum number of pps per IP address (not class!)
93 int packet_limit=5; maximum number of pps to htn CEIL, not rate !!!
94 */
95 FILE *log_file=NULL;
96
97 char *kwd="via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
98
99 const idxtable_treshold1=24; /* this is no longer configurable */
100 const idxtable_treshold2=12; /* this is no longer configurable */
101 const idxtable_bitmask1=3; /* this is no longer configurable */
102 const idxtable_bitmask2=3; /* this is no longer configurable */
103
104
105 /* not yet implemented:
106 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
107 -r just reload configuration (...and keep data transfer statistics)\n\
108 */
109
110 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
111
112 struct IP
113 {
114 char *addr;
115 char *name;
116 char *sharing;
117 int min;
118 int desired;
119 int max;
120 int mark;
121 int prio;
122 int fixedprio;
123 unsigned long long direct;
124 unsigned long long proxy;
125 unsigned long long upload;
126 unsigned long long traffic;
127 unsigned long long credit;
128 unsigned long pktsup;
129 unsigned long pktsdown;
130 struct Keyword *keyword;
131 list(IP);
132 } *ips=NULL, *ip, *sharedip;
133
134 struct Group
135 {
136 int min;
137 int count;
138 int desired;
139 list(Group);
140 } *groups=NULL, *group;
141
142 struct Index
143 {
144 char *addr;
145 char *id;
146 struct Index *parent;
147 int bitmask;
148 int children;
149 list(Index);
150 } *idxs=NULL, *idx, *metaindex;
151
152 struct Keyword
153 {
154 char *key;
155
156 int asymetry_ratio; /* ratio for ADSL-like upload */
157 int asymetry_fixed; /* fixed treshold for ADSL-like upload */
158 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
159 int prio_limit; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
160 long fixed_limit; /* fixed data limit for setting lower HTB ceil */
161 long fixed_prio; /* fixed data lmit for setting lower HTB prio */
162 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */
163 int reserve_max; /* malus for nominal HTB ceil (in kbps) */
164 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
165 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
166 int default_prio; /* default HTB priority for this keyword */
167 char *html_color;
168 int ip_count;
169
170 list(Keyword);
171 } *keyword,*defaultkeyword=NULL,*keywords=NULL;
172
173 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
174
175 void TheIP(void)
176 {
177 create(ip,IP);
178 ip->name="";
179 ip->addr="";
180 ip->sharing=NULL;
181 ip->prio=1;
182 ip->fixedprio=0;
183 ip->mark=ip->min=ip->max=ip->desired=ip->credit=0;
184 ip->upload=ip->proxy=ip->direct=ip->traffic=0;
185 ip->pktsup=ip->pktsdown=0;
186 ip->keyword=keywords;
187 push(ip,ips);
188 }
189
190 /* ====== Iptables indexes are used to reduce complexity to log8(N) ===== */
191
192 char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)
193 {
194 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
195 int dot=0,n;
196 char *ip,*outip,*outptr,*fmt;
197
198 duplicate(inip,ip);
199 /* debug printf("(%s,%d) -> ",ip,bitmask); */
200
201 if(ip && *ip && bitmask>=0 && bitmask<=32)
202 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
203 else
204 /* should never exit here */
205 return "undefined";
206 outptr=outip;
207 while(ip && *ip)
208 {
209 if(*ip=='.')
210 {
211 if(dot<(bitmask/8-1))
212 {
213 if(format_as_chainname)
214 *outptr='_';
215 else
216 *outptr='.';
217 outptr++;
218 dot++;
219 }
220 else
221 {
222 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/
223 if(cutdot)*cutdot='\0';
224 if(format_as_chainname)
225 fmt="_%d_%d";
226 else
227 fmt=".%d";
228 if(bitmask%8)
229 n=atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));
230 else
231 n=0;
232
233 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
234 sprintf(outptr,fmt,n,bitmask);
235 if(!format_as_chainname) while(bitmask<24)
236 {
237 strcat(outip,".0");
238 bitmask+=8;
239 }
240 /* debug printf("[%s]\n",outip); */
241 return outip;
242 }
243 }
244 else
245 {
246 *outptr=*ip;
247 outptr++;
248 }
249 ip++;
250 }
251 /*should never exit here*/
252 *outptr='\0';
253 return outip;
254 }
255
256 char *hash_id(char *ip,int bitmask)
257 { return very_ugly_ipv4_code(ip,bitmask,1); }
258
259 char *subnet_id(char *ip,int bitmask)
260 { return very_ugly_ipv4_code(ip,bitmask,0); }
261
262 /* ================= Let's parse configuration file here =================== */
263
264 void reject_config_and_exit(char *filename)
265 {
266 printf("Configuration file %s rejected - abnormal exit.",filename);
267 exit(-1);
268 }
269
270 void get_config(char *config_filename)
271 {
272 printf("Configured keywords: ");
273 parse(config_filename)
274 {
275 option("keyword",kwd);
276 if(kwd)
277 {
278 printf("%s ",kwd);
279
280 create(keyword,Keyword);
281 keyword->key=kwd;
282 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
283 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
284 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
285 keyword->prio_limit=4; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
286 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
287 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
288 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
289 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
290 /* obsolete:
291 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
292 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide
293 */
294 keyword->default_prio=1;
295 keyword->html_color="000000";
296 keyword->ip_count=0;
297
298 push(keyword,keywords);
299 if(!defaultkeyword) defaultkeyword=keyword;
300 keywordcount++;
301
302 kwd=NULL;
303 }
304 else every(keyword,keywords)
305 {
306 int l=strlen(keyword->key);
307
308
309 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
310 {
311 char *tmptr=_; /* <---- l+1 ----> */
312 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
313 ioption("asymetry-ratio",keyword->asymetry_ratio);
314 ioption("asymetry-treshold",keyword->asymetry_fixed);
315 ioption("magic-relative-limit",keyword->data_limit);
316 ioption("magic-relative-prio",keyword->prio_limit);
317 loption("magic-fixed-limit",keyword->fixed_limit);
318 loption("magic-fixed-prio",keyword->fixed_prio);
319 ioption("htb-default-prio",keyword->default_prio);
320 ioption("htb-rate-bonus",keyword->reserve_min);
321 ioption("htb-ceil-malus",keyword->reserve_max);
322 /* obsolete:
323 ioption("htb-ceil-divide",keyword->divide_max);
324 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
325 */
326 option("html-color",keyword->html_color);
327 _=tmptr;
328
329 if(keyword->data_limit || keyword->fixed_limit ||
330 keyword->prio_limit || keyword->fixed_prio)
331 use_credit=1;
332
333
334 }
335 }
336
337 option("tc",tc);
338 option("iptables",iptables);
339 option("hosts",hosts);
340 option("lan-interface",lan);
341 option("wan-interface",wan);
342 option("lan-medium",lan_medium);
343 option("wan-medium",wan_medium);
344 ioption("wan-download",line);
345 ioption("wan-upload",up);
346 ioption("hall-of-fame-enable",hall_of_fame);
347 option("hall-of-fame-title",title);
348 option("hall-of-fame-filename",html);
349 option("hall-of-fame-preview",preview);
350 option("log-filename",cmdlog);
351 option("credit-filename",credit);
352 ioption("credit-enable",enable_credit);
353 option("log-traffic-directory",log_dir);
354 option("log-traffic-url-path",log_url);
355 option("qos-free-zone",qos_free_zone);
356 ioption("qos-free-delay",qos_free_delay);
357 ioption("qos-proxy-enable",qos_proxy);
358 option("qos-proxy-ip",proxy_ip);
359 option("htb-leaf-discipline",qos_leaf);
360 ioption("qos-proxy-port",proxy_port);
361 ioption("free-rate",free_min);
362 ioption("free-ceil",free_max);
363 ioption("htb-burst",burst);
364 ioption("htb-nesting-limit",max_nesting);
365 ioption("magic-include-upload",include_upload);
366 ioption("magic-priorities",magic_priorities);
367 ioption("magic-treshold",magic_treshold);
368 /* not yet implemented:
369 ioption("magic-fixed-packets",fixed_packets);
370 ioption("magic-relative-packets",packet_limit);
371 */
372 }
373 fail
374 {
375 perror(config_filename);
376 puts("Warning - using built-in defaults instead ...");
377 }
378 done;
379 printf("\n");
380
381 /* are supplied values meaningful ?*/
382 if(line<=0 || up<=0)
383 {
384 puts("Illegal value of wan bandwidth: 0 kbps.");
385 reject_config_and_exit(config_filename);
386 }
387 }
388
389 /* ===================== traffic analyser - uses iptables ================ */
390
391 void get_traffic_statistics(void)
392 {
393 char *str,*cmd;
394 int downloadflag=0;
395
396 textfile(Pipe,str) *line,*lines=NULL;
397 string(str,STRLEN);
398 string(cmd,STRLEN);
399
400 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
401 shell(cmd);
402 input(str,STRLEN)
403 {
404 create(line,Pipe);
405 line->str=str;
406 string(str,STRLEN);
407 append(line,lines);
408 }
409
410 every(line,lines)
411 {
412 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
413 unsigned long long traffic=0;
414 unsigned long pkts=0;
415 char *ipaddr=NULL,*ptr;
416
417 /* debug puts(line->str); */
418 valid_columns(ptr,line->str,' ',col)
419 if(valid) switch(col)
420 {
421 case 1: if(eq(ptr,"Chain"))
422 setchainname=1;
423 else if(eq(ptr,"pkts"))
424 valid=0;
425 else
426 sscanf(ptr,"%lu",&pkts);
427 break;
428 case 2: if(setchainname)
429 {
430 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
431 downloadflag=1;
432 else
433 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
434 downloadflag=0;
435
436 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
437 commonflag=1;
438 }
439 else
440 sscanf(ptr,"%Lu",&traffic); traffic+=(1<<19); traffic>>=20;
441 break;
442 case 3: if(strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5) || commonflag)
443 accept=eq(ptr,"MARK");
444 break;
445 case 8: if(downloadflag)
446 {
447 if(strstr(proxy_ip,ptr))proxyflag=1;
448 }
449 else
450 ipaddr=ptr;
451 break;
452 case 9: if(downloadflag)ipaddr=ptr;break;
453 }
454
455 if(accept && traffic>0 && ipaddr)
456 {
457 if(proxyflag)printf("(proxy) ");
458 else if(!downloadflag) printf("(upload) ");
459 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr, traffic, pkts);
460 find(ip,ips,eq(ip->addr,ipaddr));
461 else
462 {
463 TheIP();
464 ip->addr=ipaddr;
465 if(eq(ip->addr,"0.0.0.0/0"))
466 {
467 ip->name="(unregistered)";
468 ip->min=free_min;
469 ip->max=ip->desired=free_max;
470 }
471 }
472
473 if(downloadflag)
474 {
475 if(proxyflag)
476 ip->proxy=traffic;
477 else
478 ip->traffic+=traffic;
479 ip->direct=ip->traffic-ip->upload-ip->proxy;
480 ip->pktsdown=pkts;
481 }
482 else
483 {
484 ip->upload=traffic;
485 ip->pktsup=pkts;
486 if(include_upload)
487 ip->traffic+=traffic;
488 else
489 if(traffic>ip->traffic)
490 ip->traffic=traffic;
491 }
492 }
493 }
494
495
496 free(cmd);
497 }
498
499 /* ========== This function executes, logs OR ALSO prints command ========== */
500
501 void safe_run(char *cmd)
502 {
503 if(dry_run) printf("\n=>%s\n",cmd); else system(cmd);
504 if(log_file) fprintf(log_file,"%s\n",cmd);
505 }
506
507 /* == This function strips extra characters after IP address and stores it = */
508
509 void parse_ip(char *str)
510 {
511 char *ptr=str,*ipaddr=NULL,*ipname=NULL;;
512
513 while(*ptr && *ptr!=' ' && *ptr!=9)
514 ptr++;
515
516 *ptr=0;
517 ipaddr=str;
518 ptr++;
519 while(*ptr && (*ptr==' ' || *ptr==9))
520 ptr++;
521 ipname=ptr;
522 while(*ptr && *ptr!=' ' && *ptr!=9)
523 ptr++;
524 *ptr=0;
525
526 find(ip,ips,eq(ip->addr,ipaddr)); else TheIP();
527 ip->addr=ipaddr;
528 ip->name=ipname;
529 }
530
531 char *parse_datafile_line(char *str)
532 {
533 char *ptr=strchr(str,' ');
534
535 if(ptr)
536 {
537 *ptr=0;
538 ptr++;
539 return ptr;
540 }
541 else
542 return NULL;
543 }
544
545 /*-----------------------------------------------------------------*/
546 /* Are you looking for int main (int argc, char **argv) ? :-)) */
547 /*-----------------------------------------------------------------*/
548
549 program
550 {
551 int i=0;
552 FILE *f=NULL;
553 char *str, *ptr, *d;
554 char *substring;
555 int class_count=0,ip_count=0;
556 int parent=1;
557 int just_flush=0;
558 int nodelay=0;
559 int just_preview=0; /* preview - generate just stats */
560 char *chain_forward, *chain_postrouting;
561 char *althosts=NULL;
562
563 printf("\n\
564 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
565 Version %s - Copyright (C)2005-2007 Michael Polak (xChaos)\n\
566 Credits: CZFree.Net, Martin Devera, Netdave, Aquarius\n\n",version);
567
568 /*----- Boring... we have to check command line options first: ----*/
569
570 arguments
571 {
572 argument("-c") { nextargument(config); }
573 argument("-h") { nextargument(althosts);}
574 argument("-d") { dry_run=1; }
575 argument("-f") { just_flush=1; }
576 argument("-9") { just_flush=9; }
577 argument("-p") { just_preview=1; }
578 argument("-n") { nodelay=1; }
579 argument("-?") { help(); exit(0); }
580 argument("--help") { help(); exit(0); }
581 argument("-v") { exit(0); }
582 argument("--version") { exit(0); }
583 }
584
585 if(dry_run)
586 puts("*** THIS IS JUST DRY RUN ! ***\n");
587
588 date(d); /* this is typical cll1.h macro */
589
590 /*-----------------------------------------------------------------*/
591 printf("Parsing configuration file %s ...\n", config);
592 /*-----------------------------------------------------------------*/
593 get_config(config);
594
595 if(althosts) hosts=althosts;
596
597 if(just_flush<9)
598 {
599 /*-----------------------------------------------------------------*/
600 puts("Parsing iptables verbose output ...");
601 /*-----------------------------------------------------------------*/
602 get_traffic_statistics();
603 }
604
605 /*-----------------------------------------------------------------*/
606 printf("Parsing class defintion file %s ...\n", hosts);
607 /*-----------------------------------------------------------------*/
608 parse(hosts)
609 {
610 str=_;
611
612 if(*str<'0' || *str>'9')
613 continue;
614
615 //Does this IP share QoS class with some other ?
616 substring=strstr(str,"sharing-");
617 if(substring)
618 {
619 substring+=8; //"sharing-"
620 parse_ip(str);
621 ip_count++;
622 ip->sharing=substring;
623 ip->keyword=defaultkeyword; /* settings for default keyword */
624 while(*substring && *substring!='\n')
625 substring++;
626 *substring=0;
627 }
628 else
629 {
630 //Do we have to create new QoS class for this IP ?
631
632 find(keyword,keywords,(substring=strstr(str,keyword->key)))
633 {
634 parse_ip(str);
635 ip_count++;
636 ip->keyword=keyword;
637 keyword->ip_count++;
638 ip->prio=keyword->default_prio;
639 substring+=strlen(keyword->key)+1;
640 ptr=substring;
641 while(*ptr && *ptr!='-')
642 ptr++;
643 if(*ptr=='-')
644 {
645 *ptr=0;
646 ip->max=ip->desired=atoi(ptr+1);
647 }
648 ip->min=atoi(substring);
649 if(ip->min<=0)
650 {
651 puts("Illegal value of minimum bandwidth: 0 kbps.");
652 reject_config_and_exit(hosts);
653 }
654 if(ip->max<=ip->min)
655 {
656 ip->fixedprio=1;
657 ip->max=ip->min+ip->keyword->reserve_min;
658 }
659 else
660 {
661 ip->max-=ip->keyword->reserve_max;
662
663 /*
664 if(ip->keyword->divide_max>1)
665 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
666 if(ip->keyword->htb_ceil_bonus_divide>0)
667 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
668 */
669 if(ip->max<ip->min)
670 ip->max=ip->min;
671 }
672 ip->mark=MAX_GUARANTED_KBPS+1+class_count++;
673
674 find(group,groups,group->min==ip->min)
675 {
676 group->count++;
677 group->desired+=ip->min;
678 }
679 else
680 {
681 create(group,Group);
682 group->min=ip->min;
683
684 if(group->min<8) group->min=8;
685 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
686 /* it is because class IDs are derived from min. bandwidth. - xCh */
687 if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
688
689 group->count=1;
690 group->desired=ip->min;
691 insert(group,groups,desc_order_by,min);
692 }
693 }//endif keyword-
694 }//endif sharing-
695 }
696 fail
697 {
698 perror(hosts);
699 exit(-1);
700 }
701 done;
702
703 /*-----------------------------------------------------------------*/
704 /* cll1.h - let's allocate brand new character buffer... */
705 /*-----------------------------------------------------------------*/
706 string(str,STRLEN);
707
708 /*-----------------------------------------------------------------*/
709 puts("Resolving shared connections ...");
710 /*-----------------------------------------------------------------*/
711 search(ip,ips,ip->sharing)
712 {
713 search(sharedip,ips,eq(sharedip->name,ip->sharing))
714 {
715 sharedip->traffic+=ip->traffic;
716 ip->traffic=0;
717 ip->mark=sharedip->mark;
718 break;
719 }
720 if(!sharedip)
721 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);
722 }
723
724 if(enable_credit && just_flush<9)
725 {
726 /*-----------------------------------------------------------------*/
727 printf("Parsing credit file %s ...\n", credit);
728 /*-----------------------------------------------------------------*/
729 parse(credit)
730 {
731 ptr=parse_datafile_line(_);
732 if(ptr)
733 {
734 find(ip,ips,eq(ip->addr,_))
735 sscanf(ptr,"%Lu",&(ip->credit));
736 }
737 }
738 done;
739 }
740
741 if(!just_preview)
742 {
743 /*-----------------------------------------------------------------*/
744 puts("Initializing iptables and tc classes ...");
745 /*-----------------------------------------------------------------*/
746
747 log_file=fopen(cmdlog,"w");
748
749 sprintf(str,"%s -t mangle -F INPUT",iptables);
750 safe_run(str);
751
752 sprintf(str,"%s -t mangle -F OUTPUT",iptables);
753 safe_run(str);
754
755 sprintf(str,"%s -t mangle -F PREROUTING",iptables);
756 safe_run(str);
757
758 sprintf(str,"%s -t mangle -F POSTROUTING",iptables);
759 safe_run(str);
760
761 sprintf(str,"%s -t mangle -F FORWARD",iptables);
762 safe_run(str);
763
764 sprintf(str,"%s -t mangle -Z INPUT",iptables);
765 safe_run(str);
766
767 sprintf(str,"%s -t mangle -Z OUTPUT",iptables);
768 safe_run(str);
769
770 sprintf(str,"%s -t mangle -Z PREROUTING",iptables);
771 safe_run(str);
772
773 sprintf(str,"%s -t mangle -Z POSTROUTING",iptables);
774 safe_run(str);
775
776 sprintf(str,"%s -t mangle -Z FORWARD",iptables);
777 safe_run(str);
778
779 sprintf(str,"%s -t mangle -X",iptables);
780 safe_run(str);
781
782 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
783 safe_run(str);
784
785 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
786 safe_run(str);
787
788 if(qos_free_zone && *qos_free_zone!='0')
789 {
790 char *chain;
791
792 sprintf(str,"%s -t mangle -A FORWARD -d %s -o %s -j ACCEPT",iptables, qos_free_zone, wan);
793 safe_run(str);
794
795 if(qos_proxy)
796 {
797 sprintf(str,"%s -t mangle -N post_noproxy 2>/dev/null",iptables);
798 safe_run(str);
799 sprintf(str,"%s -t mangle -F post_noproxy",iptables);
800 safe_run(str);
801 sprintf(str,"%s -t mangle -A POSTROUTING -p ! tcp -o %s -j post_noproxy",iptables, lan);
802 safe_run(str);
803 sprintf(str,"%s -t mangle -A POSTROUTING -s ! %s -o %s -j post_noproxy",iptables, proxy_ip, lan);
804 safe_run(str);
805 sprintf(str,"%s -t mangle -A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy",iptables, proxy_ip, proxy_port, lan);
806 safe_run(str);
807
808 chain="post_noproxy";
809 }
810 else
811 chain="POSTROUTING";
812
813 sprintf(str,"%s -t mangle -A %s -s %s -o %s -j ACCEPT",iptables, chain, qos_free_zone, lan);
814 safe_run(str);
815 }
816
817 if(ip_count>idxtable_treshold1 && !just_flush)
818 {
819 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
820 char *subnet, *ptr, *buf;
821 /*-----------------------------------------------------------------*/
822 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
823 /*-----------------------------------------------------------------*/
824
825 sprintf(str,"%s -t mangle -N post_common 2>/dev/null",iptables);
826 safe_run(str);
827 sprintf(str,"%s -t mangle -F post_common",iptables);
828 safe_run(str);
829 sprintf(str,"%s -t mangle -N forw_common 2>/dev/null",iptables);
830 safe_run(str);
831 sprintf(str,"%s -t mangle -F forw_common",iptables);
832 safe_run(str);
833
834 search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
835 {
836 buf=hash_id(ip->addr,bitmask);
837 find(idx,idxs,eq(idx->id,buf))
838 idx->children++;
839 else
840 {
841 create(idx,Index);
842 idx->addr=ip->addr;
843 idx->id=buf;
844 idx->bitmask=bitmask;
845 idx->parent=NULL;
846 idx->children=0;
847 idxcount++;
848 push(idx,idxs);
849 }
850 }
851
852 /* brutal perfomance optimalization */
853 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
854 {
855 bitmask-=idxtable_bitmask2;
856 idxcount=0;
857 search(idx,idxs,idx->parent==NULL)
858 {
859 buf=hash_id(idx->addr,bitmask);
860 find(metaindex,idxs,eq(metaindex->id,buf))
861 metaindex->children++;
862 else
863 {
864 create(metaindex,Index);
865 metaindex->addr=idx->addr;
866 metaindex->id=buf;
867 metaindex->bitmask=bitmask;
868 metaindex->parent=NULL;
869 metaindex->children=0;
870 idxcount++;
871 push(metaindex,idxs);
872 }
873 idx->parent=metaindex;
874 }
875 }
876
877 /* this should slightly optimize throughout ... */
878 sort(idx,idxs,desc_order_by,children);
879 sort(idx,idxs,order_by,bitmask);
880
881 i=0;
882 every(idx,idxs)
883 {
884 subnet=subnet_id(idx->addr,idx->bitmask);
885 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);
886
887 sprintf(str,"%s -t mangle -N post_%s 2>/dev/null",iptables, idx->id);
888 safe_run(str);
889
890 sprintf(str,"%s -t mangle -F post_%s",iptables, idx->id);
891 safe_run(str);
892
893 sprintf(str,"%s -t mangle -N forw_%s 2>/dev/null",iptables, idx->id);
894 safe_run(str);
895
896 sprintf(str,"%s -t mangle -F forw_%s",iptables, idx->id);
897 safe_run(str);
898
899 if(idx->parent)
900 {
901 string(buf,strlen(idx->parent->id)+6);
902 sprintf(buf,"post_%s",idx->parent->id);
903 }
904 else
905 buf="POSTROUTING";
906
907 sprintf(str,"%s -t mangle -A %s -d %s/%d -o %s -j post_%s",iptables, buf, subnet, idx->bitmask, lan, idx->id);
908 safe_run(str);
909
910 sprintf(str,"%s -t mangle -A %s -d %s/%d -o %s -j post_common",iptables, buf, subnet, idx->bitmask, lan);
911 safe_run(str);
912
913 if(idx->parent)
914 {
915 string(buf,strlen(idx->parent->id)+6);
916 sprintf(buf,"forw_%s",idx->parent->id);
917 }
918 else
919 buf="FORWARD";
920
921 sprintf(str,"%s -t mangle -A %s -s %s/%d -o %s -j forw_%s",iptables, buf, subnet, idx->bitmask, wan, idx->id);
922 safe_run(str);
923
924 sprintf(str,"%s -t mangle -A %s -s %s/%d -o %s -j forw_common",iptables, buf, subnet, idx->bitmask, wan);
925 safe_run(str);
926 }
927 printf("Total indexed iptables chains created: %d\n", i);
928
929 sprintf(str,"%s -t mangle -A FORWARD -o %s -j forw_common",iptables, wan);
930 safe_run(str);
931
932 sprintf(str,"%s -t mangle -A POSTROUTING -o %s -j post_common",iptables, lan);
933 safe_run(str);
934 }
935
936 }
937
938 if(just_flush)
939 {
940 puts("Just flushed iptables and tc classes - now exiting ...");
941 exit(0);
942 }
943
944 if(!just_preview)
945 {
946 if(!dry_run && !nodelay && qos_free_delay)
947 {
948 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
949 sleep(qos_free_delay);
950 }
951
952 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q 1 default 2",tc,lan);
953 safe_run(str);
954
955 sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,lan,lan_medium,lan_medium,burst);
956 safe_run(str);
957
958 sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %dkbit ceil %dkbit burst %dk prio 0",tc,lan,line,line,burst);
959 safe_run(str);
960
961 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q 1 default 2",tc,wan);
962 safe_run(str);
963
964 sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,wan,wan_medium,wan_medium,burst);
965 safe_run(str);
966
967 sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %dkbit ceil %dkbit burst %dk prio 0",tc,wan,up,up,burst);
968 safe_run(str);
969 }
970
971 /*-----------------------------------------------------------------*/
972 puts("Locating suckers and generating root classes ...");
973 /*-----------------------------------------------------------------*/
974 sort(ip,ips,desc_order_by,traffic);
975
976
977 /*-----------------------------------------------------------------*/
978 /* sub-scope - local variables */
979 {
980 long rate=line;
981 long max=line;
982 int group_count=0;
983 FILE *credit_file=NULL;
984
985 if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");
986
987 every(group,groups)
988 {
989 if(!just_preview)
990 {
991 //download
992 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio 1",
993 tc, lan, parent, group->min, rate, max, burst);
994 safe_run(str);
995
996 //upload
997 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %ldkbit ceil %ldkbit burst %dk prio 1",
998 tc, wan, parent, group->min, (long)(rate*up/line), (long)(max*up/line), burst);
999 safe_run(str);
1000 }
1001
1002 if(group_count++<max_nesting) parent=group->min;
1003
1004 rate-=digital_divide*group->min;
1005 if(rate<group->min)rate=group->min;
1006
1007 /*shaping of aggresive downloaders, with credit file support */
1008 if(use_credit)
1009 {
1010 int group_rate=group->min, priority_sequence=magic_priorities+1;
1011
1012 search(ip, ips, ip->min==group->min && ip->max>ip->min)
1013 {
1014 if(ip->keyword->data_limit>0 &&
1015 ip->traffic>ip->credit+
1016 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))
1017 && !ip->fixedprio)
1018 {
1019 if(group_rate<ip->max) ip->max=group_rate;
1020 group_rate+=magic_treshold;
1021 ip->prio=magic_priorities+2;
1022 if(ip->prio<3) ip->prio=3;
1023 }
1024 else
1025 {
1026 if(ip->traffic>ip->credit+
1027 (ip->min*ip->keyword->prio_limit+(ip->keyword->fixed_prio<<20)) &&
1028 !ip->fixedprio)
1029 {
1030 ip->prio=priority_sequence--;
1031 if(ip->prio<2) ip->prio=2;
1032 }
1033
1034 if(credit_file)
1035 {
1036 unsigned long long lcredit=0;
1037 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1038 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1039 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1040 }
1041 }
1042 }
1043
1044 }
1045 }
1046 if(credit_file)fclose(credit_file);
1047 }
1048
1049 if(just_preview)
1050 {
1051 f=fopen(preview,"w");
1052 ptr=preview;
1053 }
1054 else if(!dry_run && !just_flush)
1055 {
1056 /*-----------------------------------------------------------------*/
1057 printf("Writing data transfer database ...\n");
1058 /*-----------------------------------------------------------------*/
1059 f=fopen("/var/run/prometheus.previous","w");
1060 if(f)
1061 {
1062 search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)
1063 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);
1064 fclose(f);
1065 }
1066
1067 f=fopen(html,"w");
1068 ptr=html;
1069 }
1070
1071 if(f)
1072 {
1073 int total=0;
1074 int count=1;
1075 i=0;
1076
1077 /*-----------------------------------------------------------------*/
1078 printf("Sorting data and generating statistics page %s ...\n",ptr);
1079 /*-----------------------------------------------------------------*/
1080
1081 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);
1082 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);
1083 fputs("</tr>\n",f);
1084 every(group,groups)
1085 {
1086 #ifdef DEBUG
1087 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);
1088 #endif
1089 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);
1090 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);
1091
1092 every(keyword,keywords)
1093 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit);
1094
1095 i+=group->desired;
1096 total+=group->count;
1097 count++;
1098 }
1099 #ifdef DEBUG
1100 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);
1101 #endif
1102 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %d k</td>",line);
1103 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);
1104
1105 every(keyword,keywords)
1106 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count);
1107
1108 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));
1109 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);
1110
1111 fputs("</table>\n",f);
1112 }
1113 else if(!dry_run && !just_flush)
1114 perror(html);
1115
1116 i=1;
1117 if(f)
1118 {
1119 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1120 int active_classes=0;
1121 int colspan;
1122 FILE *iplog;
1123 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1124
1125 if(qos_proxy)
1126 colspan=12;
1127 else
1128 colspan=11;
1129
1130 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);
1131 fprintf(f," (%s)</th></tr>\n", d);
1132 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1133 <td align=\"right\">credit</td>\
1134 <td align=\"right\">limit</td>\
1135 <td align=\"right\">total</td>\
1136 <td align=\"right\">direct</td>\n",f);
1137 if(qos_proxy)
1138 fputs("<td align=\"right\">proxy</td>\n",f);
1139 fputs("<td align=\"right\">upload</td>\
1140 <td align=\"right\">minimum</td>\
1141 <td align=\"right\">desired</td>\
1142 <td align=\"right\">maximum</td>\
1143 <td>prio</td></tr>\n",f);
1144
1145 every(ip,ips)
1146 {
1147 char *f1="", *f2="";
1148 if(ip->max<ip->desired)
1149 {
1150 f1="<font color=\"red\">";
1151 f2="</font>";
1152 }
1153 else if(ip->prio>1)
1154 {
1155 f1="<font color=\"brown\">";
1156 f2="</font>";
1157 }
1158
1159 #ifdef DEBUG
1160 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1161 #endif
1162 fprintf(f,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td><td align=\"right\">%Lu M</td>\n",
1163 ip->name, i, log_url, ip->name, ip->name, ip->credit);
1164 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",ip->keyword->html_color,ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1165 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);
1166 if(qos_proxy)
1167 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);
1168 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);
1169 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",ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);
1170 total+=ip->traffic;
1171 total_direct+=ip->direct;
1172 total_proxy+=ip->proxy;
1173 total_upload+=ip->upload;
1174 if(ip->traffic>0)
1175 {
1176 active_classes++;
1177 tmp_sum+=ip->traffic;
1178 create(sum,Sum);
1179 sum->l=tmp_sum;
1180 sum->i=active_classes;
1181 insert(sum,sums,order_by,i);
1182 }
1183
1184 i++;
1185
1186 if(!just_preview)
1187 {
1188 sprintf(str,"%s%s.log",log_dir,ip->name);
1189 iplog=fopen(str,"a");
1190 if(iplog)
1191 {
1192 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%s",time(NULL),ip->name,ip->traffic, ip->direct, ip->proxy, ip->upload,d);
1193 fclose(iplog);
1194 }
1195 }
1196
1197 }
1198 fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1199 fprintf(f,"<th align=\"right\">%Lu M</th>\
1200 <th align=\"right\">%Lu M</th>\n", total, total_direct);
1201 if(qos_proxy)
1202 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);
1203 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);
1204 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);
1205
1206 if(active_classes>10)
1207 {
1208 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"4\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
1209 fputs("<tr><td colspan=\"2\">Active Classes</td><td colspan=\"2\">Data transfers</td></tr>\n",f);
1210 find (sum,sums,sum->l>=total/4)
1211 fprintf(f,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1212 find (sum,sums,sum->i==10)
1213 fprintf(f,"<tr><td>Top 10</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1214 find (sum,sums,sum->l>=total/2)
1215 fprintf(f,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1216 find (sum,sums,sum->i>=(active_classes+3)/4)
1217 fprintf(f,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1218 find (sum,sums,sum->i>=(active_classes+1)/2)
1219 fprintf(f,"<tr><td>Top %d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%d %%</td></tr>\n",sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total);
1220 fprintf(f,"<tr><th align=\"left\">All %d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes,total);
1221 fputs("</table>\n",f);
1222 }
1223 fprintf(f,"<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n",version);
1224 fclose(f);
1225 }
1226
1227 if(just_preview)
1228 {
1229 puts("Statistics preview generated (-p switch) - now exiting ...");
1230 exit(0);
1231 }
1232
1233 /*-----------------------------------------------------------------*/
1234 puts("Generating iptables and tc classes ...");
1235 /*-----------------------------------------------------------------*/
1236
1237 i=0;
1238 printf("%-22s %-15s mark\n","name","ip");
1239 search(ip,ips,ip->mark>0)
1240 {
1241
1242 if(idxs)
1243 {
1244 char *buf;
1245 duplicate(ip->addr,buf);
1246 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1247
1248 string(chain_forward,6+strlen(buf));
1249 strcpy(chain_forward,"forw_");
1250 strcat(chain_forward,buf);
1251
1252 string(chain_postrouting,6+strlen(buf));
1253 strcpy(chain_postrouting,"post_");
1254 strcat(chain_postrouting,buf);
1255
1256 free(buf);
1257 }
1258 else
1259 {
1260 chain_forward="FORWARD";
1261 chain_postrouting="POSTROUTING";
1262 }
1263
1264 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1265
1266 /* -------------------------------------------------------- mark download */
1267
1268 sprintf(str,"%s -t mangle -A %s -d %s/32 -o %s -j MARK --set-mark %d",iptables,chain_postrouting,ip->addr,lan,ip->mark);
1269 /* -m limit --limit 1/s */
1270 safe_run(str);
1271
1272 if(qos_proxy)
1273 {
1274 sprintf(str,"%s -t mangle -A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j MARK --set-mark %d",iptables,chain_postrouting,proxy_ip,proxy_port,ip->addr,lan,ip->mark);
1275 safe_run(str);
1276 }
1277
1278 sprintf(str,"%s -t mangle -A %s -d %s/32 -o %s -j ACCEPT",iptables,chain_postrouting,ip->addr,lan);
1279 safe_run(str);
1280
1281 /* -------------------------------------------------------- mark upload */
1282
1283 sprintf(str,"%s -t mangle -A %s -s %s/32 -o %s -j MARK --set-mark %d",iptables,chain_forward,ip->addr,wan,ip->mark);
1284 safe_run(str);
1285
1286 sprintf(str,"%s -t mangle -A %s -s %s/32 -o %s -j ACCEPT",iptables,chain_forward,ip->addr,wan);
1287 safe_run(str);
1288
1289 if(ip->min)
1290 {
1291 /* -------------------------------------------------------- download class */
1292 printf("(down: %dk-%dk ", ip->min, ip->max);
1293
1294 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->min, ip->mark,ip->min,ip->max, burst, ip->prio);
1295 safe_run(str);
1296
1297 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, ip->mark, ip->mark, qos_leaf);
1298 safe_run(str);
1299
1300 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, ip->mark, ip->mark);
1301 safe_run(str);
1302
1303 /* -------------------------------------------------------- upload class */
1304 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1305 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1306
1307 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1308 tc, wan, ip->min, ip->mark,
1309 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1310 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1311 safe_run(str);
1312
1313 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s",tc, wan, ip->mark, ip->mark, qos_leaf);
1314 safe_run(str);
1315
1316 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc, wan, ip->mark, ip->mark);
1317 safe_run(str);
1318 }
1319 else
1320 printf("(sharing %s)\n", ip->sharing);
1321 i++;
1322 }
1323
1324
1325 if(idxs)
1326 {
1327 chain_forward="forw_common";
1328 chain_postrouting="post_common";
1329 }
1330 else
1331 {
1332 chain_forward="FORWARD";
1333 chain_postrouting="POSTROUTING";
1334 }
1335
1336 /* -------------------------------------------------------- mark download */
1337
1338 if(qos_proxy)
1339 {
1340 sprintf(str,"%s -t mangle -A %s -s %s -p tcp --sport %d -o %s -j MARK --set-mark 3",iptables,chain_postrouting,proxy_ip,proxy_port,lan);
1341 safe_run(str);
1342 sprintf(str,"%s -t mangle -A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",iptables,chain_postrouting,proxy_ip,proxy_port,lan);
1343 safe_run(str);
1344 }
1345 sprintf(str,"%s -t mangle -A %s -o %s -j MARK --set-mark 3",iptables,chain_postrouting,lan);
1346 safe_run(str);
1347 sprintf(str,"%s -t mangle -A %s -o %s -j ACCEPT",iptables,chain_postrouting,lan);
1348 safe_run(str);
1349
1350 /* -------------------------------------------------------- mark upload */
1351 sprintf(str,"%s -t mangle -A %s -o %s -j MARK --set-mark 3",iptables,chain_forward,wan);
1352 safe_run(str);
1353 sprintf(str,"%s -t mangle -A %s -o %s -j ACCEPT",iptables,chain_forward,wan);
1354 safe_run(str);
1355
1356 printf("Total IP count: %d\n", i);
1357
1358 /* ---------------------------------------- tc - free bandwith shared class */
1359 sprintf(str,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc,lan,parent,free_min,free_max,burst);
1360 safe_run(str);
1361
1362 sprintf(str,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc,wan,parent,free_min,free_max,burst);
1363 safe_run(str);
1364
1365 /* tc SFQ */
1366 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);
1367 safe_run(str);
1368
1369 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);
1370 safe_run(str);
1371
1372 /* tc handle 1 fw flowid */
1373 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);
1374 safe_run(str);
1375
1376 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);
1377 safe_run(str);
1378
1379 if(log_file) fclose(log_file);
1380 return 0;
1381
1382 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1383 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1384 }
This page took 1.125516 seconds and 4 git commands to generate.