7ab712f737f15fa340c797d35e4656581e6c0273
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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
10 /* Modified by: xChaos, 20110221
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 Prometheus Qos; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 GNU General Public License is located in file COPYING */
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
34 #include "cll1-0.6.2.h"
36 const char *version
= "0.8.3";
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. */
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";
45 /* ======= All path names are defined here (for RPM patch) ======= */
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 :-) */
53 char *config
= "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts
= "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
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/";
65 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
69 puts("Command line switches:\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\
88 /* === Configuraration file values defaults - stored in global variables ==== */
90 int filter_type
= 1; /*1 mark, 2 classify*/
92 char *mark_iptables
= "MARK --set-mark ";
93 int dry_run
= 0; /* preview - use puts() instead of system() */
94 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]";
95 FILE *iptables_file
= NULL
;
96 int enable_credit
= 1; /* enable credit file */
97 int use_credit
= 0; /* use credit file (if enabled)*/
98 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
99 int hall_of_fame
= 1; /* enable hall of fame */
100 char *lan
= "eth0"; /* LAN interface */
101 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
102 char *wan
= "eth1"; /* WAN/ISP interface */
103 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
104 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
105 char *qos_free_zone
= NULL
; /* QoS free zone */
106 int qos_proxy
= 1; /* include proxy port to QoS */
107 int include_upload
= 1; /* upload+download=total traffic */
108 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
109 int proxy_port
= 3128; /* proxy port number */
110 long long int line
= 1024; /* WAN/ISP download in kbps */
111 long long int up
= 1024; /* WAN/ISP upload in kbps */
112 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
113 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
114 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
115 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
116 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
117 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
118 int burst
= 8; /* HTB burst (in kbits) */
120 int burst_group
= 32;
121 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
122 int keywordcount
= 0;
123 /* not yet implemented:
124 int fixed_packets = 0; maximum number of pps per IP address (not class!)
125 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
127 FILE *log_file
= NULL
;
128 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
130 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
131 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
132 const int idxtable_treshold1
= 24; /* this is no longer configurable */
133 const int idxtable_treshold2
= 12; /* this is no longer configurable */
134 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
135 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
137 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
152 unsigned long long direct
;
153 unsigned long long proxy
;
154 unsigned long long upload
;
155 unsigned long long traffic
;
156 unsigned long long credit
;
157 unsigned long pktsup
;
158 unsigned long pktsdown
;
159 struct Keyword
*keyword
;
161 } *ips
=NULL
, *ip
, *sharedip
;
170 } *groups
=NULL
, *group
;
176 struct Index
*parent
;
180 } *idxs
=NULL
, *idx
, *metaindex
;
186 int asymetry_ratio
; /* ratio for ADSL-like upload */
187 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
188 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
189 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
190 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
191 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
192 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
193 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
194 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
195 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
196 int default_prio
; /* default HTB priority for this keyword */
199 char *leaf_discipline
;
202 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
204 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
212 ip
->prio
= highest_priority
+1;
226 ip
->keyword
= keywords
;
230 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
232 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
234 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
236 char *ip
,*outip
,*outptr
,*fmt
;
239 /* debug printf("(%s,%d) -> ",ip,bitmask); */
241 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
243 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
247 /* should never exit here */
255 if(dot
<(bitmask
/8-1))
257 if(format_as_chainname
)
270 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
271 if(cutdot
)*cutdot
='\0';
272 if(format_as_chainname
)
277 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
281 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
282 sprintf(outptr
,fmt
,n
,bitmask
);
283 if(!format_as_chainname
) while(bitmask
<24)
288 /* debug printf("[%s]\n",outip); */
299 /*should never exit here*/
304 char *hash_id(char *ip
,int bitmask
)
305 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
307 char *subnet_id(char *ip
,int bitmask
)
308 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
310 /* ================= Let's parse configuration file here =================== */
312 void reject_config_and_exit(char *filename
)
314 printf("Configuration file %s rejected - abnormal exit.",filename
);
318 void get_config(char *config_filename
)
322 printf("Configured keywords: ");
323 parse(config_filename
)
325 option("keyword",kwd
);
330 create(keyword
,Keyword
);
332 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
333 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
334 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
335 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
336 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
337 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
338 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
339 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
340 keyword
->default_prio
=highest_priority
+1;
341 keyword
->html_color
="000000";
343 keyword
->leaf_discipline
="";
345 push(keyword
,keywords
);
346 if(!defaultkeyword
) defaultkeyword
=keyword
;
353 for_each(keyword
,keywords
)
355 int l
=strlen(keyword
->key
);
357 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
359 char *tmptr
=_
; /* <---- l+1 ----> */
360 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
361 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
362 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
363 ioption("magic-relative-limit",keyword
->data_limit
);
364 ioption("magic-relative-prio",keyword
->data_prio
);
365 loption("magic-fixed-limit",keyword
->fixed_limit
);
366 loption("magic-fixed-prio",keyword
->fixed_prio
);
367 ioption("htb-default-prio",keyword
->default_prio
);
368 ioption("htb-rate-bonus",keyword
->reserve_min
);
369 ioption("htb-ceil-malus",keyword
->reserve_max
);
370 option("leaf-discipline",keyword
->leaf_discipline
);
371 option("html-color",keyword
->html_color
);
374 if(keyword
->data_limit
|| keyword
->fixed_limit
||
375 keyword
->data_prio
|| keyword
->fixed_prio
)
384 option("iptables",iptables
);
385 option("iptables-save",iptablessave
); /* new */
386 option("iptables-restore",iptablesrestore
); /* new */
387 option("iptables-file",iptablesfile
); /* new */
388 option("hosts",hosts
);
389 option("lan-interface",lan
);
390 option("wan-interface",wan
);
391 option("lan-medium",lan_medium
);
392 option("wan-medium",wan_medium
);
393 lloption("wan-download",line
);
394 lloption("wan-upload",up
);
395 ioption("hall-of-fame-enable",hall_of_fame
);
396 option("hall-of-fame-title",title
);
397 option("hall-of-fame-filename",html
);
398 option("hall-of-fame-preview",preview
);
399 option("log-filename",cmdlog
);
400 option("credit-filename",credit
);
401 ioption("credit-enable",enable_credit
);
402 option("log-traffic-directory",log_dir
);
403 option("log-traffic-html-directory",html_log_dir
);
404 option("log-traffic-url-path",log_url
);
405 option("qos-free-zone",qos_free_zone
);
406 ioption("qos-free-delay",qos_free_delay
);
407 ioption("qos-proxy-enable",qos_proxy
);
408 option("qos-proxy-ip",proxy_ip
);
409 option("htb-leaf-discipline",qos_leaf
);
410 ioption("qos-proxy-port",proxy_port
);
411 ioption("free-rate",free_min
);
412 ioption("free-ceil",free_max
);
413 ioption("htb-burst",burst
);
414 ioption("htb-burst-main",burst_main
);
415 ioption("htb-burst-group",burst_group
);
416 ioption("htb-nesting-limit",max_nesting
);
417 ioption("htb-r2q",htb_r2q
);
418 ioption("magic-include-upload",include_upload
);
419 ioption("magic-treshold",magic_treshold
);
420 option("filter-type", cnf
);
422 /* not yet implemented:
423 ioption("magic-fixed-packets",fixed_packets);
424 ioption("magic-relative-packets",packet_limit);
429 perror(config_filename
);
430 puts("Warning - using built-in defaults instead ...");
435 /*leaf discipline for keywords*/
436 for_each(keyword
,keywords
)
438 if (!strcmpi(keyword
->leaf_discipline
, ""))
440 keyword
->leaf_discipline
= qos_leaf
;
444 if (strcmpi(cnf
, "mark"))
448 mark_iptables
= "CLASSIFY --set-class 1:";
454 mark_iptables
= "MARK --set-mark ";
457 /* are supplied values meaningful ?*/
460 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
461 reject_config_and_exit(config_filename
);
465 /* ===================== traffic analyser - uses iptables ================ */
467 void get_traffic_statistics(void)
472 textfile(Pipe
,str
) *line
,*lines
=NULL
;
476 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
488 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
489 unsigned long long traffic
=0;
490 unsigned long pkts
=0;
491 char *ipaddr
=NULL
,*ptr
;
493 /* debug puts(line->str); */
494 valid_columns(ptr
,line
->str
,' ',col
)
495 if(valid
) switch(col
)
497 case 1: if(eq(ptr
,"Chain"))
499 else if(eq(ptr
,"pkts"))
502 sscanf(ptr
,"%lu",&pkts
);
504 case 2: if(setchainname
)
506 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
509 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
512 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
516 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
518 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
520 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
522 case 8: if(downloadflag
)
524 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
529 case 9: if(downloadflag
)ipaddr
=ptr
;break;
532 if(accept
&& traffic
>0 && ipaddr
)
534 if(proxyflag
)printf("(proxy) ");
535 else if(!downloadflag
) printf("(upload) ");
536 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
538 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
543 if(eq(ip
->addr
,"0.0.0.0/0"))
545 ip
->name
="(unregistered)";
547 ip
->max
=ip
->desired
=free_max
;
556 ip
->traffic
+=traffic
;
557 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
566 ip
->traffic
+=traffic
;
570 if(traffic
>ip
->traffic
)
582 /* ========== This function executes, logs OR ALSO prints command ========== */
584 void safe_run(char *cmd
)
586 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
587 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
590 void save_line(char *line
)
592 fprintf(iptables_file
,"%s\n",line
);
595 void run_restore(void)
598 string(restor
,STRLEN
);
600 /*-----------------------------------------------------------------*/
601 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
602 /*-----------------------------------------------------------------*/
605 fclose(iptables_file
);
615 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
621 /* == This function strips extra characters after IP address and stores it = */
623 void parse_ip(char *str
)
625 char *ptr
=str
,*ipaddr
=NULL
,*ipname
=NULL
;;
627 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
633 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
636 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
640 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
649 char *parse_datafile_line(char *str
)
651 char *ptr
=strchr(str
,' ');
673 void parse_ip_log(int argc
, char **argv
)
675 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
676 long traffic
=0l, traffic_month
, total
=0, guaranted
;
677 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0;
678 char mstr
[4], ystr
[5];
681 string(filename
,STRLEN
);
683 if(argv
[1][1]=='l') /* -l */
687 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
693 if(eq(month
,"Year")) any_month
=1;
699 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
700 struct tm
*timep
= localtime(&t
);
702 if(argv
[1][1]=='m') /* -m yestarday - month */
704 strftime(mstr
, 4, "%b", timep
);
706 strftime(ystr
, 5, "%Y", timep
);
709 else /* -y yesterday - year */
713 strftime(ystr
, 5, "%Y", timep
);
717 printf("Analysing traffic for %s %s ...\n",month
,year
);
719 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
720 sprintf(str
,"%s %s/",ls
,log_dir
);
724 if(strstr(str
,".log"))
726 ptr
=strrchr(str
,'\n');
728 sprintf(filename
,"%s/%s",log_dir
,str
);
729 printf("Parsing %s ...",filename
);
736 valid_columns(ptr
,_
,'\t',col
) switch(col
)
738 case 2: name
= ptr
;break;
739 case 3: traffic
= atol(ptr
);break;
740 /* column number - was 7, now 10...*/
744 case 10: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
746 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
748 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
749 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
754 if(col
== 7) guaranted
= atol(ptr
);
760 traffic_month
+= traffic
;
770 iplog
->guaranted
= guaranted
;
771 iplog
->traffic
= traffic_month
;
772 insert(iplog
,iplogs
,desc_order_by
,traffic
);
773 printf(" %ld MB\n",iplog
->traffic
);
777 puts(" no records.");
781 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
782 printf("Writing %s ...",str
);
786 fprintf(f
,"<table border><tr><th colspan=\"2\">%s %s</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",month
,year
);
788 for_each(iplog
,iplogs
)
792 fprintf(f
,"<tr><td align=\"right\">%d</td><th align=\"left\">%s</td><td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
793 i
++, iplog
->name
, iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
794 total
+=iplog
->traffic
>>10;
799 fprintf(f
,"<tr><th colspan=\"3\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total
, line
);
800 fputs("</table>\n", f
);
804 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
805 fputs("<tr><td>Analytic category</td>\n",f
);
806 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
808 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
810 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
811 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
));
814 if_exists(iplog
,iplogs
,iplog
->i
==10)
816 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
817 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
));
820 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
822 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
823 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
));
826 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
828 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
829 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
));
832 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
834 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
835 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
));
838 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
840 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
841 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
));
844 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
846 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
847 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
));
850 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
852 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
853 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
));
856 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
857 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
);
858 fputs("</table>\n", f
);
861 fprintf(f
, stats_html_signature
, version
);
867 /*-----------------------------------------------------------------*/
868 /* Are you looking for int main(int argc, char **argv) ? :-)) */
869 /*-----------------------------------------------------------------*/
877 int class_count
=0,ip_count
=0;
879 int just_flush
=FALSE
;
881 int just_preview
=FALSE
; /* preview - generate just stats */
882 int just_logs
=FALSE
; /* just parse logs */
885 char *chain_forward
, *chain_postrouting
;
889 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
890 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
891 iptables-restore & burst tunning & classify modification by Ludva\n\
892 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
894 /*----- Boring... we have to check command line options first: ----*/
898 argument("-c") { nextargument(config
); }
899 argument("-h") { nextargument(althosts
);}
900 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
901 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
902 argument("-9") { run
=TRUE
; just_flush
=9; }
903 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
904 argument("-r") { run
=TRUE
; }
905 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
906 argument("-l") { just_logs
=TRUE
; }
907 argument("-m") { just_logs
=TRUE
; }
908 argument("-y") { just_logs
=TRUE
; }
909 argument("-?") { help(); exit(0); }
910 argument("--help") { help(); exit(0); }
911 argument("-v") { exit(0); }
912 argument("--version") { exit(0); }
917 puts("*** THIS IS JUST DRY RUN ! ***\n");
920 date(d
); /* this is typical cll1.h macro - prints current date */
922 /*-----------------------------------------------------------------*/
923 printf("Parsing configuration file %s ...\n", config
);
924 /*-----------------------------------------------------------------*/
929 parse_ip_log(argc
,argv
);
945 /*-----------------------------------------------------------------*/
946 puts("Parsing iptables verbose output ...");
947 /*-----------------------------------------------------------------*/
948 get_traffic_statistics();
951 /*-----------------------------------------------------------------*/
952 printf("Parsing class defintion file %s ...\n", hosts
);
953 /*-----------------------------------------------------------------*/
954 int groupidx
= FIRSTGROUPID
;
959 if(*str
<'0' || *str
>'9')
962 //Does this IP share QoS class with some other ?
963 substring
=strstr(str
,"sharing-");
966 substring
+=8; //"sharing-"
969 ip
->sharing
=substring
;
970 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
971 while(*substring
&& *substring
!='\n')
977 //Do we have to create new QoS class for this IP ?
979 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
985 ip
->prio
=keyword
->default_prio
;
986 substring
+=strlen(keyword
->key
)+1;
988 while(*ptr
&& *ptr
!='-')
995 ip
->max
=ip
->desired
=atoi(ptr
+1);
997 ip
->min
=atoi(substring
);
1000 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
1003 if(ip
->max
<=ip
->min
)
1006 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
1010 ip
->max
-=ip
->keyword
->reserve_max
;
1016 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1018 if_exists(group
,groups
,group
->min
==ip
->min
)
1021 group
->desired
+=ip
->min
;
1022 ip
->group
= group
->id
;
1026 create(group
,Group
);
1028 group
->id
= groupidx
++;
1029 ip
->group
= group
->id
;
1031 if(group
->min
<8) group
->min
=8;
1032 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1033 /* it is because class IDs are derived from min. bandwidth. - xCh */
1034 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1037 group
->desired
=ip
->min
;
1038 insert(group
,groups
,desc_order_by
,min
);
1050 /*-----------------------------------------------------------------*/
1051 /* cll1.h - let's allocate brand new character buffer... */
1052 /*-----------------------------------------------------------------*/
1055 /*-----------------------------------------------------------------*/
1056 puts("Resolving shared connections ...");
1057 /*-----------------------------------------------------------------*/
1058 for_selected(ip
,ips
,ip
->sharing
)
1060 for_selected(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
1062 sharedip
->traffic
+=ip
->traffic
;
1064 ip
->mark
=sharedip
->mark
;
1069 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1073 if(enable_credit
&& just_flush
<9)
1075 /*-----------------------------------------------------------------*/
1076 printf("Parsing credit file %s ...\n", credit
);
1077 /*-----------------------------------------------------------------*/
1080 ptr
=parse_datafile_line(_
);
1083 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1085 sscanf(ptr
,"%Lu",&(ip
->credit
));
1094 /*-----------------------------------------------------------------*/
1095 puts("Initializing iptables and tc classes ...");
1096 /*-----------------------------------------------------------------*/
1098 iptables_file
=fopen(iptablesfile
,"w");
1099 if (iptables_file
== NULL
)
1101 puts("Cannot open iptablesfile!");
1105 log_file
=fopen(cmdlog
,"w");
1106 if (log_file
== NULL
)
1108 puts("Cannot open logfile!");
1112 save_line(iptablespreamble
);
1115 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1118 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1121 iptables_file
=fopen(iptablesfile
,"w");
1122 save_line(iptablespreamble
);
1124 if(qos_free_zone
&& *qos_free_zone
!='0')
1128 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1133 save_line(":post_noproxy - [0:0]");
1134 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1136 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1138 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1141 chain
="post_noproxy";
1145 chain
="POSTROUTING";
1148 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1152 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1154 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1156 /*-----------------------------------------------------------------*/
1157 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1158 /*-----------------------------------------------------------------*/
1160 save_line(":post_common - [0:0]");
1161 save_line(":forw_common - [0:0]");
1163 for_selected(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1165 buf
=hash_id(ip
->addr
,bitmask
);
1166 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1175 idx
->bitmask
=bitmask
;
1183 /* brutal perfomance optimalization */
1184 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1186 bitmask
-=idxtable_bitmask2
;
1189 for_selected(idx
,idxs
,idx
->parent
==NULL
)
1191 buf
=hash_id(idx
->addr
,bitmask
);
1192 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1194 metaindex
->children
++;
1198 create(metaindex
,Index
);
1199 metaindex
->addr
=idx
->addr
;
1201 metaindex
->bitmask
=bitmask
;
1202 metaindex
->parent
=NULL
;
1203 metaindex
->children
=0;
1205 push(metaindex
,idxs
);
1207 idx
->parent
=metaindex
;
1211 /* this should slightly optimize throughout ... */
1212 sort(idx
,idxs
,desc_order_by
,children
);
1213 sort(idx
,idxs
,order_by
,bitmask
);
1218 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1219 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1221 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1224 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1229 string(buf
,strlen(idx
->parent
->id
)+6);
1230 sprintf(buf
,"post_%s",idx
->parent
->id
);
1237 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1240 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1245 string(buf
,strlen(idx
->parent
->id
)+6);
1246 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1253 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1256 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1259 printf("Total indexed iptables chains created: %d\n", i
);
1261 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1264 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1272 fclose(iptables_file
);
1273 if (log_file
) fclose(log_file
);
1274 puts("Just flushed iptables and tc classes - now exiting ...");
1280 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1282 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1283 sleep(qos_free_delay
);
1286 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1289 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1290 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1293 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1294 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1297 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1300 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1301 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1304 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1305 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1309 /*-----------------------------------------------------------------*/
1310 puts("Locating heavy downloaders and generating root classes ...");
1311 /*-----------------------------------------------------------------*/
1312 sort(ip
,ips
,desc_order_by
,traffic
);
1314 /*-----------------------------------------------------------------*/
1315 /* sub-scope - local variables */
1317 long long int rate
=line
;
1318 long long int max
=line
;
1320 FILE *credit_file
=NULL
;
1322 if(!just_preview
&& !dry_run
&& enable_credit
) credit_file
=fopen(credit
,"w");
1324 for_each(group
,groups
)
1329 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",
1330 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1334 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",
1335 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1339 if(group_count
++<max_nesting
)
1344 rate
-=digital_divide
*group
->min
;
1345 if(rate
<group
->min
)rate
=group
->min
;
1347 /*shaping of aggresive downloaders, with credit file support */
1350 int group_rate
=group
->min
, priority_sequence
=lowest_priority
;
1352 for_selected(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1354 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
&&
1355 ip
->traffic
>ip
->credit
+
1356 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)) )
1358 if(group_rate
<ip
->max
) ip
->max
=group_rate
;
1359 group_rate
+=magic_treshold
;
1360 ip
->prio
=lowest_priority
;
1361 if(ip
->prio
<highest_priority
+2) ip
->prio
=highest_priority
+2;
1365 if( ip
->keyword
->data_prio
&& !ip
->fixedprio
&&
1366 ip
->traffic
>ip
->credit
+
1367 (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20)) )
1369 ip
->prio
=priority_sequence
--;
1370 if(ip
->prio
<highest_priority
+1) ip
->prio
=highest_priority
+1;
1375 unsigned long long lcredit
=0;
1377 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1378 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1379 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1386 if(credit_file
)fclose(credit_file
);
1391 f
=fopen(preview
,"w");
1394 else if(!dry_run
&& !just_flush
)
1396 /*-----------------------------------------------------------------*/
1397 printf("Writing data transfer database ...\n");
1398 /*-----------------------------------------------------------------*/
1399 f
=fopen("/var/run/prometheus.previous","w");
1402 for_selected(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1403 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1417 /*-----------------------------------------------------------------*/
1418 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1419 /*-----------------------------------------------------------------*/
1421 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
);
1422 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1425 for_each(group
,groups
)
1428 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1430 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1431 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1433 for_each(keyword
,keywords
)
1435 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1438 total
+=group
->count
;
1442 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1444 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1445 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1447 for_each(keyword
,keywords
)
1449 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1451 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1452 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1454 fputs("</table>\n",f
);
1456 else if(!dry_run
&& !just_flush
)
1462 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1463 int active_classes
=0;
1466 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1473 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1474 fprintf(f
," (%s)</th></tr>\n", d
);
1475 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1476 <td align=\"right\">credit</td>\
1477 <td align=\"right\">limit</td>\
1478 <td align=\"right\">total</td>\
1479 <td align=\"right\">direct</td>\n",f
);
1481 fputs("<td align=\"right\">proxy</td>\n",f
);
1482 fputs("<td align=\"right\">upload</td>\
1483 <td align=\"right\">minimum</td>\
1484 <td align=\"right\">desired</td>\
1485 <td align=\"right\">maximum</td>\
1486 <td>prio</td></tr>\n",f
);
1490 char *f1
="", *f2
="";
1491 if(ip
->max
<ip
->desired
)
1493 f1
="<font color=\"red\">";
1496 else if(ip
->prio
>highest_priority
+1)
1498 f1
="<font color=\"brown\">";
1503 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1505 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",
1506 ip
->name
, i
, log_url
, ip
->name
, ip
->name
, ip
->credit
);
1507 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)));
1508 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1510 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1511 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1512 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
);
1514 total_direct
+=ip
->direct
;
1515 total_proxy
+=ip
->proxy
;
1516 total_upload
+=ip
->upload
;
1520 tmp_sum
+=ip
->traffic
;
1523 sum
->i
=active_classes
;
1524 insert(sum
,sums
,order_by
,i
);
1531 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1532 iplog
=fopen(str
,"a");
1535 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%s",
1536 time(NULL
),ip
->name
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
,ip
->min
,ip
->max
,ip
->desired
,d
); /* d = date*/
1542 fprintf(f
,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1543 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1544 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1546 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1547 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1548 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1550 if(active_classes
>10)
1552 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1553 fputs("<tr><td>Analytic category</td>\n",f
);
1554 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1556 if_exists(sum
,sums
,sum
->l
>=total
/4)
1558 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1559 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
);
1562 if_exists(sum
,sums
,sum
->i
==10)
1564 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1565 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
);
1568 if_exists(sum
,sums
,sum
->l
>=total
/2)
1570 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1571 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
);
1574 if_exists(sum
,sums
,sum
->l
>=4*total
/5)
1576 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1577 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
);
1580 if_exists (sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1582 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1583 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
);
1586 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1588 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1589 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
);
1592 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1594 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1595 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
);
1598 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1600 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1601 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
);
1604 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
1605 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
);
1606 fputs("</table>\n", f
);
1608 fprintf(f
, stats_html_signature
, version
);
1614 puts("Statistics preview generated (-p switch) - now exiting ...");
1618 /*-----------------------------------------------------------------*/
1619 puts("Generating iptables and tc classes ...");
1620 /*-----------------------------------------------------------------*/
1623 printf("%-22s %-15s mark\n","name","ip");
1625 for_selected(ip
,ips
,ip
->mark
>0)
1631 duplicate(ip
->addr
,buf
);
1632 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1634 string(chain_forward
,6+strlen(buf
));
1635 strcpy(chain_forward
,"forw_");
1636 strcat(chain_forward
,buf
);
1638 string(chain_postrouting
,6+strlen(buf
));
1639 strcpy(chain_postrouting
,"post_");
1640 strcat(chain_postrouting
,buf
);
1646 chain_forward
="FORWARD";
1647 chain_postrouting
="POSTROUTING";
1650 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1652 /* -------------------------------------------------------- mark download */
1654 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1655 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1656 /* -m limit --limit 1/s */
1661 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
);
1662 /*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);*/
1666 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1669 /* -------------------------------------------------------- mark upload */
1670 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1671 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1674 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1679 /* -------------------------------------------------------- download class */
1680 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1682 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
);
1685 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1687 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*/
1690 if (filter_type
== 1)
1692 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1696 /* -------------------------------------------------------- upload class */
1697 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1698 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1700 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1701 tc
, wan
, ip
->group
, ip
->mark
,
1702 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1703 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1706 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1708 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*/
1711 if (filter_type
== 1)
1713 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1718 printf("(sharing %s)\n", ip
->sharing
);
1724 chain_forward
= "forw_common";
1725 chain_postrouting
= "post_common";
1729 chain_forward
= "FORWARD";
1730 chain_postrouting
= "POSTROUTING";
1732 /* -------------------------------- classify or reject free download */
1734 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1735 if(free_min
) final_chain
= "ACCEPT";
1740 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);
1743 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1748 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1751 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1753 /* ------------------------------- classify or reject free upload */
1756 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1759 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1763 if(free_min
) /* allocate free bandwith if it is not zero... */
1765 /*-----------------------------------------------------------------*/
1766 puts("Generating free bandwith classes ...");
1767 /*-----------------------------------------------------------------*/
1768 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1769 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1771 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1772 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1775 if (strcmpi(qos_leaf
, "none"))
1777 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1780 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1783 /* tc handle 1 fw flowid */
1784 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1787 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1790 printf("Total IP count: %d\n", i
);
1792 if (log_file
) fclose(log_file
);
1794 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1795 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.492458 seconds and 3 git commands to generate.