4731bcc2dac89bdaedcc9d37421c702066f65ad9
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, 20110428
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\
89 /* === Configuraration file values defaults - stored in global variables ==== */
91 int filter_type
= 1; /*1 mark, 2 classify*/
93 char *mark_iptables
= "MARK --set-mark ";
94 int dry_run
= 0; /* preview - use puts() instead of system() */
95 char *iptablespreamble
= "*mangle\n:PREROUTING ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:FORWARD ACCEPT [0:0]";
96 FILE *iptables_file
= NULL
;
97 int enable_credit
= 1; /* enable credit file */
98 int use_credit
= 0; /* use credit file (if enabled)*/
99 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
100 int hall_of_fame
= 1; /* enable hall of fame */
101 char *lan
= "eth0"; /* LAN interface */
102 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
103 char *wan
= "eth1"; /* WAN/ISP interface */
104 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
105 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
106 char *qos_free_zone
= NULL
; /* QoS free zone */
107 int qos_proxy
= 1; /* include proxy port to QoS */
108 int found_lmsid
= 0; /* show links to users in LMS information system */
109 int include_upload
= 1; /* upload+download=total traffic */
110 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
111 int proxy_port
= 3128; /* proxy port number */
112 long long int line
= 1024; /* WAN/ISP download in kbps */
113 long long int up
= 1024; /* WAN/ISP upload in kbps */
114 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
115 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
116 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
117 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
118 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
119 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
120 int burst
= 8; /* HTB burst (in kbits) */
122 int burst_group
= 32;
123 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
124 int keywordcount
= 0;
125 /* not yet implemented:
126 int fixed_packets = 0; maximum number of pps per IP address (not class!)
127 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
129 FILE *log_file
= NULL
;
130 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
132 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
133 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
134 const int idxtable_treshold1
= 24; /* this is no longer configurable */
135 const int idxtable_treshold2
= 12; /* this is no longer configurable */
136 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
137 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
139 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
154 unsigned long long direct
;
155 unsigned long long proxy
;
156 unsigned long long upload
;
157 unsigned long long traffic
;
158 unsigned long long credit
;
159 unsigned long pktsup
;
160 unsigned long pktsdown
;
161 struct Keyword
*keyword
;
163 } *ips
=NULL
, *ip
, *sharedip
;
172 } *groups
=NULL
, *group
;
178 struct Index
*parent
;
182 } *idxs
=NULL
, *idx
, *metaindex
;
188 int asymetry_ratio
; /* ratio for ADSL-like upload */
189 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
190 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
191 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
192 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
193 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
194 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
195 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
196 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
197 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
198 int default_prio
; /* default HTB priority for this keyword */
201 char *leaf_discipline
;
204 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
206 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
214 ip
->prio
= highest_priority
+1;
228 ip
->keyword
= keywords
;
232 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
234 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
236 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
238 char *ip
,*outip
,*outptr
,*fmt
;
241 /* debug printf("(%s,%d) -> ",ip,bitmask); */
243 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
245 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
249 /* should never exit here */
257 if(dot
<(bitmask
/8-1))
259 if(format_as_chainname
)
272 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
273 if(cutdot
)*cutdot
='\0';
274 if(format_as_chainname
)
279 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
283 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
284 sprintf(outptr
,fmt
,n
,bitmask
);
285 if(!format_as_chainname
) while(bitmask
<24)
290 /* debug printf("[%s]\n",outip); */
301 /*should never exit here*/
306 char *hash_id(char *ip
,int bitmask
)
308 return very_ugly_ipv4_code(ip
,bitmask
,1);
311 char *subnet_id(char *ip
,int bitmask
)
313 return very_ugly_ipv4_code(ip
,bitmask
,0);
316 /* ================= Let's parse configuration file here =================== */
318 void reject_config_and_exit(char *filename
)
320 printf("Configuration file %s rejected - abnormal exit.",filename
);
324 void get_config(char *config_filename
)
328 printf("Configured keywords: ");
329 parse(config_filename
)
331 option("keyword",kwd
);
336 create(keyword
,Keyword
);
338 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
339 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
340 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
341 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
342 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
343 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
344 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
345 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
346 keyword
->default_prio
=highest_priority
+1;
347 keyword
->html_color
="000000";
349 keyword
->leaf_discipline
="";
351 push(keyword
,keywords
);
352 if(!defaultkeyword
) defaultkeyword
=keyword
;
359 for_each(keyword
,keywords
)
361 int l
=strlen(keyword
->key
);
363 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
365 char *tmptr
=_
; /* <---- l+1 ----> */
366 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
367 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
368 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
369 ioption("magic-relative-limit",keyword
->data_limit
);
370 ioption("magic-relative-prio",keyword
->data_prio
);
371 loption("magic-fixed-limit",keyword
->fixed_limit
);
372 loption("magic-fixed-prio",keyword
->fixed_prio
);
373 ioption("htb-default-prio",keyword
->default_prio
);
374 ioption("htb-rate-bonus",keyword
->reserve_min
);
375 ioption("htb-ceil-malus",keyword
->reserve_max
);
376 option("leaf-discipline",keyword
->leaf_discipline
);
377 option("html-color",keyword
->html_color
);
380 if(keyword
->data_limit
|| keyword
->fixed_limit
||
381 keyword
->data_prio
|| keyword
->fixed_prio
)
390 option("iptables",iptables
);
391 option("iptables-save",iptablessave
); /* new */
392 option("iptables-restore",iptablesrestore
); /* new */
393 option("iptables-file",iptablesfile
); /* new */
394 option("hosts",hosts
);
395 option("lan-interface",lan
);
396 option("wan-interface",wan
);
397 option("lan-medium",lan_medium
);
398 option("wan-medium",wan_medium
);
399 lloption("wan-download",line
);
400 lloption("wan-upload",up
);
401 ioption("hall-of-fame-enable",hall_of_fame
);
402 option("hall-of-fame-title",title
);
403 option("hall-of-fame-filename",html
);
404 option("hall-of-fame-preview",preview
);
405 option("log-filename",cmdlog
);
406 option("credit-filename",credit
);
407 ioption("credit-enable",enable_credit
);
408 option("log-traffic-directory",log_dir
);
409 option("log-traffic-html-directory",html_log_dir
);
410 option("log-traffic-url-path",log_url
);
411 option("qos-free-zone",qos_free_zone
);
412 ioption("qos-free-delay",qos_free_delay
);
413 ioption("qos-proxy-enable",qos_proxy
);
414 option("qos-proxy-ip",proxy_ip
);
415 option("htb-leaf-discipline",qos_leaf
);
416 ioption("qos-proxy-port",proxy_port
);
417 ioption("free-rate",free_min
);
418 ioption("free-ceil",free_max
);
419 ioption("htb-burst",burst
);
420 ioption("htb-burst-main",burst_main
);
421 ioption("htb-burst-group",burst_group
);
422 ioption("htb-nesting-limit",max_nesting
);
423 ioption("htb-r2q",htb_r2q
);
424 ioption("magic-include-upload",include_upload
);
425 ioption("magic-treshold",magic_treshold
);
426 option("filter-type", cnf
);
428 /* not yet implemented:
429 ioption("magic-fixed-packets",fixed_packets);
430 ioption("magic-relative-packets",packet_limit);
435 perror(config_filename
);
436 puts("Warning - using built-in defaults instead ...");
441 /*leaf discipline for keywords*/
442 for_each(keyword
,keywords
)
444 if (!strcmpi(keyword
->leaf_discipline
, ""))
446 keyword
->leaf_discipline
= qos_leaf
;
450 if (strcmpi(cnf
, "mark"))
454 mark_iptables
= "CLASSIFY --set-class 1:";
460 mark_iptables
= "MARK --set-mark ";
463 /* are supplied values meaningful ?*/
466 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
467 reject_config_and_exit(config_filename
);
471 /* ===================== traffic analyser - uses iptables ================ */
473 void get_traffic_statistics(void)
478 textfile(Pipe
,str
) *line
,*lines
=NULL
;
482 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
494 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
495 unsigned long long traffic
=0;
496 unsigned long pkts
=0;
497 char *ipaddr
=NULL
,*ptr
;
499 /* debug puts(line->str); */
500 valid_columns(ptr
,line
->str
,' ',col
)
501 if(valid
) switch(col
)
503 case 1: if(eq(ptr
,"Chain"))
505 else if(eq(ptr
,"pkts"))
508 sscanf(ptr
,"%lu",&pkts
);
510 case 2: if(setchainname
)
512 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
515 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
518 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
522 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
524 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
526 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
528 case 8: if(downloadflag
)
530 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
535 case 9: if(downloadflag
)ipaddr
=ptr
;break;
538 if(accept
&& traffic
>0 && ipaddr
)
544 else if(!downloadflag
)
548 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
550 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
555 if(eq(ip
->addr
,"0.0.0.0/0"))
557 ip
->name
="(unregistered)";
559 ip
->max
=ip
->desired
=free_max
;
571 ip
->traffic
+=traffic
;
573 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
582 ip
->traffic
+=traffic
;
586 if(traffic
>ip
->traffic
)
598 /* ========== This function executes, logs OR ALSO prints command ========== */
600 void safe_run(char *cmd
)
604 printf("\n=>%s\n",cmd
);
612 fprintf(log_file
,"%s\n",cmd
);
616 void save_line(char *line
)
618 fprintf(iptables_file
,"%s\n",line
);
621 void run_restore(void)
624 string(restor
,STRLEN
);
626 /*-----------------------------------------------------------------*/
627 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
628 /*-----------------------------------------------------------------*/
631 fclose(iptables_file
);
641 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
647 /* == This function strips extra characters after IP address and stores it = */
649 void parse_ip(char *str
)
651 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
657 while(*ptr
&& *ptr
!='}')
665 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
673 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
678 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
684 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
693 ip
->lmsid
=atoi(lmsid
);
698 char *parse_datafile_line(char *str
)
700 char *ptr
=strchr(str
,' ');
725 void parse_ip_log(int argc
, char **argv
)
727 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
728 long traffic
=0l, traffic_month
, total
=0, guaranted
;
729 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
730 char mstr
[4], ystr
[5];
733 string(filename
,STRLEN
);
735 if(argv
[1][1]=='l') /* -l */
739 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
745 if(eq(month
,"Year")) any_month
=1;
751 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
752 struct tm
*timep
= localtime(&t
);
754 if(argv
[1][1]=='m') /* -m yestarday - month */
756 strftime(mstr
, 4, "%b", timep
);
758 strftime(ystr
, 5, "%Y", timep
);
761 else /* -y yesterday - year */
765 strftime(ystr
, 5, "%Y", timep
);
769 printf("Analysing traffic for %s %s ...\n",month
,year
);
771 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
772 sprintf(str
,"%s %s/",ls
,log_dir
);
776 if(strstr(str
,".log"))
778 ptr
=strrchr(str
,'\n');
780 sprintf(filename
,"%s/%s",log_dir
,str
);
781 printf("Parsing %s ...",filename
);
789 valid_columns(ptr
,_
,'\t',col
) switch(col
)
791 case 2: name
= ptr
;break;
792 case 3: traffic
= atol(ptr
);break;
793 /* column number - was 7, now 11...*/
798 case 11: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
800 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
802 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
803 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
808 if(col
== 7) guaranted
= atol(ptr
);
809 if(col
== 10) lmsid
= atoi(ptr
);
815 traffic_month
+= traffic
;
825 iplog
->guaranted
= guaranted
;
826 iplog
->traffic
= traffic_month
;
827 iplog
->lmsid
= lmsid
;
828 insert(iplog
,iplogs
,desc_order_by
,traffic
);
829 printf(" %ld MB\n",iplog
->traffic
);
833 puts(" no records.");
837 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
838 printf("Writing %s ...",str
);
842 fprintf(f
,"<table border><tr><th colspan=\"2\">%s %s</th><th align=\"right\">lms</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",month
,year
);
844 for_each(iplog
,iplogs
)
848 fprintf(f
,"<tr><td align=\"right\">%d</td><th align=\"left\">%s</td><td align=\"right\">", i
++, iplog
->name
);
851 /*base URL will be configurable soon ... */
852 fprintf(f
,"<a href=\"https://hermes.spoje.net/?m=customerinfo&id=%d\">%04d</a>\n", iplog
->lmsid
, iplog
->lmsid
);
854 else if(iplog
->lmsid
== 0)
858 fprintf(f
,"<td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
859 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
860 total
+=iplog
->traffic
>>10;
865 fprintf(f
,"<tr><th colspan=\"4\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total
, line
);
866 fputs("</table>\n", f
);
870 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Resource Planning (ERP)</th></tr>\n",f
);
871 fputs("<tr><td>Analytic category</td>\n",f
);
872 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
874 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
876 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
877 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
880 if_exists(iplog
,iplogs
,iplog
->i
==10)
882 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
883 fprintf(f
,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
886 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
888 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
889 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
892 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
894 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
895 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
898 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
900 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
901 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
904 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
906 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
907 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
910 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
912 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
913 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
916 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
918 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
919 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
922 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
923 fprintf(f
,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%ld G</th><th align=\"right\">100 %%</th></tr>\n",i
-1,total
);
924 fputs("</table>\n", f
);
927 fprintf(f
, stats_html_signature
, version
);
933 /*-----------------------------------------------------------------*/
934 /* Are you looking for int main(int argc, char **argv) ? :-)) */
935 /*-----------------------------------------------------------------*/
943 int class_count
=0,ip_count
=0;
945 int just_flush
=FALSE
;
947 int just_preview
=FALSE
; /* preview - generate just stats */
948 int just_logs
=FALSE
; /* just parse logs */
952 char *chain_forward
, *chain_postrouting
;
956 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
957 Version %s - Copyright (C)2005-2011 Michael Polak (xChaos)\n\
958 iptables-restore & burst tunning & classify modification by Ludva\n\
959 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
961 /*----- Boring... we have to check command line options first: ----*/
965 argument("-c") { nextargument(config
); }
966 argument("-h") { nextargument(althosts
);}
967 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
968 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
969 argument("-9") { run
=TRUE
; just_flush
=9; }
970 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
971 argument("-r") { run
=TRUE
; }
972 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
973 argument("-l") { just_logs
=TRUE
; }
974 argument("-m") { just_logs
=TRUE
; }
975 argument("-y") { just_logs
=TRUE
; }
976 argument("-?") { help(); exit(0); }
977 argument("--help") { help(); exit(0); }
978 argument("-v") { exit(0); }
979 argument("--version") { exit(0); }
984 puts("*** THIS IS JUST DRY RUN ! ***\n");
987 date(d
); /* this is typical cll1.h macro - prints current date */
989 /*-----------------------------------------------------------------*/
990 printf("Parsing configuration file %s ...\n", config
);
991 /*-----------------------------------------------------------------*/
996 parse_ip_log(argc
,argv
);
1012 /*-----------------------------------------------------------------*/
1013 puts("Parsing iptables verbose output ...");
1014 /*-----------------------------------------------------------------*/
1015 get_traffic_statistics();
1018 /*-----------------------------------------------------------------*/
1019 printf("Parsing class defintion file %s ...\n", hosts
);
1020 /*-----------------------------------------------------------------*/
1021 int groupidx
= FIRSTGROUPID
;
1026 if(*str
<'0' || *str
>'9')
1028 /* any line starting with non-number is comment ...*/
1032 //Does this IP share QoS class with some other ?
1033 substring
=strstr(str
,"sharing-");
1036 substring
+=8; //"sharing-"
1039 ip
->sharing
=substring
;
1040 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1041 while(*substring
&& *substring
!='\n')
1049 //Do we have to create new QoS class for this IP ?
1051 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1055 ip
->keyword
=keyword
;
1056 keyword
->ip_count
++;
1057 ip
->prio
=keyword
->default_prio
;
1058 substring
+=strlen(keyword
->key
)+1;
1060 while(*ptr
&& *ptr
!='-')
1067 ip
->max
=ip
->desired
=atoi(ptr
+1);
1069 ip
->min
=atoi(substring
);
1072 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
1075 if(ip
->max
<=ip
->min
)
1078 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
1082 ip
->max
-=ip
->keyword
->reserve_max
;
1088 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1090 if_exists(group
,groups
,group
->min
==ip
->min
)
1093 group
->desired
+=ip
->min
;
1094 ip
->group
= group
->id
;
1098 create(group
,Group
);
1100 group
->id
= groupidx
++;
1101 ip
->group
= group
->id
;
1103 if(group
->min
<8) group
->min
=8;
1104 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1105 /* it is because class IDs are derived from min. bandwidth. - xCh */
1106 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1109 group
->desired
=ip
->min
;
1110 insert(group
,groups
,desc_order_by
,min
);
1122 /*-----------------------------------------------------------------*/
1123 /* cll1.h - let's allocate brand new character buffer... */
1124 /*-----------------------------------------------------------------*/
1127 /*-----------------------------------------------------------------*/
1128 puts("Resolving shared connections ...");
1129 /*-----------------------------------------------------------------*/
1130 for_selected(ip
,ips
,ip
->sharing
)
1132 for_selected(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
1134 sharedip
->traffic
+=ip
->traffic
;
1136 ip
->mark
=sharedip
->mark
;
1137 ip
->lmsid
=sharedip
->lmsid
;
1142 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1146 if(enable_credit
&& just_flush
<9)
1148 /*-----------------------------------------------------------------*/
1149 printf("Parsing credit file %s ...\n", credit
);
1150 /*-----------------------------------------------------------------*/
1153 ptr
=parse_datafile_line(_
);
1156 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1158 sscanf(ptr
,"%Lu",&(ip
->credit
));
1167 /*-----------------------------------------------------------------*/
1168 puts("Initializing iptables and tc classes ...");
1169 /*-----------------------------------------------------------------*/
1171 iptables_file
=fopen(iptablesfile
,"w");
1172 if (iptables_file
== NULL
)
1174 puts("Cannot open iptablesfile!");
1178 log_file
=fopen(cmdlog
,"w");
1179 if (log_file
== NULL
)
1181 puts("Cannot open logfile!");
1185 save_line(iptablespreamble
);
1188 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1191 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1194 iptables_file
=fopen(iptablesfile
,"w");
1195 save_line(iptablespreamble
);
1197 if(qos_free_zone
&& *qos_free_zone
!='0')
1201 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1206 save_line(":post_noproxy - [0:0]");
1207 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1209 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1211 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1214 chain
="post_noproxy";
1218 chain
="POSTROUTING";
1221 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1225 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1227 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1229 /*-----------------------------------------------------------------*/
1230 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1231 /*-----------------------------------------------------------------*/
1233 save_line(":post_common - [0:0]");
1234 save_line(":forw_common - [0:0]");
1236 for_selected(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1238 buf
=hash_id(ip
->addr
,bitmask
);
1239 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1248 idx
->bitmask
=bitmask
;
1256 /* brutal perfomance optimalization */
1257 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1259 bitmask
-=idxtable_bitmask2
;
1262 for_selected(idx
,idxs
,idx
->parent
==NULL
)
1264 buf
=hash_id(idx
->addr
,bitmask
);
1265 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1267 metaindex
->children
++;
1271 create(metaindex
,Index
);
1272 metaindex
->addr
=idx
->addr
;
1274 metaindex
->bitmask
=bitmask
;
1275 metaindex
->parent
=NULL
;
1276 metaindex
->children
=0;
1278 push(metaindex
,idxs
);
1280 idx
->parent
=metaindex
;
1284 /* this should slightly optimize throughout ... */
1285 sort(idx
,idxs
,desc_order_by
,children
);
1286 sort(idx
,idxs
,order_by
,bitmask
);
1291 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1292 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1294 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1297 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1302 string(buf
,strlen(idx
->parent
->id
)+6);
1303 sprintf(buf
,"post_%s",idx
->parent
->id
);
1310 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1313 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1318 string(buf
,strlen(idx
->parent
->id
)+6);
1319 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1326 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1329 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1332 printf("Total indexed iptables chains created: %d\n", i
);
1334 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1337 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1345 fclose(iptables_file
);
1346 if (log_file
) fclose(log_file
);
1347 puts("Just flushed iptables and tc classes - now exiting ...");
1353 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1355 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1356 sleep(qos_free_delay
);
1359 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1362 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1363 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1366 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1367 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1370 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1373 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1374 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1377 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1378 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1382 /*-----------------------------------------------------------------*/
1383 puts("Locating heavy downloaders and generating root classes ...");
1384 /*-----------------------------------------------------------------*/
1385 sort(ip
,ips
,desc_order_by
,traffic
);
1387 /*-----------------------------------------------------------------*/
1388 /* sub-scope - local variables */
1390 long long int rate
=line
;
1391 long long int max
=line
;
1393 FILE *credit_file
=NULL
;
1395 if(!just_preview
&& !dry_run
&& enable_credit
)
1397 credit_file
=fopen(credit
,"w");
1400 for_each(group
,groups
)
1405 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #down desired %d",
1406 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1410 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d #up desired %d",
1411 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1415 if(group_count
++<max_nesting
)
1420 rate
-=digital_divide
*group
->min
;
1426 /*shaping of aggresive downloaders, with credit file support */
1429 int group_rate
=group
->min
, priority_sequence
=lowest_priority
;
1431 for_selected(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1433 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
&&
1434 ip
->traffic
>ip
->credit
+
1435 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)) )
1437 if(group_rate
<ip
->max
)
1441 group_rate
+=magic_treshold
;
1442 ip
->prio
=lowest_priority
;
1443 if(ip
->prio
<highest_priority
+2)
1445 ip
->prio
=highest_priority
+2;
1450 if( ip
->keyword
->data_prio
&& !ip
->fixedprio
&&
1451 ip
->traffic
>ip
->credit
+
1452 (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20)) )
1454 ip
->prio
=priority_sequence
--;
1455 if(ip
->prio
<highest_priority
+1)
1457 ip
->prio
=highest_priority
+1;
1463 unsigned long long lcredit
=0;
1465 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1467 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1469 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1478 fclose(credit_file
);
1484 f
=fopen(preview
,"w");
1487 else if(!dry_run
&& !just_flush
)
1489 /*-----------------------------------------------------------------*/
1490 printf("Writing data transfer database ...\n");
1491 /*-----------------------------------------------------------------*/
1492 f
=fopen("/var/run/prometheus.previous","w");
1495 for_selected(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1496 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1510 /*-----------------------------------------------------------------*/
1511 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1512 /*-----------------------------------------------------------------*/
1514 fputs("<table border>\n<tr><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f
);
1515 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1518 for_each(group
,groups
)
1521 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1523 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1524 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1526 for_each(keyword
,keywords
)
1528 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%d M</span></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1531 total
+=group
->count
;
1535 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1537 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1538 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1540 for_each(keyword
,keywords
)
1542 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1544 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1545 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1547 fputs("</table>\n",f
);
1549 else if(!dry_run
&& !just_flush
)
1555 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1556 int active_classes
=0;
1559 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1560 int limit_count
=0, prio_count
=0;
1572 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1573 fprintf(f
," (%s)</th></tr>\n", d
);
1574 fputs("<tr><td align=\"right\">#</td><td>hostname</td>",f
);
1577 fputs("<td align=\"right\">lms</td>\n",f
);
1579 fputs("<td align=\"right\">credit</td>\
1580 <td align=\"right\">limit</td>\
1581 <td align=\"right\">total</td>\
1582 <td align=\"right\">direct</td>\n",f
);
1585 fputs("<td align=\"right\">proxy</td>\n",f
);
1587 fputs("<td align=\"right\">upload</td>\
1588 <td align=\"right\">minimum</td>\
1589 <td align=\"right\">desired</td>\
1590 <td align=\"right\">maximum</td>\
1591 <td>prio</td></tr>\n",f
);
1595 char *f1
="", *f2
="";
1596 if(ip
->max
<ip
->desired
)
1598 f1
="<span style=\"color:red\">";
1602 else if(ip
->prio
>highest_priority
+1)
1604 f1
="<span style=\"color:brown\">";
1610 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1612 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
);
1615 fputs("<td align=\"right\">",f
);
1618 /*base URL will be configurable soon ... */
1619 fprintf(f
,"<a href=\"https://hermes.spoje.net/?m=customerinfo&id=%d\">%04d</a>\n", ip
->lmsid
, ip
->lmsid
);
1621 else if(ip
->lmsid
== 0)
1627 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->credit
);
1628 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%Lu M</span></td>",
1629 ip
->keyword
->html_color
, ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1630 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1633 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1635 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1636 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",
1637 ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1638 total_traffic
+=ip
->traffic
;
1639 total_direct
+=ip
->direct
;
1640 total_proxy
+=ip
->proxy
;
1641 total_upload
+=ip
->upload
;
1645 tmp_sum
+=ip
->traffic
;
1648 sum
->i
=active_classes
;
1649 insert(sum
,sums
,order_by
,i
);
1656 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1657 iplog
=fopen(str
,"a");
1660 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1661 time(NULL
),ip
->name
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
,ip
->min
,ip
->max
,ip
->desired
,ip
->lmsid
,d
); /* d = date*/
1666 fprintf(f
,"<tr><th colspan=\"%d\" align=\"left\">SUMMARY:</td>",colspan
-7);
1667 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1668 <th align=\"right\">%Lu M</th>\n", total_traffic
, total_direct
);
1671 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1673 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1674 fprintf(f
,"<th colspan=\"4\"><span style=\"color:red\">FUP-LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</table>\n",limit_count
,prio_count
);
1676 if(active_classes
>10)
1678 int top20_count
=0,top20_perc1
=0;
1679 long long top20_perc2
=0;
1680 unsigned long long top20_sum
=0l;
1682 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Resource Planning (ERP)</th></tr>\n",f
);
1683 fputs("<tr><td>Analytic category</td>\n",f
);
1684 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1686 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1688 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1689 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1692 if_exists(sum
,sums
,sum
->i
==10)
1694 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1695 fprintf(f
,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1698 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1700 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1701 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1704 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
1706 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1707 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1710 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1712 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1714 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1716 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1717 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
1720 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1722 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1723 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1726 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1728 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1729 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1732 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1734 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1735 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1738 fprintf(f
,"<tr><td><a href=\"%sERP.log\">All users, all traffic</a></td>\n", log_url
);
1739 fprintf(f
,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
1740 fputs("</table>\n", f
);
1742 /* write basic ERP data to log directory */
1745 sprintf(str
,"%s/ERP.log",log_dir
);
1746 iplog
=fopen(str
,"a");
1749 fprintf(iplog
,"%ld\t%d\t%d %%\t%Lu M\t%Ld %%\tACTIVE %d\tTRAFFIC %Lu M\tCLASSES %d\tFUP-LIMIT %d\tLOW-PRIO %d\t%s",
1750 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
1751 active_classes
, total_traffic
, total
, limit_count
, prio_count
, d
); /* d = date*/
1757 fprintf(f
, stats_html_signature
, version
);
1763 puts("Statistics preview generated (-p switch) - now exiting ...");
1767 /*-----------------------------------------------------------------*/
1768 puts("Generating iptables and tc classes ...");
1769 /*-----------------------------------------------------------------*/
1772 printf("%-22s %-15s mark\n","name","ip");
1774 for_selected(ip
,ips
,ip
->mark
>0)
1780 duplicate(ip
->addr
,buf
);
1781 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1783 string(chain_forward
,6+strlen(buf
));
1784 strcpy(chain_forward
,"forw_");
1785 strcat(chain_forward
,buf
);
1787 string(chain_postrouting
,6+strlen(buf
));
1788 strcpy(chain_postrouting
,"post_");
1789 strcat(chain_postrouting
,buf
);
1795 chain_forward
="FORWARD";
1796 chain_postrouting
="POSTROUTING";
1799 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1801 /* -------------------------------------------------------- mark download */
1803 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1804 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1805 /* -m limit --limit 1/s */
1810 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
);
1811 /*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);*/
1815 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1818 /* -------------------------------------------------------- mark upload */
1819 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1820 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1823 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1828 /* -------------------------------------------------------- download class */
1829 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1831 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
);
1834 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1836 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*/
1839 if (filter_type
== 1)
1841 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1845 /* -------------------------------------------------------- upload class */
1846 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1847 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1849 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1850 tc
, wan
, ip
->group
, ip
->mark
,
1851 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1852 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1855 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1857 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*/
1860 if (filter_type
== 1)
1862 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1867 printf("(sharing %s)\n", ip
->sharing
);
1873 chain_forward
= "forw_common";
1874 chain_postrouting
= "post_common";
1878 chain_forward
= "FORWARD";
1879 chain_postrouting
= "POSTROUTING";
1881 /* -------------------------------- classify or reject free download */
1883 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1884 if(free_min
) final_chain
= "ACCEPT";
1889 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);
1892 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1897 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1900 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1902 /* ------------------------------- classify or reject free upload */
1905 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1908 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1912 if(free_min
) /* allocate free bandwith if it is not zero... */
1914 /*-----------------------------------------------------------------*/
1915 puts("Generating free bandwith classes ...");
1916 /*-----------------------------------------------------------------*/
1917 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1918 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1920 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1921 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1924 if (strcmpi(qos_leaf
, "none"))
1926 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1929 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1932 /* tc handle 1 fw flowid */
1933 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1936 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1939 printf("Total IP count: %d\n", i
);
1941 if (log_file
) fclose(log_file
);
1943 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1944 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.30317 seconds and 3 git commands to generate.