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 /* ============================================================= */
10 /* Modified: xChaos, 20070502
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with the Linux kernel source code; if not, write to
25 Michael Polak, Svojsikova 7, 169 00 Praha 6 Czech Republic */
28 #define FIRSTGROUPID 1024
29 #define MAX_GUARANTED_KBPS 2048
34 const char *version
="0.7.7"; /*0.7.9 will be last development, 0.8.0 first stable */
36 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
40 puts("Command line switches:\n\
42 -?, --help this help screen\n\
43 -v, --version show version number of this utility and exit\n\
44 -c filename force alternative /etc/prometheus.conf filename\n\
45 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
46 -f just flush iptables and tc classes and exit (stop shaping)\n\
47 -9 emergency iptables flush (do not read data transfer statistics)\n\
48 -p just generate preview of data transfer statistics and exit\n\
49 -n no delay (overrides qos-free-delay keyword)\n\
50 -d dry run (preview tc and iptables commands on stdout)\n\
54 /* === Configuraration file values defaults - stored in global variables ==== */
56 int filter_type
=1; /*1 mark, 2 classify*/
58 char *mark_iptables
="MARK --set-mark ";
59 int dry_run
=0; /* preview - use puts() instead of system() */
60 char *config
="/etc/prometheus.conf"; /* main configuration file */
61 char *hosts
="/etc/hosts"; /* line bandwidth definition file */
62 char *tc
="/sbin/tc"; /* requires tc with HTB support */
63 char *iptables
="/usr/sbin/iptables"; /* requires iptables utility */
64 char *iptablessave
="/usr/sbin/iptables-save"; /* new */
65 char *iptablesrestore
="/usr/sbin/iptables-restore"; /* new */
66 char *iptablesfile
="/var/spool/prometheus.iptables"; /* new; file for iptables-restore*/
67 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]";
68 FILE *iptables_file
=NULL
;
69 char *html
="/var/www/traffic.html"; /* hall of fame filename */
70 char *preview
="/var/www/preview.html"; /* hall of fame preview */
71 char *cmdlog
="/var/log/prometheus"; /* command log filename */
72 char *credit
="/var/run/prometheus.credit"; /* credit log file */
73 int enable_credit
=1; /* enable credit file */
74 int use_credit
=0; /* use credit file (if enabled)*/
75 char *log_dir
="/var/www/html/logs/"; /* log directory pathname */
76 char *log_url
="logs/"; /* log directory URL prefix */
77 char *title
="Hall of Fame - Greatest Suckers"; /* hall of fame title */
78 int hall_of_fame
=1; /* enable hall of fame */
79 char *lan
="eth0"; /* LAN interface */
80 char *lan_medium
="100Mbit"; /* 10Mbit/100Mbit ethernet */
81 char *wan
="eth1"; /* WAN/ISP interface */
82 char *wan_medium
="100Mbit"; /* 10Mbit/100Mbit ethernet */
83 char *qos_leaf
="sfq perturb 5"; /* leaf discipline */
84 char *qos_free_zone
=NULL
; /* QoS free zone */
85 int qos_proxy
=1; /* include proxy port to QoS */
86 int include_upload
=1; /* upload+download=total traffic */
87 char *proxy_ip
="192.168.1.1/32"; /* our IP with proxy port */
88 int proxy_port
=3128; /* proxy port number */
89 long long int line
=1024; /* WAN/ISP download in kbps */
90 long long int up
=1024; /* WAN/ISP upload in kbps */
91 int free_min
=32; /* minimum guaranted bandwidth for all undefined hosts */
92 int free_max
=64; /* maximum allowed bandwidth for all undefined hosts */
93 int qos_free_delay
=0; /* seconds to sleep before applying new QoS rules */
94 int digital_divide
=2; /* controls digital divide weirdness ratio, 1...3 */
95 int max_nesting
=3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
97 int burst
=8; /* HTB burst (in kbits) */
100 int magic_priorities
=8; /* number of priority levels (soft shaping) */
101 int magic_treshold
=8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
104 /* not yet implemented:
105 int fixed_packets=0; maximum number of pps per IP address (not class!)
106 int packet_limit=5; maximum number of pps to htn CEIL, not rate !!!
110 char *kwd
="via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
112 const int idxtable_treshold1
=24; /* this is no longer configurable */
113 const int idxtable_treshold2
=12; /* this is no longer configurable */
114 const int idxtable_bitmask1
=3; /* this is no longer configurable */
115 const int idxtable_bitmask2
=3; /* this is no longer configurable */
118 /* not yet implemented:
119 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
120 -r just reload configuration (...and keep data transfer statistics)\n\
123 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
137 unsigned long long direct
;
138 unsigned long long proxy
;
139 unsigned long long upload
;
140 unsigned long long traffic
;
141 unsigned long long credit
;
142 unsigned long pktsup
;
143 unsigned long pktsdown
;
144 struct Keyword
*keyword
;
146 } *ips
=NULL
, *ip
, *sharedip
;
155 } *groups
=NULL
, *group
;
161 struct Index
*parent
;
165 } *idxs
=NULL
, *idx
, *metaindex
;
171 int asymetry_ratio
; /* ratio for ADSL-like upload */
172 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
173 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
174 int prio_limit
; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
175 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
176 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
177 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
178 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
179 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
180 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
181 int default_prio
; /* default HTB priority for this keyword */
184 char *leaf_discipline
;
187 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
189 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
199 ip
->mark
=ip
->min
=ip
->max
=ip
->desired
=ip
->credit
=0;
200 ip
->upload
=ip
->proxy
=ip
->direct
=ip
->traffic
=0;
201 ip
->pktsup
=ip
->pktsdown
=0;
202 ip
->keyword
=keywords
;
206 /* ====== Iptables indexes are used to reduce complexity to log8(N) ===== */
208 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
210 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
212 char *ip
,*outip
,*outptr
,*fmt
;
215 /* debug printf("(%s,%d) -> ",ip,bitmask); */
217 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
218 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
220 /* should never exit here */
227 if(dot
<(bitmask
/8-1))
229 if(format_as_chainname
)
238 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
239 if(cutdot
)*cutdot
='\0';
240 if(format_as_chainname
)
245 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
249 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
250 sprintf(outptr
,fmt
,n
,bitmask
);
251 if(!format_as_chainname
) while(bitmask
<24)
256 /* debug printf("[%s]\n",outip); */
267 /*should never exit here*/
272 char *hash_id(char *ip
,int bitmask
)
273 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
275 char *subnet_id(char *ip
,int bitmask
)
276 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
278 /* ================= Let's parse configuration file here =================== */
280 void reject_config_and_exit(char *filename
)
282 printf("Configuration file %s rejected - abnormal exit.",filename
);
286 void get_config(char *config_filename
)
290 printf("Configured keywords: ");
291 parse(config_filename
)
293 option("keyword",kwd
);
298 create(keyword
,Keyword
);
300 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
301 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
302 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
303 keyword
->prio_limit
=4; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */
304 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
305 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
306 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
307 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
309 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
310 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide
312 keyword
->default_prio
=1;
313 keyword
->html_color
="000000";
315 keyword
->leaf_discipline
="";
317 push(keyword
,keywords
);
318 if(!defaultkeyword
) defaultkeyword
=keyword
;
323 else every(keyword
,keywords
)
325 int l
=strlen(keyword
->key
);
328 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
330 char *tmptr
=_
; /* <---- l+1 ----> */
331 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
332 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
333 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
334 ioption("magic-relative-limit",keyword
->data_limit
);
335 ioption("magic-relative-prio",keyword
->prio_limit
);
336 loption("magic-fixed-limit",keyword
->fixed_limit
);
337 loption("magic-fixed-prio",keyword
->fixed_prio
);
338 ioption("htb-default-prio",keyword
->default_prio
);
339 ioption("htb-rate-bonus",keyword
->reserve_min
);
340 ioption("htb-ceil-malus",keyword
->reserve_max
);
342 ioption("htb-ceil-divide",keyword->divide_max);
343 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
345 option("leaf-discipline",keyword
->leaf_discipline
);
346 option("html-color",keyword
->html_color
);
349 if(keyword
->data_limit
|| keyword
->fixed_limit
||
350 keyword
->prio_limit
|| keyword
->fixed_prio
)
358 option("iptables",iptables
);
359 option("iptables-save",iptablessave
); /* new */
360 option("iptables-restore",iptablesrestore
); /* new */
361 option("iptables-file",iptablesfile
); /* new */
362 option("hosts",hosts
);
363 option("lan-interface",lan
);
364 option("wan-interface",wan
);
365 option("lan-medium",lan_medium
);
366 option("wan-medium",wan_medium
);
367 lloption("wan-download",line
);
368 lloption("wan-upload",up
);
369 ioption("hall-of-fame-enable",hall_of_fame
);
370 option("hall-of-fame-title",title
);
371 option("hall-of-fame-filename",html
);
372 option("hall-of-fame-preview",preview
);
373 option("log-filename",cmdlog
);
374 option("credit-filename",credit
);
375 ioption("credit-enable",enable_credit
);
376 option("log-traffic-directory",log_dir
);
377 option("log-traffic-url-path",log_url
);
378 option("qos-free-zone",qos_free_zone
);
379 ioption("qos-free-delay",qos_free_delay
);
380 ioption("qos-proxy-enable",qos_proxy
);
381 option("qos-proxy-ip",proxy_ip
);
382 option("htb-leaf-discipline",qos_leaf
);
383 ioption("qos-proxy-port",proxy_port
);
384 ioption("free-rate",free_min
);
385 ioption("free-ceil",free_max
);
386 ioption("htb-burst",burst
);
387 ioption("htb-burst-main",burst_main
);
388 ioption("htb-burst-group",burst_group
);
389 ioption("htb-nesting-limit",max_nesting
);
390 ioption("htb-r2q",htb_r2q
);
391 ioption("magic-include-upload",include_upload
);
392 ioption("magic-priorities",magic_priorities
);
393 ioption("magic-treshold",magic_treshold
);
395 option("filter-type", cnf
);
397 /* not yet implemented:
398 ioption("magic-fixed-packets",fixed_packets);
399 ioption("magic-relative-packets",packet_limit);
404 perror(config_filename
);
405 puts("Warning - using built-in defaults instead ...");
410 /*leaf discipline for keywords*/
411 every(keyword
,keywords
)
413 if (!strcmpi(keyword
->leaf_discipline
, "")){
414 keyword
->leaf_discipline
= qos_leaf
;
418 if (strcmpi(cnf
, "mark")){
421 mark_iptables
= "CLASSIFY --set-class 1:";
425 mark_iptables
= "MARK --set-mark ";
428 /* are supplied values meaningful ?*/
431 puts("Illegal value of wan bandwidth: 0 kbps.");
432 reject_config_and_exit(config_filename
);
436 /* ===================== traffic analyser - uses iptables ================ */
438 void get_traffic_statistics(void)
443 textfile(Pipe
,str
) *line
,*lines
=NULL
;
447 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
459 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
460 unsigned long long traffic
=0;
461 unsigned long pkts
=0;
462 char *ipaddr
=NULL
,*ptr
;
464 /* debug puts(line->str); */
465 valid_columns(ptr
,line
->str
,' ',col
)
466 if(valid
) switch(col
)
468 case 1: if(eq(ptr
,"Chain"))
470 else if(eq(ptr
,"pkts"))
473 sscanf(ptr
,"%lu",&pkts
);
475 case 2: if(setchainname
)
477 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
480 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
483 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
487 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
489 case 3: if(strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5) || commonflag
)
491 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
493 case 8: if(downloadflag
)
495 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
500 case 9: if(downloadflag
)ipaddr
=ptr
;break;
503 if(accept
&& traffic
>0 && ipaddr
)
505 if(proxyflag
)printf("(proxy) ");
506 else if(!downloadflag
) printf("(upload) ");
507 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
508 find(ip
,ips
,eq(ip
->addr
,ipaddr
));
513 if(eq(ip
->addr
,"0.0.0.0/0"))
515 ip
->name
="(unregistered)";
517 ip
->max
=ip
->desired
=free_max
;
526 ip
->traffic
+=traffic
;
527 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
535 ip
->traffic
+=traffic
;
537 if(traffic
>ip
->traffic
)
547 /* ========== This function executes, logs OR ALSO prints command ========== */
549 void safe_run(char *cmd
)
551 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
552 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
555 void save_line(char *line
)
557 fprintf(iptables_file
,"%s\n",line
);
560 void run_restore(void)
563 string(restor
,STRLEN
);
566 fclose(iptables_file
);
574 //sprintf(restor,"cat %s",iptablesfile); else
575 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
582 /* == This function strips extra characters after IP address and stores it = */
584 void parse_ip(char *str
)
586 char *ptr
=str
,*ipaddr
=NULL
,*ipname
=NULL
;;
588 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
594 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
597 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
601 find(ip
,ips
,eq(ip
->addr
,ipaddr
)); else TheIP();
606 char *parse_datafile_line(char *str
)
608 char *ptr
=strchr(str
,' ');
620 /*-----------------------------------------------------------------*/
621 /* Are you looking for int main (int argc, char **argv) ? :-)) */
622 /*-----------------------------------------------------------------*/
630 int class_count
=0,ip_count
=0;
634 int just_preview
=0; /* preview - generate just stats */
635 char *chain_forward
, *chain_postrouting
;
639 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
640 Version %s - Copyright (C)2005-2007 Michael Polak (xChaos)\n\
641 iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\
642 Credits: CZFree.Net, Martin Devera, Netdave, Aquarius\n\n",version
);
644 /*----- Boring... we have to check command line options first: ----*/
648 argument("-c") { nextargument(config
); }
649 argument("-h") { nextargument(althosts
);}
650 argument("-d") { dry_run
=1; }
651 argument("-f") { just_flush
=1; }
652 argument("-9") { just_flush
=9; }
653 argument("-p") { just_preview
=1; }
654 argument("-n") { nodelay
=1; }
655 argument("-?") { help(); exit(0); }
656 argument("--help") { help(); exit(0); }
657 argument("-v") { exit(0); }
658 argument("--version") { exit(0); }
662 puts("*** THIS IS JUST DRY RUN ! ***\n");
664 date(d
); /* this is typical cll1.h macro */
666 /*-----------------------------------------------------------------*/
667 printf("Parsing configuration file %s ...\n", config
);
668 /*-----------------------------------------------------------------*/
671 if(althosts
) hosts
=althosts
;
675 /*-----------------------------------------------------------------*/
676 puts("Parsing iptables verbose output ...");
677 /*-----------------------------------------------------------------*/
678 get_traffic_statistics();
681 /*-----------------------------------------------------------------*/
682 printf("Parsing class defintion file %s ...\n", hosts
);
683 /*-----------------------------------------------------------------*/
684 int groupidx
= FIRSTGROUPID
;
689 if(*str
<'0' || *str
>'9')
692 //Does this IP share QoS class with some other ?
693 substring
=strstr(str
,"sharing-");
696 substring
+=8; //"sharing-"
699 ip
->sharing
=substring
;
700 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
701 while(*substring
&& *substring
!='\n')
707 //Do we have to create new QoS class for this IP ?
709 find(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
715 ip
->prio
=keyword
->default_prio
;
716 substring
+=strlen(keyword
->key
)+1;
718 while(*ptr
&& *ptr
!='-')
723 ip
->max
=ip
->desired
=atoi(ptr
+1);
725 ip
->min
=atoi(substring
);
728 puts("Illegal value of minimum bandwidth: 0 kbps.");
729 reject_config_and_exit(hosts
);
734 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
738 ip
->max
-=ip
->keyword
->reserve_max
;
741 if(ip->keyword->divide_max>1)
742 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
743 if(ip->keyword->htb_ceil_bonus_divide>0)
744 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
749 ip
->mark
=MAX_GUARANTED_KBPS
+1+class_count
++;
751 find(group
,groups
,group
->min
==ip
->min
)
754 group
->desired
+=ip
->min
;
755 ip
->group
= group
->id
;
761 group
->id
= groupidx
++;
762 ip
->group
= group
->id
;
764 if(group
->min
<8) group
->min
=8;
765 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
766 /* it is because class IDs are derived from min. bandwidth. - xCh */
767 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
770 group
->desired
=ip
->min
;
771 insert(group
,groups
,desc_order_by
,min
);
783 /*-----------------------------------------------------------------*/
784 /* cll1.h - let's allocate brand new character buffer... */
785 /*-----------------------------------------------------------------*/
788 /*-----------------------------------------------------------------*/
789 puts("Resolving shared connections ...");
790 /*-----------------------------------------------------------------*/
791 search(ip
,ips
,ip
->sharing
)
793 search(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
795 sharedip
->traffic
+=ip
->traffic
;
797 ip
->mark
=sharedip
->mark
;
801 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
804 if(enable_credit
&& just_flush
<9)
806 /*-----------------------------------------------------------------*/
807 printf("Parsing credit file %s ...\n", credit
);
808 /*-----------------------------------------------------------------*/
811 ptr
=parse_datafile_line(_
);
814 find(ip
,ips
,eq(ip
->addr
,_
))
815 sscanf(ptr
,"%Lu",&(ip
->credit
));
823 /*-----------------------------------------------------------------*/
824 puts("Initializing iptables and tc classes ...");
825 /*-----------------------------------------------------------------*/
827 iptables_file
=fopen(iptablesfile
,"w");
828 if (iptables_file
== NULL
) {
829 puts("Cannot open iptablesfile!");
833 log_file
=fopen(cmdlog
,"w");
834 if (log_file
== NULL
) {
835 puts("Cannot open logfile!");
839 save_line(iptablespreamble
);
842 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
845 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
848 iptables_file
=fopen(iptablesfile
,"w");
849 save_line(iptablespreamble
);
851 if(qos_free_zone
&& *qos_free_zone
!='0')
855 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
860 save_line(":post_noproxy - [0:0]");
861 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
863 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
865 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
868 chain
="post_noproxy";
873 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
877 if(ip_count
>idxtable_treshold1
&& !just_flush
)
879 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
881 /*-----------------------------------------------------------------*/
882 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
883 /*-----------------------------------------------------------------*/
885 save_line(":post_common - [0:0]");
886 save_line(":forw_common - [0:0]");
888 search(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
890 buf
=hash_id(ip
->addr
,bitmask
);
891 find(idx
,idxs
,eq(idx
->id
,buf
))
898 idx
->bitmask
=bitmask
;
906 /* brutal perfomance optimalization */
907 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
909 bitmask
-=idxtable_bitmask2
;
911 search(idx
,idxs
,idx
->parent
==NULL
)
913 buf
=hash_id(idx
->addr
,bitmask
);
914 find(metaindex
,idxs
,eq(metaindex
->id
,buf
))
915 metaindex
->children
++;
918 create(metaindex
,Index
);
919 metaindex
->addr
=idx
->addr
;
921 metaindex
->bitmask
=bitmask
;
922 metaindex
->parent
=NULL
;
923 metaindex
->children
=0;
925 push(metaindex
,idxs
);
927 idx
->parent
=metaindex
;
931 /* this should slightly optimize throughout ... */
932 sort(idx
,idxs
,desc_order_by
,children
);
933 sort(idx
,idxs
,order_by
,bitmask
);
938 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
939 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
941 sprintf(str
,":post_%s - [0:0]", idx
->id
);
944 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
949 string(buf
,strlen(idx
->parent
->id
)+6);
950 sprintf(buf
,"post_%s",idx
->parent
->id
);
955 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
958 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
963 string(buf
,strlen(idx
->parent
->id
)+6);
964 sprintf(buf
,"forw_%s",idx
->parent
->id
);
969 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
972 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
975 printf("Total indexed iptables chains created: %d\n", i
);
977 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
980 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
988 fclose(iptables_file
);
989 if (log_file
) fclose(log_file
);
990 puts("Just flushed iptables and tc classes - now exiting ...");
996 if(!dry_run
&& !nodelay
&& qos_free_delay
)
998 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
999 sleep(qos_free_delay
);
1002 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1005 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_main
);
1008 sprintf(str
,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc
,lan
,line
,line
,burst_main
);
1011 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1014 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_main
);
1017 sprintf(str
,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc
,wan
,up
,up
,burst_main
);
1021 /*-----------------------------------------------------------------*/
1022 puts("Locating suckers and generating root classes ...");
1023 /*-----------------------------------------------------------------*/
1024 sort(ip
,ips
,desc_order_by
,traffic
);
1027 /*-----------------------------------------------------------------*/
1028 /* sub-scope - local variables */
1030 long long int rate
=line
;
1031 long long int max
=line
;
1033 FILE *credit_file
=NULL
;
1035 if(!just_preview
&& !dry_run
&& enable_credit
) credit_file
=fopen(credit
,"w");
1043 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #down desired %d",
1044 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, group
->desired
);
1048 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #up desired %d",
1049 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, group
->desired
);
1053 if(group_count
++<max_nesting
) parent
=group
->id
;
1055 rate
-=digital_divide
*group
->min
;
1056 if(rate
<group
->min
)rate
=group
->min
;
1058 /*shaping of aggresive downloaders, with credit file support */
1061 int group_rate
=group
->min
, priority_sequence
=magic_priorities
+1;
1063 search(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1065 if(ip
->keyword
->data_limit
>0 &&
1066 ip
->traffic
>ip
->credit
+
1067 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))
1070 if(group_rate
<ip
->max
) ip
->max
=group_rate
;
1071 group_rate
+=magic_treshold
;
1072 ip
->prio
=magic_priorities
+2;
1073 if(ip
->prio
<3) ip
->prio
=3;
1077 if(ip
->traffic
>ip
->credit
+
1078 (ip
->min
*ip
->keyword
->prio_limit
+(ip
->keyword
->fixed_prio
<<20)) &&
1081 ip
->prio
=priority_sequence
--;
1082 if(ip
->prio
<2) ip
->prio
=2;
1087 unsigned long long lcredit
=0;
1088 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1089 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1090 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1097 if(credit_file
)fclose(credit_file
);
1102 f
=fopen(preview
,"w");
1105 else if(!dry_run
&& !just_flush
)
1107 /*-----------------------------------------------------------------*/
1108 printf("Writing data transfer database ...\n");
1109 /*-----------------------------------------------------------------*/
1110 f
=fopen("/var/run/prometheus.previous","w");
1113 search(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1114 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1128 /*-----------------------------------------------------------------*/
1129 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1130 /*-----------------------------------------------------------------*/
1132 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
);
1133 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1138 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1140 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1141 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1143 every(keyword
,keywords
)
1144 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1147 total
+=group
->count
;
1151 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1153 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1154 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1156 every(keyword
,keywords
)
1157 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1159 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1160 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1162 fputs("</table>\n",f
);
1164 else if(!dry_run
&& !just_flush
)
1170 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1171 int active_classes
=0;
1174 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1181 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1182 fprintf(f
," (%s)</th></tr>\n", d
);
1183 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1184 <td align=\"right\">credit</td>\
1185 <td align=\"right\">limit</td>\
1186 <td align=\"right\">total</td>\
1187 <td align=\"right\">direct</td>\n",f
);
1189 fputs("<td align=\"right\">proxy</td>\n",f
);
1190 fputs("<td align=\"right\">upload</td>\
1191 <td align=\"right\">minimum</td>\
1192 <td align=\"right\">desired</td>\
1193 <td align=\"right\">maximum</td>\
1194 <td>prio</td></tr>\n",f
);
1198 char *f1
="", *f2
="";
1199 if(ip
->max
<ip
->desired
)
1201 f1
="<font color=\"red\">";
1206 f1
="<font color=\"brown\">";
1211 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1213 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",
1214 ip
->name
, i
, log_url
, ip
->name
, ip
->name
, ip
->credit
);
1215 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)));
1216 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1218 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1219 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1220 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
);
1222 total_direct
+=ip
->direct
;
1223 total_proxy
+=ip
->proxy
;
1224 total_upload
+=ip
->upload
;
1228 tmp_sum
+=ip
->traffic
;
1231 sum
->i
=active_classes
;
1232 insert(sum
,sums
,order_by
,i
);
1239 sprintf(str
,"%s%s.log",log_dir
,ip
->name
);
1240 iplog
=fopen(str
,"a");
1243 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
);
1249 fprintf(f
,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1250 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1251 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1253 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1254 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1255 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1257 if(active_classes
>10)
1259 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"4\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1260 fputs("<tr><td colspan=\"2\">Active Classes</td><td colspan=\"2\">Data transfers</td></tr>\n",f
);
1261 find (sum
,sums
,sum
->l
>=total
/4)
1262 fprintf(f
,"<tr><td>Top %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
);
1263 find (sum
,sums
,sum
->i
==10)
1264 fprintf(f
,"<tr><td>Top 10</td><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
);
1265 find (sum
,sums
,sum
->l
>=total
/2)
1266 fprintf(f
,"<tr><td>Top %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
);
1267 find (sum
,sums
,sum
->i
>=(active_classes
+3)/4)
1268 fprintf(f
,"<tr><td>Top %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
);
1269 find (sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1270 fprintf(f
,"<tr><td>Top %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
);
1271 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
);
1272 fputs("</table>\n",f
);
1274 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
);
1280 puts("Statistics preview generated (-p switch) - now exiting ...");
1284 /*-----------------------------------------------------------------*/
1285 puts("Generating iptables and tc classes ...");
1286 /*-----------------------------------------------------------------*/
1289 printf("%-22s %-15s mark\n","name","ip");
1290 search(ip
,ips
,ip
->mark
>0)
1296 duplicate(ip
->addr
,buf
);
1297 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1299 string(chain_forward
,6+strlen(buf
));
1300 strcpy(chain_forward
,"forw_");
1301 strcat(chain_forward
,buf
);
1303 string(chain_postrouting
,6+strlen(buf
));
1304 strcpy(chain_postrouting
,"post_");
1305 strcat(chain_postrouting
,buf
);
1311 chain_forward
="FORWARD";
1312 chain_postrouting
="POSTROUTING";
1315 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1317 /* -------------------------------------------------------- mark download */
1319 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1320 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1321 /* -m limit --limit 1/s */
1326 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
);
1327 /*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);*/
1331 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1334 /* -------------------------------------------------------- mark upload */
1335 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1336 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1339 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1344 /* -------------------------------------------------------- download class */
1345 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1347 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
);
1350 if (strcmpi(ip
->keyword
->leaf_discipline
, "none")){
1351 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*/
1355 if (filter_type
== 1){
1356 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1360 /* -------------------------------------------------------- upload class */
1361 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1362 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1364 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1365 tc
, wan
, ip
->group
, ip
->mark
,
1366 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1367 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1370 if (strcmpi(ip
->keyword
->leaf_discipline
, "none")){
1371 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*/
1375 if (filter_type
== 1){
1376 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1381 printf("(sharing %s)\n", ip
->sharing
);
1388 chain_forward
="forw_common";
1389 chain_postrouting
="post_common";
1393 chain_forward
="FORWARD";
1394 chain_postrouting
="POSTROUTING";
1397 /* -------------------------------------------------------- mark download */
1401 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j MARK --set-mark 3",chain_postrouting
,proxy_ip
,proxy_port
,lan
);
1403 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",chain_postrouting
,proxy_ip
,proxy_port
,lan
);
1406 sprintf(str
,"-A %s -o %s -j MARK --set-mark 3",chain_postrouting
,lan
);
1408 sprintf(str
,"-A %s -o %s -j ACCEPT",chain_postrouting
,lan
);
1411 /* -------------------------------------------------------- mark upload */
1412 sprintf(str
,"-A %s -o %s -j MARK --set-mark 3",chain_forward
,wan
);
1414 sprintf(str
,"-A %s -o %s -j ACCEPT",chain_forward
,wan
);
1417 printf("Total IP count: %d\n", i
);
1419 /* ---------------------------------------- tc - free bandwith shared class */
1420 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
);
1423 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
);
1427 if (strcmpi(qos_leaf
, "none")){
1428 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1431 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1435 /* tc handle 1 fw flowid */
1436 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1439 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1444 if (log_file
) fclose(log_file
);
1447 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1448 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.127958 seconds and 5 git commands to generate.