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, 20111130
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-b";
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 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
66 char *lms_url
= "/lms/?m=customerinfo&id=";
67 int use_jquery_popups
= 1;
68 int row_odd_even
= 0; /*<tr class="odd/even"> */
70 const char *tr_odd_even(void)
72 row_odd_even
= 1 - row_odd_even
;
75 return "<tr class=\"even\">\n";
79 return "<tr class=\"odd\">\n";
83 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
87 puts("Command line switches:\n\
89 -?, --help this help screen\n\
90 -v, --version show Version number of this utility and exit\n\
91 -c filename force alternative /etc/prometheus.Conf filename\n\
92 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
93 -f just Flush iptables and tc classes and exit (stop shaping)\n\
94 -9 emergency iptables flush (do not read data transfer statistics)\n\
95 -p just generate Preview of data transfer statistics and exit\n\
96 -d Dry run (preview tc and iptables commands on stdout)\n\
97 -r Run (reset all statistics and start shaping)\n\
98 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
99 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
100 -m generate HTML summary of traffic logs for yesterday's Month\n\
101 -y generate HTML summary of traffic logs for yesterday's Year\n");
102 /* not yet implemented:
103 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
107 /* === Configuraration file values defaults - stored in global variables ==== */
109 int filter_type
= 1; /*1 mark, 2 classify*/
111 char *mark_iptables
= "MARK --set-mark ";
112 int dry_run
= 0; /* preview - use puts() instead of system() */
113 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]";
114 FILE *iptables_file
= NULL
;
115 int enable_credit
= 1; /* enable credit file */
116 int use_credit
= 0; /* use credit file (if enabled)*/
117 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
118 int hall_of_fame
= 1; /* enable hall of fame */
119 char *lan
= "eth0"; /* LAN interface */
120 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
121 char *wan
= "eth1"; /* WAN/ISP interface */
122 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
123 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
124 char *qos_free_zone
= NULL
; /* QoS free zone */
125 int qos_proxy
= 1; /* include proxy port to QoS */
126 int found_lmsid
= 0; /* show links to users in LMS information system */
127 int include_upload
= 1; /* upload+download=total traffic */
128 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
129 int proxy_port
= 3128; /* proxy port number */
130 long long int line
= 1024; /* WAN/ISP download in kbps */
131 long long int up
= 1024; /* WAN/ISP upload in kbps */
132 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
133 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
134 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
135 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
136 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
137 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
138 int burst
= 8; /* HTB burst (in kbits) */
140 int burst_group
= 32;
141 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
142 int keywordcount
= 0;
143 /* not yet implemented:
144 int fixed_packets = 0; maximum number of pps per IP address (not class!)
145 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
147 FILE *log_file
= NULL
;
148 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
150 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
151 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
152 const int idxtable_treshold1
= 24; /* this is no longer configurable */
153 const int idxtable_treshold2
= 12; /* this is no longer configurable */
154 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
155 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
157 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
172 unsigned long long direct
;
173 unsigned long long proxy
;
174 unsigned long long upload
;
175 unsigned long long traffic
;
176 unsigned long long credit
;
177 unsigned long pktsup
;
178 unsigned long pktsdown
;
179 struct Keyword
*keyword
;
181 } *ips
=NULL
, *ip
, *sharedip
;
190 } *groups
=NULL
, *group
;
196 struct Index
*parent
;
200 } *idxs
=NULL
, *idx
, *metaindex
;
206 int asymetry_ratio
; /* ratio for ADSL-like upload */
207 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
208 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
209 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
210 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
211 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
212 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
213 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
214 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
215 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
216 int default_prio
; /* default HTB priority for this keyword */
219 char *leaf_discipline
;
222 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
224 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
232 ip
->prio
= highest_priority
+1;
246 ip
->keyword
= keywords
;
250 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
252 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
254 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
256 char *ip
,*outip
,*outptr
,*fmt
;
259 /* debug printf("(%s,%d) -> ",ip,bitmask); */
261 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
263 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
267 /* should never exit here */
275 if(dot
<(bitmask
/8-1))
277 if(format_as_chainname
)
290 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
291 if(cutdot
)*cutdot
='\0';
292 if(format_as_chainname
)
297 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
301 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
302 sprintf(outptr
,fmt
,n
,bitmask
);
303 if(!format_as_chainname
) while(bitmask
<24)
308 /* debug printf("[%s]\n",outip); */
319 /*should never exit here*/
324 char *hash_id(char *ip
,int bitmask
)
326 return very_ugly_ipv4_code(ip
,bitmask
,1);
329 char *subnet_id(char *ip
,int bitmask
)
331 return very_ugly_ipv4_code(ip
,bitmask
,0);
334 /* ================= Let's parse configuration file here =================== */
336 void reject_config_and_exit(char *filename
)
338 printf("Configuration file %s rejected - abnormal exit.",filename
);
342 void get_config(char *config_filename
)
346 printf("Configured keywords: ");
347 parse(config_filename
)
349 option("keyword",kwd
);
354 create(keyword
,Keyword
);
356 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
357 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
358 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
359 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
360 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
361 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
362 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
363 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
364 keyword
->default_prio
=highest_priority
+1;
365 keyword
->html_color
="000000";
367 keyword
->leaf_discipline
="";
369 push(keyword
,keywords
);
370 if(!defaultkeyword
) defaultkeyword
=keyword
;
377 for_each(keyword
,keywords
)
379 int l
=strlen(keyword
->key
);
381 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
383 char *tmptr
=_
; /* <---- l+1 ----> */
384 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
385 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
386 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
387 ioption("magic-relative-limit",keyword
->data_limit
);
388 ioption("magic-relative-prio",keyword
->data_prio
);
389 loption("magic-fixed-limit",keyword
->fixed_limit
);
390 loption("magic-fixed-prio",keyword
->fixed_prio
);
391 ioption("htb-default-prio",keyword
->default_prio
);
392 ioption("htb-rate-bonus",keyword
->reserve_min
);
393 ioption("htb-ceil-malus",keyword
->reserve_max
);
394 option("leaf-discipline",keyword
->leaf_discipline
);
395 option("html-color",keyword
->html_color
);
398 if(keyword
->data_limit
|| keyword
->fixed_limit
||
399 keyword
->data_prio
|| keyword
->fixed_prio
)
408 option("iptables",iptables
);
409 option("iptables-save",iptablessave
); /* new */
410 option("iptables-restore",iptablesrestore
); /* new */
411 option("iptables-file",iptablesfile
); /* new */
412 option("hosts",hosts
);
413 option("lan-interface",lan
);
414 option("wan-interface",wan
);
415 option("lan-medium",lan_medium
);
416 option("wan-medium",wan_medium
);
417 lloption("wan-download",line
);
418 lloption("wan-upload",up
);
419 ioption("hall-of-fame-enable",hall_of_fame
);
420 option("hall-of-fame-title",title
);
421 option("hall-of-fame-filename",html
);
422 option("hall-of-fame-preview",preview
);
423 option("log-filename",cmdlog
);
424 option("credit-filename",credit
);
425 ioption("credit-enable",enable_credit
);
426 option("log-traffic-directory",log_dir
);
427 option("log-traffic-html-directory",html_log_dir
);
428 option("log-traffic-url-path",log_url
);
429 option("jquery-url",jquery_url
);
430 option("lms-url",lms_url
);
431 ioption("use-jquery-popups",use_jquery_popups
);
432 option("qos-free-zone",qos_free_zone
);
433 ioption("qos-free-delay",qos_free_delay
);
434 ioption("qos-proxy-enable",qos_proxy
);
435 option("qos-proxy-ip",proxy_ip
);
436 option("htb-leaf-discipline",qos_leaf
);
437 ioption("qos-proxy-port",proxy_port
);
438 ioption("free-rate",free_min
);
439 ioption("free-ceil",free_max
);
440 ioption("htb-burst",burst
);
441 ioption("htb-burst-main",burst_main
);
442 ioption("htb-burst-group",burst_group
);
443 ioption("htb-nesting-limit",max_nesting
);
444 ioption("htb-r2q",htb_r2q
);
445 ioption("magic-include-upload",include_upload
);
446 ioption("magic-treshold",magic_treshold
);
447 option("filter-type", cnf
);
449 /* not yet implemented:
450 ioption("magic-fixed-packets",fixed_packets);
451 ioption("magic-relative-packets",packet_limit);
456 perror(config_filename
);
457 puts("Warning - using built-in defaults instead ...");
462 /*leaf discipline for keywords*/
463 for_each(keyword
,keywords
)
465 if (!strcmpi(keyword
->leaf_discipline
, ""))
467 keyword
->leaf_discipline
= qos_leaf
;
471 if (strcmpi(cnf
, "mark"))
475 mark_iptables
= "CLASSIFY --set-class 1:";
481 mark_iptables
= "MARK --set-mark ";
484 /* are supplied values meaningful ?*/
487 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
488 reject_config_and_exit(config_filename
);
492 /* ===================== traffic analyser - uses iptables ================ */
494 void get_traffic_statistics(void)
499 textfile(Pipe
,str
) *line
,*lines
=NULL
;
503 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
515 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
516 unsigned long long traffic
=0;
517 unsigned long pkts
=0;
518 char *ipaddr
=NULL
,*ptr
;
520 /* debug puts(line->str); */
521 valid_columns(ptr
,line
->str
,' ',col
)
522 if(valid
) switch(col
)
524 case 1: if(eq(ptr
,"Chain"))
526 else if(eq(ptr
,"pkts"))
529 sscanf(ptr
,"%lu",&pkts
);
531 case 2: if(setchainname
)
533 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
536 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
539 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
543 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
545 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
547 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
549 case 8: if(downloadflag
)
551 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
556 case 9: if(downloadflag
)ipaddr
=ptr
;break;
559 if(accept
&& traffic
>0 && ipaddr
)
565 else if(!downloadflag
)
569 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
571 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
576 if(eq(ip
->addr
,"0.0.0.0/0"))
578 ip
->name
="(unregistered)";
580 ip
->max
=ip
->desired
=free_max
;
592 ip
->traffic
+=traffic
;
594 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
603 ip
->traffic
+=traffic
;
607 if(traffic
>ip
->traffic
)
619 /* ========== This function executes, logs OR ALSO prints command ========== */
621 void safe_run(char *cmd
)
625 printf("\n=>%s\n",cmd
);
633 fprintf(log_file
,"%s\n",cmd
);
637 void save_line(char *line
)
639 fprintf(iptables_file
,"%s\n",line
);
642 void run_restore(void)
645 string(restor
,STRLEN
);
647 /*-----------------------------------------------------------------*/
648 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
649 /*-----------------------------------------------------------------*/
652 fclose(iptables_file
);
662 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
668 /* == This function strips extra characters after IP address and stores it = */
670 void parse_ip(char *str
)
672 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
678 while(*ptr
&& *ptr
!='}')
686 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
694 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
699 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
705 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
714 ip
->lmsid
=atoi(lmsid
);
719 char *parse_datafile_line(char *str
)
721 char *ptr
=strchr(str
,' ');
746 void parse_ip_log(int argc
, char **argv
)
748 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
749 long traffic
=0l, traffic_month
, total
=0, guaranted
;
750 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
751 char mstr
[4], ystr
[5];
754 string(filename
,STRLEN
);
756 if(argv
[1][1]=='l') /* -l */
760 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
766 if(eq(month
,"Year")) any_month
=1;
772 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
773 struct tm
*timep
= localtime(&t
);
775 if(argv
[1][1]=='m') /* -m yestarday - month */
777 strftime(mstr
, 4, "%b", timep
);
779 strftime(ystr
, 5, "%Y", timep
);
782 else /* -y yesterday - year */
786 strftime(ystr
, 5, "%Y", timep
);
790 printf("Analysing traffic for %s %s ...\n",month
,year
);
792 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
793 sprintf(str
,"%s %s/",ls
,log_dir
);
797 if(strstr(str
,".log"))
799 ptr
=strrchr(str
,'\n');
801 sprintf(filename
,"%s/%s",log_dir
,str
);
802 printf("Parsing %s ...",filename
);
810 valid_columns(ptr
,_
,'\t',col
) switch(col
)
812 case 2: name
= ptr
;break;
813 case 3: traffic
= atol(ptr
);break;
814 /* column number - was 7, now 11...*/
819 case 11: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
821 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
823 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
824 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
829 if(col
== 7) guaranted
= atol(ptr
);
830 if(col
== 10) lmsid
= atoi(ptr
);
836 traffic_month
+= traffic
;
846 iplog
->guaranted
= guaranted
;
847 iplog
->traffic
= traffic_month
;
848 iplog
->lmsid
= lmsid
;
849 insert(iplog
,iplogs
,desc_order_by
,traffic
);
850 printf(" %ld MB\n",iplog
->traffic
);
854 puts(" no records.");
858 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
859 printf("Writing %s ...",str
);
863 fprintf(f
, "<table border=\"1\"><thead><tr class=\"bgGrey\"><th colspan=\"2\">%s %s</th><th align=\"right\">lms</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr></thead><tbody>\n ",
867 for_each(iplog
, iplogs
)
871 fprintf(f
, "%s<td align=\"right\">%d</td><td align=\"left\"><a href=\"%s%s.log\">%s</td></td><td align=\"right\">",
872 tr_odd_even(), i
++, log_url
, iplog
->name
, iplog
->name
);
875 /*base URL will be configurable soon ... */
876 fprintf(f
, "<a href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
878 else if(iplog
->lmsid
== 0)
882 fprintf(f
, "<td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
883 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
884 total
+=iplog
->traffic
>>10;
889 fprintf(f
,"<tr class=\"bgGrey\"><th colspan=\"4\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total
, line
);
890 fputs("</tbody></table>\n", f
);
895 fputs("<a name=\"erp\"></a><p><table border=\"0\"><thead><caption>Enterprise Resource Planning (ERP)</caption></tr>\n",f
);
896 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f
);
897 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n</thead><tbody>\n",f
);
899 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
901 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
902 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
));
905 if_exists(iplog
,iplogs
,iplog
->i
==10)
907 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
908 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
));
911 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
913 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
914 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
));
917 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
919 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
920 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
));
923 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
925 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
926 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
));
929 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
931 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
932 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
));
935 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
937 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
938 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
));
941 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
943 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
944 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
));
947 fprintf(f
,"<tr class=\"bgGrey\"><td>All users, all traffic</td>\n");
948 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
);
949 fputs("</tbody></table>\n", f
);
952 fprintf(f
, stats_html_signature
, version
);
958 /*-----------------------------------------------------------------*/
959 /* Are you looking for int main(int argc, char **argv) ? :-)) */
960 /*-----------------------------------------------------------------*/
968 int class_count
=0,ip_count
=0;
970 int just_flush
=FALSE
;
972 int just_preview
=FALSE
; /* preview - generate just stats */
973 int just_logs
=FALSE
; /* just parse logs */
977 char *chain_forward
, *chain_postrouting
;
981 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
982 Version %s - Copyright (C)2005-2011 Michael Polak (xChaos)\n\
983 iptables-restore & burst tunning & classify modification by Ludva\n\
984 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
986 /*----- Boring... we have to check command line options first: ----*/
990 argument("-c") { nextargument(config
); }
991 argument("-h") { nextargument(althosts
);}
992 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
993 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
994 argument("-9") { run
=TRUE
; just_flush
=9; }
995 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
996 argument("-r") { run
=TRUE
; }
997 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
998 argument("-l") { just_logs
=TRUE
; }
999 argument("-m") { just_logs
=TRUE
; }
1000 argument("-y") { just_logs
=TRUE
; }
1001 argument("-?") { help(); exit(0); }
1002 argument("--help") { help(); exit(0); }
1003 argument("-v") { exit(0); }
1004 argument("--version") { exit(0); }
1009 puts("*** THIS IS JUST DRY RUN ! ***\n");
1012 date(d
); /* this is typical cll1.h macro - prints current date */
1014 /*-----------------------------------------------------------------*/
1015 printf("Parsing configuration file %s ...\n", config
);
1016 /*-----------------------------------------------------------------*/
1021 parse_ip_log(argc
,argv
);
1037 /*-----------------------------------------------------------------*/
1038 puts("Parsing iptables verbose output ...");
1039 /*-----------------------------------------------------------------*/
1040 get_traffic_statistics();
1043 /*-----------------------------------------------------------------*/
1044 printf("Parsing class defintion file %s ...\n", hosts
);
1045 /*-----------------------------------------------------------------*/
1046 int groupidx
= FIRSTGROUPID
;
1051 if(*str
<'0' || *str
>'9')
1053 /* any line starting with non-number is comment ...*/
1057 //Does this IP share QoS class with some other ?
1058 substring
=strstr(str
,"sharing-");
1061 substring
+=8; //"sharing-"
1064 ip
->sharing
=substring
;
1065 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1066 while(*substring
&& *substring
!='\n')
1074 //Do we have to create new QoS class for this IP ?
1076 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1080 ip
->keyword
=keyword
;
1081 keyword
->ip_count
++;
1082 ip
->prio
=keyword
->default_prio
;
1083 substring
+=strlen(keyword
->key
)+1;
1085 while(*ptr
&& *ptr
!='-')
1092 ip
->max
=ip
->desired
=atoi(ptr
+1);
1094 ip
->min
=atoi(substring
);
1097 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
1100 if(ip
->max
<=ip
->min
)
1103 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
1107 ip
->max
-=ip
->keyword
->reserve_max
;
1113 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1115 if_exists(group
,groups
,group
->min
==ip
->min
)
1118 group
->desired
+=ip
->min
;
1119 ip
->group
= group
->id
;
1123 create(group
,Group
);
1125 group
->id
= groupidx
++;
1126 ip
->group
= group
->id
;
1128 if(group
->min
<8) group
->min
=8;
1129 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1130 /* it is because class IDs are derived from min. bandwidth. - xCh */
1131 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1134 group
->desired
=ip
->min
;
1135 insert(group
,groups
,desc_order_by
,min
);
1147 /*-----------------------------------------------------------------*/
1148 /* cll1.h - let's allocate brand new character buffer... */
1149 /*-----------------------------------------------------------------*/
1152 /*-----------------------------------------------------------------*/
1153 puts("Resolving shared connections ...");
1154 /*-----------------------------------------------------------------*/
1155 for_each(ip
,ips
) if(ip
->sharing
)
1157 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1159 sharedip
->traffic
+=ip
->traffic
;
1161 ip
->mark
=sharedip
->mark
;
1162 ip
->lmsid
=sharedip
->lmsid
;
1167 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1171 if(enable_credit
&& just_flush
<9)
1173 /*-----------------------------------------------------------------*/
1174 printf("Parsing credit file %s ...\n", credit
);
1175 /*-----------------------------------------------------------------*/
1178 ptr
=parse_datafile_line(_
);
1181 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1183 sscanf(ptr
,"%Lu",&(ip
->credit
));
1192 /*-----------------------------------------------------------------*/
1193 puts("Initializing iptables and tc classes ...");
1194 /*-----------------------------------------------------------------*/
1196 iptables_file
=fopen(iptablesfile
,"w");
1197 if (iptables_file
== NULL
)
1199 puts("Cannot open iptablesfile!");
1203 log_file
=fopen(cmdlog
,"w");
1204 if (log_file
== NULL
)
1206 puts("Cannot open logfile!");
1210 save_line(iptablespreamble
);
1213 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1216 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1219 iptables_file
=fopen(iptablesfile
,"w");
1220 save_line(iptablespreamble
);
1222 if(qos_free_zone
&& *qos_free_zone
!='0')
1226 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1231 save_line(":post_noproxy - [0:0]");
1232 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1234 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1236 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1239 chain
="post_noproxy";
1243 chain
="POSTROUTING";
1246 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1250 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1252 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1254 /*-----------------------------------------------------------------*/
1255 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1256 /*-----------------------------------------------------------------*/
1258 save_line(":post_common - [0:0]");
1259 save_line(":forw_common - [0:0]");
1261 for_each(ip
,ips
) if (ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1263 buf
=hash_id(ip
->addr
,bitmask
);
1264 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1273 idx
->bitmask
=bitmask
;
1281 /* brutal perfomance optimalization */
1282 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1284 bitmask
-=idxtable_bitmask2
;
1287 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1289 buf
=hash_id(idx
->addr
,bitmask
);
1290 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1292 metaindex
->children
++;
1296 create(metaindex
,Index
);
1297 metaindex
->addr
=idx
->addr
;
1299 metaindex
->bitmask
=bitmask
;
1300 metaindex
->parent
=NULL
;
1301 metaindex
->children
=0;
1303 push(metaindex
,idxs
);
1305 idx
->parent
=metaindex
;
1309 /* this should slightly optimize throughout ... */
1310 sort(idx
,idxs
,desc_order_by
,children
);
1311 sort(idx
,idxs
,order_by
,bitmask
);
1316 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1317 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1319 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1322 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1327 string(buf
,strlen(idx
->parent
->id
)+6);
1328 sprintf(buf
,"post_%s",idx
->parent
->id
);
1335 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1338 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1343 string(buf
,strlen(idx
->parent
->id
)+6);
1344 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1351 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1354 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1357 printf("Total indexed iptables chains created: %d\n", i
);
1359 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1362 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1370 fclose(iptables_file
);
1371 if (log_file
) fclose(log_file
);
1372 puts("Just flushed iptables and tc classes - now exiting ...");
1378 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1380 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1381 sleep(qos_free_delay
);
1384 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1388 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1389 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1392 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1393 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1396 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1399 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1400 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1403 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1404 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1408 /*-----------------------------------------------------------------*/
1409 puts("Locating heavy downloaders and generating root classes ...");
1410 /*-----------------------------------------------------------------*/
1411 sort(ip
,ips
,desc_order_by
,traffic
);
1413 /*-----------------------------------------------------------------*/
1414 /* sub-scope - local variables */
1416 long long int rate
= line
;
1417 long long int max
= line
;
1418 int group_count
= 0;
1419 FILE *credit_file
= NULL
;
1421 if(!just_preview
&& !dry_run
&& enable_credit
)
1423 credit_file
= fopen(credit
,"w");
1426 for_each(group
,groups
)
1431 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",
1432 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1436 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",
1437 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1441 if(group_count
++ < max_nesting
)
1446 rate
-= digital_divide
*group
->min
;
1447 if(rate
< group
->min
)
1452 /*shaping of aggresive downloaders, with credit file support */
1455 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1457 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1459 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1460 && ( ip
->traffic
>ip
->credit
1461 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1463 if(group_rate
<ip
->max
)
1467 group_rate
+=magic_treshold
;
1468 ip
->prio
=lowest_priority
;
1469 if(ip
->prio
<highest_priority
+2)
1471 ip
->prio
=highest_priority
+2;
1476 if( ip
->keyword
->data_prio
1478 && ( ip
->traffic
>ip
->credit
1479 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1481 ip
->prio
=priority_sequence
--;
1482 if(ip
->prio
<highest_priority
+1)
1484 ip
->prio
=highest_priority
+1;
1490 unsigned long long lcredit
=0;
1492 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1494 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1496 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1504 fclose(credit_file
);
1510 f
=fopen(preview
,"w");
1513 else if(!dry_run
&& !just_flush
)
1515 /*-----------------------------------------------------------------*/
1516 printf("Writing data transfer database ...\n");
1517 /*-----------------------------------------------------------------*/
1518 f
=fopen("/var/run/prometheus.previous","w");
1521 for_each(ip
,ips
) if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1523 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",
1524 ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1538 /*-----------------------------------------------------------------*/
1539 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1540 /*-----------------------------------------------------------------*/
1542 if(use_jquery_popups
)
1544 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1546 fputs("<table border=\"0\">\n<thead><tr class=\"bgGrey\"><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f
);
1547 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1548 fputs("</tr></thead><tbody>\n",f
);
1551 for_each(group
, groups
)
1554 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1556 fprintf(f
, "%s<td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1557 tr_odd_even(), count
, group
->min
);
1558 fprintf(f
, "<td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1559 group
->count
, group
->desired
);
1561 for_each(keyword
, keywords
)
1563 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%d M</span></td>",
1564 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1566 i
+= group
->desired
;
1567 total
+= group
->count
;
1571 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",
1574 fprintf(f
,"<tr class=\"bgGrey\"><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1575 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1577 for_each(keyword
, keywords
)
1579 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1581 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1582 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1584 fputs("</tbody></table>\n",f
);
1586 else if(!dry_run
&& !just_flush
)
1594 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1595 int active_classes
=0;
1598 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1599 int limit_count
=0, prio_count
=0;
1611 fprintf(f
,"<p><table border>\n<thead><caption>%s",title
);
1612 fprintf(f
," (%s)</caption>\n", d
);
1613 fputs("<tr class=\"bgGrey\"><td align=\"right\">#</td><td>hostname</td>",f
);
1616 fputs("<td align=\"right\">lms</td>\n",f
);
1618 fputs("<td align=\"right\">credit</td>\
1619 <td align=\"right\">limit</td>\
1620 <td align=\"right\">total</td>\
1621 <td align=\"right\">direct</td>\n",f
);
1624 fputs("<td align=\"right\">proxy</td>\n",f
);
1626 fputs("<td align=\"right\">upload</td>\
1627 <td align=\"right\">minimum</td>\
1628 <td align=\"right\">desired</td>\
1629 <td align=\"right\">maximum</td>\
1630 <td>prio</td></tr>\n\
1631 </thead><tbody>\n",f
);
1634 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1636 char *f1
="", *f2
="";
1639 if(ip
->max
< ip
->desired
)
1641 f1
="<span style=\"color:red\">";
1645 else if(ip
->prio
> highest_priority
+1)
1647 f1
="<span style=\"color:brown\">";
1653 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1655 /* hostnames -------------------------------------- */
1656 fprintf(f
,"%s<td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a>\n",
1657 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1658 if(use_jquery_popups
)
1660 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1662 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1664 fprintf(f
,"<br /><a href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1667 fputs("</span>\n",f
);
1670 fprintf(f
,"<span>[<a href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1671 i
, i
, i
, popup_button
);
1675 /* ----------------------------------------------- */
1679 fputs("<td align=\"right\">",f
);
1682 /*base URL will be configurable soon ... */
1683 fprintf(f
,"<a href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1685 else if(ip
->lmsid
== 0)
1691 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->credit
);
1692 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%Lu M</span></td>",
1693 ip
->keyword
->html_color
,
1694 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1695 fprintf(f
,"<td align=\"right\">%s%Lu M%s", f1
, ip
->traffic
, f2
);
1697 /* download --------------------------------------- */
1698 fprintf(f
,"</td><td align=\"right\">%Lu M", ip
->direct
);
1699 if(use_jquery_popups
)
1701 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1702 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1704 fprintf(f
,"<br />%Lu M", sharedip
->direct
);
1706 fputs("</span>\n",f
);
1709 /* ----------------------------------------------- */
1713 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1715 /* upload ---------------------------------------- */
1716 fprintf(f
,"<td align=\"right\">%Lu M", ip
->upload
);
1717 if(use_jquery_popups
)
1719 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1720 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1722 fprintf(f
,"<br />%Lu M", sharedip
->upload
);
1724 fputs("</span>\n",f
);
1727 /* ----------------------------------------------- */
1729 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",
1730 ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1732 total_traffic
+=ip
->traffic
;
1733 total_direct
+=ip
->direct
;
1734 total_proxy
+=ip
->proxy
;
1735 total_upload
+=ip
->upload
;
1739 tmp_sum
+=ip
->traffic
;
1742 sum
->i
=active_classes
;
1743 insert(sum
,sums
,order_by
,i
);
1748 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1749 iplog
=fopen(str
,"a");
1752 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1753 time(NULL
), ip
->name
, ip
->traffic
, ip
->direct
, ip
->proxy
,
1754 ip
->upload
, ip
->min
, ip
->max
, ip
->desired
, ip
->lmsid
, d
); /* d = date*/
1759 fprintf(f
,"<tr class=\"bgGrey\"><th colspan=\"%d\" align=\"left\">%d CLASSES</th>", colspan
-7, i
);
1760 fprintf(f
,"<th align=\"right\">%Lu M</th><th align=\"right\">%Lu M</th>\n", total_traffic
, total_direct
);
1763 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1765 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1766 fprintf(f
,"<th colspan=\"4\"><span style=\"color:red\">FUP-LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</tbody></table>\n",limit_count
,prio_count
);
1769 if(active_classes
>10)
1771 int top20_count
=0,top20_perc1
=0;
1772 long long top20_perc2
=0;
1773 unsigned long long top20_sum
=0l;
1775 fputs("<a name=\"erp\"></a><p><table border><thead><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1776 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f
);
1777 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr></thead><tbody>\n",f
);
1779 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1781 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1782 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
);
1785 if_exists(sum
,sums
,sum
->i
==10)
1787 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1788 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
);
1791 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1793 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1794 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
);
1797 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
1799 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1800 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
);
1803 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1805 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1807 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1809 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1810 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
);
1813 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1815 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1816 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
);
1819 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1821 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1822 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
);
1825 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1827 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1828 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
);
1831 fprintf(f
,"<tr class=\"bgGrey\"><td><a href=\"%sERP.log\">All users, all traffic</a></td>\n", log_url
);
1832 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
);
1833 fputs("</tbody></table>\n", f
);
1835 /* write basic ERP data to log directory */
1838 sprintf(str
,"%s/ERP.log",log_dir
);
1839 iplog
=fopen(str
,"a");
1842 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",
1843 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
1844 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
1850 fprintf(f
, stats_html_signature
, version
);
1856 puts("Statistics preview generated (-p switch) - now exiting ...");
1860 /*-----------------------------------------------------------------*/
1861 puts("Generating iptables and tc classes ...");
1862 /*-----------------------------------------------------------------*/
1865 printf("%-22s %-15s mark\n","name","ip");
1867 for_each(ip
,ips
) if(ip
->mark
>0)
1872 duplicate(ip
->addr
,buf
);
1873 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1875 string(chain_forward
,6+strlen(buf
));
1876 strcpy(chain_forward
,"forw_");
1877 strcat(chain_forward
,buf
);
1879 string(chain_postrouting
,6+strlen(buf
));
1880 strcpy(chain_postrouting
,"post_");
1881 strcat(chain_postrouting
,buf
);
1887 chain_forward
="FORWARD";
1888 chain_postrouting
="POSTROUTING";
1891 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1893 /* -------------------------------------------------------- mark download */
1895 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1896 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1897 /* -m limit --limit 1/s */
1902 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
);
1903 /*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);*/
1907 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1910 /* -------------------------------------------------------- mark upload */
1911 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1912 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1915 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1920 /* -------------------------------------------------------- download class */
1921 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1923 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
);
1926 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1928 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*/
1931 if (filter_type
== 1)
1933 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1937 /* -------------------------------------------------------- upload class */
1938 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1939 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1941 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1942 tc
, wan
, ip
->group
, ip
->mark
,
1943 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1944 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1947 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1949 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*/
1952 if (filter_type
== 1)
1954 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1959 printf("(sharing %s)\n", ip
->sharing
);
1965 chain_forward
= "forw_common";
1966 chain_postrouting
= "post_common";
1970 chain_forward
= "FORWARD";
1971 chain_postrouting
= "POSTROUTING";
1973 /* -------------------------------- classify or reject free download */
1975 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1976 if(free_min
) final_chain
= "ACCEPT";
1981 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);
1984 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1989 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1992 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1994 /* ------------------------------- classify or reject free upload */
1997 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
2000 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
2004 if(free_min
) /* allocate free bandwith if it is not zero... */
2006 /*-----------------------------------------------------------------*/
2007 puts("Generating free bandwith classes ...");
2008 /*-----------------------------------------------------------------*/
2009 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2010 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2012 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2013 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2016 if (strcmpi(qos_leaf
, "none"))
2018 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
2021 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
2024 /* tc handle 1 fw flowid */
2025 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
2028 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
2031 printf("Total IP count: %d\n", i
);
2033 if (log_file
) fclose(log_file
);
2035 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2036 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.892688 seconds and 5 git commands to generate.