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, 20110427
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 found_lmsid
= 0; /* show links to users in LMS information system */
108 int include_upload
= 1; /* upload+download=total traffic */
109 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
110 int proxy_port
= 3128; /* proxy port number */
111 long long int line
= 1024; /* WAN/ISP download in kbps */
112 long long int up
= 1024; /* WAN/ISP upload in kbps */
113 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
114 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
115 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
116 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
117 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
118 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
119 int burst
= 8; /* HTB burst (in kbits) */
121 int burst_group
= 32;
122 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
123 int keywordcount
= 0;
124 /* not yet implemented:
125 int fixed_packets = 0; maximum number of pps per IP address (not class!)
126 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
128 FILE *log_file
= NULL
;
129 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
131 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
132 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
133 const int idxtable_treshold1
= 24; /* this is no longer configurable */
134 const int idxtable_treshold2
= 12; /* this is no longer configurable */
135 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
136 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
138 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
153 unsigned long long direct
;
154 unsigned long long proxy
;
155 unsigned long long upload
;
156 unsigned long long traffic
;
157 unsigned long long credit
;
158 unsigned long pktsup
;
159 unsigned long pktsdown
;
160 struct Keyword
*keyword
;
162 } *ips
=NULL
, *ip
, *sharedip
;
171 } *groups
=NULL
, *group
;
177 struct Index
*parent
;
181 } *idxs
=NULL
, *idx
, *metaindex
;
187 int asymetry_ratio
; /* ratio for ADSL-like upload */
188 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
189 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
190 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
191 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
192 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
193 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
194 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
195 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
196 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
197 int default_prio
; /* default HTB priority for this keyword */
200 char *leaf_discipline
;
203 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
205 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
213 ip
->prio
= highest_priority
+1;
227 ip
->keyword
= keywords
;
231 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
233 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
235 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
237 char *ip
,*outip
,*outptr
,*fmt
;
240 /* debug printf("(%s,%d) -> ",ip,bitmask); */
242 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
244 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
248 /* should never exit here */
256 if(dot
<(bitmask
/8-1))
258 if(format_as_chainname
)
271 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
272 if(cutdot
)*cutdot
='\0';
273 if(format_as_chainname
)
278 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
282 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
283 sprintf(outptr
,fmt
,n
,bitmask
);
284 if(!format_as_chainname
) while(bitmask
<24)
289 /* debug printf("[%s]\n",outip); */
300 /*should never exit here*/
305 char *hash_id(char *ip
,int bitmask
)
306 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
308 char *subnet_id(char *ip
,int bitmask
)
309 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
311 /* ================= Let's parse configuration file here =================== */
313 void reject_config_and_exit(char *filename
)
315 printf("Configuration file %s rejected - abnormal exit.",filename
);
319 void get_config(char *config_filename
)
323 printf("Configured keywords: ");
324 parse(config_filename
)
326 option("keyword",kwd
);
331 create(keyword
,Keyword
);
333 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
334 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
335 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
336 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
337 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
338 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
339 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
340 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
341 keyword
->default_prio
=highest_priority
+1;
342 keyword
->html_color
="000000";
344 keyword
->leaf_discipline
="";
346 push(keyword
,keywords
);
347 if(!defaultkeyword
) defaultkeyword
=keyword
;
354 for_each(keyword
,keywords
)
356 int l
=strlen(keyword
->key
);
358 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
360 char *tmptr
=_
; /* <---- l+1 ----> */
361 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
362 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
363 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
364 ioption("magic-relative-limit",keyword
->data_limit
);
365 ioption("magic-relative-prio",keyword
->data_prio
);
366 loption("magic-fixed-limit",keyword
->fixed_limit
);
367 loption("magic-fixed-prio",keyword
->fixed_prio
);
368 ioption("htb-default-prio",keyword
->default_prio
);
369 ioption("htb-rate-bonus",keyword
->reserve_min
);
370 ioption("htb-ceil-malus",keyword
->reserve_max
);
371 option("leaf-discipline",keyword
->leaf_discipline
);
372 option("html-color",keyword
->html_color
);
375 if(keyword
->data_limit
|| keyword
->fixed_limit
||
376 keyword
->data_prio
|| keyword
->fixed_prio
)
385 option("iptables",iptables
);
386 option("iptables-save",iptablessave
); /* new */
387 option("iptables-restore",iptablesrestore
); /* new */
388 option("iptables-file",iptablesfile
); /* new */
389 option("hosts",hosts
);
390 option("lan-interface",lan
);
391 option("wan-interface",wan
);
392 option("lan-medium",lan_medium
);
393 option("wan-medium",wan_medium
);
394 lloption("wan-download",line
);
395 lloption("wan-upload",up
);
396 ioption("hall-of-fame-enable",hall_of_fame
);
397 option("hall-of-fame-title",title
);
398 option("hall-of-fame-filename",html
);
399 option("hall-of-fame-preview",preview
);
400 option("log-filename",cmdlog
);
401 option("credit-filename",credit
);
402 ioption("credit-enable",enable_credit
);
403 option("log-traffic-directory",log_dir
);
404 option("log-traffic-html-directory",html_log_dir
);
405 option("log-traffic-url-path",log_url
);
406 option("qos-free-zone",qos_free_zone
);
407 ioption("qos-free-delay",qos_free_delay
);
408 ioption("qos-proxy-enable",qos_proxy
);
409 option("qos-proxy-ip",proxy_ip
);
410 option("htb-leaf-discipline",qos_leaf
);
411 ioption("qos-proxy-port",proxy_port
);
412 ioption("free-rate",free_min
);
413 ioption("free-ceil",free_max
);
414 ioption("htb-burst",burst
);
415 ioption("htb-burst-main",burst_main
);
416 ioption("htb-burst-group",burst_group
);
417 ioption("htb-nesting-limit",max_nesting
);
418 ioption("htb-r2q",htb_r2q
);
419 ioption("magic-include-upload",include_upload
);
420 ioption("magic-treshold",magic_treshold
);
421 option("filter-type", cnf
);
423 /* not yet implemented:
424 ioption("magic-fixed-packets",fixed_packets);
425 ioption("magic-relative-packets",packet_limit);
430 perror(config_filename
);
431 puts("Warning - using built-in defaults instead ...");
436 /*leaf discipline for keywords*/
437 for_each(keyword
,keywords
)
439 if (!strcmpi(keyword
->leaf_discipline
, ""))
441 keyword
->leaf_discipline
= qos_leaf
;
445 if (strcmpi(cnf
, "mark"))
449 mark_iptables
= "CLASSIFY --set-class 1:";
455 mark_iptables
= "MARK --set-mark ";
458 /* are supplied values meaningful ?*/
461 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
462 reject_config_and_exit(config_filename
);
466 /* ===================== traffic analyser - uses iptables ================ */
468 void get_traffic_statistics(void)
473 textfile(Pipe
,str
) *line
,*lines
=NULL
;
477 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
489 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
490 unsigned long long traffic
=0;
491 unsigned long pkts
=0;
492 char *ipaddr
=NULL
,*ptr
;
494 /* debug puts(line->str); */
495 valid_columns(ptr
,line
->str
,' ',col
)
496 if(valid
) switch(col
)
498 case 1: if(eq(ptr
,"Chain"))
500 else if(eq(ptr
,"pkts"))
503 sscanf(ptr
,"%lu",&pkts
);
505 case 2: if(setchainname
)
507 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
510 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
513 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
517 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
519 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
521 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
523 case 8: if(downloadflag
)
525 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
530 case 9: if(downloadflag
)ipaddr
=ptr
;break;
533 if(accept
&& traffic
>0 && ipaddr
)
535 if(proxyflag
)printf("(proxy) ");
536 else if(!downloadflag
) printf("(upload) ");
537 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
539 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
544 if(eq(ip
->addr
,"0.0.0.0/0"))
546 ip
->name
="(unregistered)";
548 ip
->max
=ip
->desired
=free_max
;
557 ip
->traffic
+=traffic
;
558 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
567 ip
->traffic
+=traffic
;
571 if(traffic
>ip
->traffic
)
583 /* ========== This function executes, logs OR ALSO prints command ========== */
585 void safe_run(char *cmd
)
587 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
588 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
591 void save_line(char *line
)
593 fprintf(iptables_file
,"%s\n",line
);
596 void run_restore(void)
599 string(restor
,STRLEN
);
601 /*-----------------------------------------------------------------*/
602 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
603 /*-----------------------------------------------------------------*/
606 fclose(iptables_file
);
616 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
622 /* == This function strips extra characters after IP address and stores it = */
624 void parse_ip(char *str
)
626 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
632 while(*ptr
&& *ptr
!='}')
638 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
644 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
647 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
651 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
660 ip
->lmsid
=atoi(lmsid
);
665 char *parse_datafile_line(char *str
)
667 char *ptr
=strchr(str
,' ');
691 void parse_ip_log(int argc
, char **argv
)
693 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
694 long traffic
=0l, traffic_month
, total
=0, guaranted
;
695 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
696 char mstr
[4], ystr
[5];
699 string(filename
,STRLEN
);
701 if(argv
[1][1]=='l') /* -l */
705 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
711 if(eq(month
,"Year")) any_month
=1;
717 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
718 struct tm
*timep
= localtime(&t
);
720 if(argv
[1][1]=='m') /* -m yestarday - month */
722 strftime(mstr
, 4, "%b", timep
);
724 strftime(ystr
, 5, "%Y", timep
);
727 else /* -y yesterday - year */
731 strftime(ystr
, 5, "%Y", timep
);
735 printf("Analysing traffic for %s %s ...\n",month
,year
);
737 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
738 sprintf(str
,"%s %s/",ls
,log_dir
);
742 if(strstr(str
,".log"))
744 ptr
=strrchr(str
,'\n');
746 sprintf(filename
,"%s/%s",log_dir
,str
);
747 printf("Parsing %s ...",filename
);
755 valid_columns(ptr
,_
,'\t',col
) switch(col
)
757 case 2: name
= ptr
;break;
758 case 3: traffic
= atol(ptr
);break;
759 /* column number - was 7, now 11...*/
764 case 11: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
766 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
768 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
769 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
774 if(col
== 7) guaranted
= atol(ptr
);
775 if(col
== 10) lmsid
= atoi(ptr
);
781 traffic_month
+= traffic
;
791 iplog
->guaranted
= guaranted
;
792 iplog
->traffic
= traffic_month
;
793 insert(iplog
,iplogs
,desc_order_by
,traffic
);
794 printf(" %ld MB\n",iplog
->traffic
);
798 puts(" no records.");
802 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
803 printf("Writing %s ...",str
);
807 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
);
809 for_each(iplog
,iplogs
)
813 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",
814 i
++, iplog
->name
, iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
815 total
+=iplog
->traffic
>>10;
820 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
);
821 fputs("</table>\n", f
);
825 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
826 fputs("<tr><td>Analytic category</td>\n",f
);
827 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
829 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
831 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
832 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
));
835 if_exists(iplog
,iplogs
,iplog
->i
==10)
837 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
838 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
));
841 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
843 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
844 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
));
847 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
849 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
850 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
));
853 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
855 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
856 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
));
859 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
861 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
862 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
));
865 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
867 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
868 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
));
871 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
873 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
874 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
));
877 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
878 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
);
879 fputs("</table>\n", f
);
882 fprintf(f
, stats_html_signature
, version
);
888 /*-----------------------------------------------------------------*/
889 /* Are you looking for int main(int argc, char **argv) ? :-)) */
890 /*-----------------------------------------------------------------*/
898 int class_count
=0,ip_count
=0;
900 int just_flush
=FALSE
;
902 int just_preview
=FALSE
; /* preview - generate just stats */
903 int just_logs
=FALSE
; /* just parse logs */
906 char *chain_forward
, *chain_postrouting
;
910 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
911 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
912 iptables-restore & burst tunning & classify modification by Ludva\n\
913 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
915 /*----- Boring... we have to check command line options first: ----*/
919 argument("-c") { nextargument(config
); }
920 argument("-h") { nextargument(althosts
);}
921 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
922 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
923 argument("-9") { run
=TRUE
; just_flush
=9; }
924 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
925 argument("-r") { run
=TRUE
; }
926 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
927 argument("-l") { just_logs
=TRUE
; }
928 argument("-m") { just_logs
=TRUE
; }
929 argument("-y") { just_logs
=TRUE
; }
930 argument("-?") { help(); exit(0); }
931 argument("--help") { help(); exit(0); }
932 argument("-v") { exit(0); }
933 argument("--version") { exit(0); }
938 puts("*** THIS IS JUST DRY RUN ! ***\n");
941 date(d
); /* this is typical cll1.h macro - prints current date */
943 /*-----------------------------------------------------------------*/
944 printf("Parsing configuration file %s ...\n", config
);
945 /*-----------------------------------------------------------------*/
950 parse_ip_log(argc
,argv
);
966 /*-----------------------------------------------------------------*/
967 puts("Parsing iptables verbose output ...");
968 /*-----------------------------------------------------------------*/
969 get_traffic_statistics();
972 /*-----------------------------------------------------------------*/
973 printf("Parsing class defintion file %s ...\n", hosts
);
974 /*-----------------------------------------------------------------*/
975 int groupidx
= FIRSTGROUPID
;
980 if(*str
<'0' || *str
>'9')
982 /* any line starting with non-number is comment ...*/
986 //Does this IP share QoS class with some other ?
987 substring
=strstr(str
,"sharing-");
990 substring
+=8; //"sharing-"
993 ip
->sharing
=substring
;
994 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
995 while(*substring
&& *substring
!='\n')
1003 //Do we have to create new QoS class for this IP ?
1005 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1009 ip
->keyword
=keyword
;
1010 keyword
->ip_count
++;
1011 ip
->prio
=keyword
->default_prio
;
1012 substring
+=strlen(keyword
->key
)+1;
1014 while(*ptr
&& *ptr
!='-')
1021 ip
->max
=ip
->desired
=atoi(ptr
+1);
1023 ip
->min
=atoi(substring
);
1026 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
1029 if(ip
->max
<=ip
->min
)
1032 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
1036 ip
->max
-=ip
->keyword
->reserve_max
;
1042 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1044 if_exists(group
,groups
,group
->min
==ip
->min
)
1047 group
->desired
+=ip
->min
;
1048 ip
->group
= group
->id
;
1052 create(group
,Group
);
1054 group
->id
= groupidx
++;
1055 ip
->group
= group
->id
;
1057 if(group
->min
<8) group
->min
=8;
1058 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1059 /* it is because class IDs are derived from min. bandwidth. - xCh */
1060 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1063 group
->desired
=ip
->min
;
1064 insert(group
,groups
,desc_order_by
,min
);
1076 /*-----------------------------------------------------------------*/
1077 /* cll1.h - let's allocate brand new character buffer... */
1078 /*-----------------------------------------------------------------*/
1081 /*-----------------------------------------------------------------*/
1082 puts("Resolving shared connections ...");
1083 /*-----------------------------------------------------------------*/
1084 for_selected(ip
,ips
,ip
->sharing
)
1086 for_selected(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
1088 sharedip
->traffic
+=ip
->traffic
;
1090 ip
->mark
=sharedip
->mark
;
1095 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1099 if(enable_credit
&& just_flush
<9)
1101 /*-----------------------------------------------------------------*/
1102 printf("Parsing credit file %s ...\n", credit
);
1103 /*-----------------------------------------------------------------*/
1106 ptr
=parse_datafile_line(_
);
1109 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1111 sscanf(ptr
,"%Lu",&(ip
->credit
));
1120 /*-----------------------------------------------------------------*/
1121 puts("Initializing iptables and tc classes ...");
1122 /*-----------------------------------------------------------------*/
1124 iptables_file
=fopen(iptablesfile
,"w");
1125 if (iptables_file
== NULL
)
1127 puts("Cannot open iptablesfile!");
1131 log_file
=fopen(cmdlog
,"w");
1132 if (log_file
== NULL
)
1134 puts("Cannot open logfile!");
1138 save_line(iptablespreamble
);
1141 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1144 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1147 iptables_file
=fopen(iptablesfile
,"w");
1148 save_line(iptablespreamble
);
1150 if(qos_free_zone
&& *qos_free_zone
!='0')
1154 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1159 save_line(":post_noproxy - [0:0]");
1160 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1162 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1164 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1167 chain
="post_noproxy";
1171 chain
="POSTROUTING";
1174 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1178 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1180 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1182 /*-----------------------------------------------------------------*/
1183 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1184 /*-----------------------------------------------------------------*/
1186 save_line(":post_common - [0:0]");
1187 save_line(":forw_common - [0:0]");
1189 for_selected(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1191 buf
=hash_id(ip
->addr
,bitmask
);
1192 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1201 idx
->bitmask
=bitmask
;
1209 /* brutal perfomance optimalization */
1210 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1212 bitmask
-=idxtable_bitmask2
;
1215 for_selected(idx
,idxs
,idx
->parent
==NULL
)
1217 buf
=hash_id(idx
->addr
,bitmask
);
1218 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1220 metaindex
->children
++;
1224 create(metaindex
,Index
);
1225 metaindex
->addr
=idx
->addr
;
1227 metaindex
->bitmask
=bitmask
;
1228 metaindex
->parent
=NULL
;
1229 metaindex
->children
=0;
1231 push(metaindex
,idxs
);
1233 idx
->parent
=metaindex
;
1237 /* this should slightly optimize throughout ... */
1238 sort(idx
,idxs
,desc_order_by
,children
);
1239 sort(idx
,idxs
,order_by
,bitmask
);
1244 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1245 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1247 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1250 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1255 string(buf
,strlen(idx
->parent
->id
)+6);
1256 sprintf(buf
,"post_%s",idx
->parent
->id
);
1263 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1266 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1271 string(buf
,strlen(idx
->parent
->id
)+6);
1272 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1279 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1282 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1285 printf("Total indexed iptables chains created: %d\n", i
);
1287 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1290 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1298 fclose(iptables_file
);
1299 if (log_file
) fclose(log_file
);
1300 puts("Just flushed iptables and tc classes - now exiting ...");
1306 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1308 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1309 sleep(qos_free_delay
);
1312 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1315 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1316 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1319 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1320 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1323 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1326 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1327 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1330 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1331 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1335 /*-----------------------------------------------------------------*/
1336 puts("Locating heavy downloaders and generating root classes ...");
1337 /*-----------------------------------------------------------------*/
1338 sort(ip
,ips
,desc_order_by
,traffic
);
1340 /*-----------------------------------------------------------------*/
1341 /* sub-scope - local variables */
1343 long long int rate
=line
;
1344 long long int max
=line
;
1346 FILE *credit_file
=NULL
;
1348 if(!just_preview
&& !dry_run
&& enable_credit
)
1350 credit_file
=fopen(credit
,"w");
1353 for_each(group
,groups
)
1358 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",
1359 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1363 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",
1364 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1368 if(group_count
++<max_nesting
)
1373 rate
-=digital_divide
*group
->min
;
1379 /*shaping of aggresive downloaders, with credit file support */
1382 int group_rate
=group
->min
, priority_sequence
=lowest_priority
;
1384 for_selected(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1386 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
&&
1387 ip
->traffic
>ip
->credit
+
1388 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)) )
1390 if(group_rate
<ip
->max
)
1394 group_rate
+=magic_treshold
;
1395 ip
->prio
=lowest_priority
;
1396 if(ip
->prio
<highest_priority
+2)
1398 ip
->prio
=highest_priority
+2;
1403 if( ip
->keyword
->data_prio
&& !ip
->fixedprio
&&
1404 ip
->traffic
>ip
->credit
+
1405 (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20)) )
1407 ip
->prio
=priority_sequence
--;
1408 if(ip
->prio
<highest_priority
+1)
1410 ip
->prio
=highest_priority
+1;
1416 unsigned long long lcredit
=0;
1418 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1420 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1422 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1431 fclose(credit_file
);
1437 f
=fopen(preview
,"w");
1440 else if(!dry_run
&& !just_flush
)
1442 /*-----------------------------------------------------------------*/
1443 printf("Writing data transfer database ...\n");
1444 /*-----------------------------------------------------------------*/
1445 f
=fopen("/var/run/prometheus.previous","w");
1448 for_selected(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1449 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1463 /*-----------------------------------------------------------------*/
1464 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1465 /*-----------------------------------------------------------------*/
1467 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
);
1468 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1471 for_each(group
,groups
)
1474 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1476 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1477 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1479 for_each(keyword
,keywords
)
1481 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1484 total
+=group
->count
;
1488 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1490 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1491 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1493 for_each(keyword
,keywords
)
1495 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1497 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1498 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1500 fputs("</table>\n",f
);
1502 else if(!dry_run
&& !just_flush
)
1508 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1509 int active_classes
=0;
1512 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1524 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1525 fprintf(f
," (%s)</th></tr>\n", d
);
1526 fputs("<tr><td align=\"right\">#</td><td>hostname</td>",f
);
1529 fputs("<td align=\"right\">lms</td>\n",f
);
1531 fputs("<td align=\"right\">credit</td>\
1532 <td align=\"right\">limit</td>\
1533 <td align=\"right\">total</td>\
1534 <td align=\"right\">direct</td>\n",f
);
1537 fputs("<td align=\"right\">proxy</td>\n",f
);
1539 fputs("<td align=\"right\">upload</td>\
1540 <td align=\"right\">minimum</td>\
1541 <td align=\"right\">desired</td>\
1542 <td align=\"right\">maximum</td>\
1543 <td>prio</td></tr>\n",f
);
1547 char *f1
="", *f2
="";
1548 if(ip
->max
<ip
->desired
)
1550 f1
="<font color=\"red\">";
1553 else if(ip
->prio
>highest_priority
+1)
1555 f1
="<font color=\"brown\">";
1560 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1562 fprintf(f
,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td>\n", ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1565 fputs("<td align=\"right\">",f
);
1568 /*base URL will be configurable soon ... */
1569 fprintf(f
,"<a href=\"https://hermes.spoje.net/?m=customerinfo&id=%d\">%04d</a>\n", ip
->lmsid
, ip
->lmsid
);
1573 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->credit
);
1574 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",
1575 ip
->keyword
->html_color
, ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1576 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1579 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1581 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1582 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",
1583 ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1585 total_direct
+=ip
->direct
;
1586 total_proxy
+=ip
->proxy
;
1587 total_upload
+=ip
->upload
;
1591 tmp_sum
+=ip
->traffic
;
1594 sum
->i
=active_classes
;
1595 insert(sum
,sums
,order_by
,i
);
1602 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1603 iplog
=fopen(str
,"a");
1606 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1607 time(NULL
),ip
->name
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
,ip
->min
,ip
->max
,ip
->desired
,ip
->lmsid
,d
); /* d = date*/
1613 fprintf(f
,"<tr><th colspan=\"%d\" align=\"left\">SUMMARY:</td>",colspan
-7);
1614 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1615 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1618 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1620 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1621 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1623 if(active_classes
>10)
1625 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1626 fputs("<tr><td>Analytic category</td>\n",f
);
1627 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1629 if_exists(sum
,sums
,sum
->l
>=total
/4)
1631 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1632 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
);
1635 if_exists(sum
,sums
,sum
->i
==10)
1637 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1638 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
);
1641 if_exists(sum
,sums
,sum
->l
>=total
/2)
1643 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1644 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
);
1647 if_exists(sum
,sums
,sum
->l
>=4*total
/5)
1649 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1650 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
);
1653 if_exists (sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1655 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1656 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
);
1659 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1661 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1662 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
);
1665 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1667 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1668 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
);
1671 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1673 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1674 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
);
1677 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
1678 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
);
1679 fputs("</table>\n", f
);
1681 fprintf(f
, stats_html_signature
, version
);
1687 puts("Statistics preview generated (-p switch) - now exiting ...");
1691 /*-----------------------------------------------------------------*/
1692 puts("Generating iptables and tc classes ...");
1693 /*-----------------------------------------------------------------*/
1696 printf("%-22s %-15s mark\n","name","ip");
1698 for_selected(ip
,ips
,ip
->mark
>0)
1704 duplicate(ip
->addr
,buf
);
1705 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1707 string(chain_forward
,6+strlen(buf
));
1708 strcpy(chain_forward
,"forw_");
1709 strcat(chain_forward
,buf
);
1711 string(chain_postrouting
,6+strlen(buf
));
1712 strcpy(chain_postrouting
,"post_");
1713 strcat(chain_postrouting
,buf
);
1719 chain_forward
="FORWARD";
1720 chain_postrouting
="POSTROUTING";
1723 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1725 /* -------------------------------------------------------- mark download */
1727 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1728 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1729 /* -m limit --limit 1/s */
1734 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
);
1735 /*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);*/
1739 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1742 /* -------------------------------------------------------- mark upload */
1743 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1744 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1747 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1752 /* -------------------------------------------------------- download class */
1753 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1755 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
);
1758 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1760 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*/
1763 if (filter_type
== 1)
1765 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1769 /* -------------------------------------------------------- upload class */
1770 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1771 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1773 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1774 tc
, wan
, ip
->group
, ip
->mark
,
1775 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1776 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1779 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1781 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*/
1784 if (filter_type
== 1)
1786 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1791 printf("(sharing %s)\n", ip
->sharing
);
1797 chain_forward
= "forw_common";
1798 chain_postrouting
= "post_common";
1802 chain_forward
= "FORWARD";
1803 chain_postrouting
= "POSTROUTING";
1805 /* -------------------------------- classify or reject free download */
1807 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1808 if(free_min
) final_chain
= "ACCEPT";
1813 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);
1816 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1821 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1824 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1826 /* ------------------------------- classify or reject free upload */
1829 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1832 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1836 if(free_min
) /* allocate free bandwith if it is not zero... */
1838 /*-----------------------------------------------------------------*/
1839 puts("Generating free bandwith classes ...");
1840 /*-----------------------------------------------------------------*/
1841 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1842 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1844 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1845 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1848 if (strcmpi(qos_leaf
, "none"))
1850 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1853 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1856 /* tc handle 1 fw flowid */
1857 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1860 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1863 printf("Total IP count: %d\n", i
);
1865 if (log_file
) fclose(log_file
);
1867 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1868 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.360481 seconds and 5 git commands to generate.