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, 20120511
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-c";
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
= "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2012 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\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*/
296 if(format_as_chainname
)
307 n
= atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
314 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
315 sprintf(outptr
,fmt
,n
,bitmask
);
316 if(!format_as_chainname
)
324 /* debug printf("[%s]\n",outip); */
335 /*should never exit here*/
340 char *hash_id(char *ip
,int bitmask
)
342 return very_ugly_ipv4_code(ip
,bitmask
,1);
345 char *subnet_id(char *ip
,int bitmask
)
347 return very_ugly_ipv4_code(ip
,bitmask
,0);
350 /* ================= Let's parse configuration file here =================== */
352 void reject_config_and_exit(char *filename
)
354 printf("Configuration file %s rejected - abnormal exit.",filename
);
358 void get_config(char *config_filename
)
362 printf("Configured keywords: ");
363 parse(config_filename
)
365 option("keyword",kwd
);
370 create(keyword
,Keyword
);
372 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
373 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
374 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
375 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
376 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
377 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
378 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
379 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
380 keyword
->default_prio
=highest_priority
+1;
381 keyword
->html_color
="000000";
383 keyword
->leaf_discipline
="";
385 push(keyword
,keywords
);
386 if(!defaultkeyword
) defaultkeyword
=keyword
;
393 for_each(keyword
,keywords
)
395 int l
=strlen(keyword
->key
);
397 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
399 char *tmptr
=_
; /* <---- l+1 ----> */
400 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
401 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
402 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
403 ioption("magic-relative-limit",keyword
->data_limit
);
404 ioption("magic-relative-prio",keyword
->data_prio
);
405 loption("magic-fixed-limit",keyword
->fixed_limit
);
406 loption("magic-fixed-prio",keyword
->fixed_prio
);
407 ioption("htb-default-prio",keyword
->default_prio
);
408 ioption("htb-rate-bonus",keyword
->reserve_min
);
409 ioption("htb-ceil-malus",keyword
->reserve_max
);
410 option("leaf-discipline",keyword
->leaf_discipline
);
411 option("html-color",keyword
->html_color
);
414 if(keyword
->data_limit
|| keyword
->fixed_limit
||
415 keyword
->data_prio
|| keyword
->fixed_prio
)
424 option("iptables",iptables
);
425 option("iptables-save",iptablessave
); /* new */
426 option("iptables-restore",iptablesrestore
); /* new */
427 option("iptables-file",iptablesfile
); /* new */
428 option("hosts",hosts
);
429 option("lan-interface",lan
);
430 option("wan-interface",wan
);
431 option("lan-medium",lan_medium
);
432 option("wan-medium",wan_medium
);
433 lloption("wan-download",line
);
434 lloption("wan-upload",up
);
435 ioption("hall-of-fame-enable",hall_of_fame
);
436 option("hall-of-fame-title",title
);
437 option("hall-of-fame-filename",html
);
438 option("hall-of-fame-preview",preview
);
439 option("log-filename",cmdlog
);
440 option("credit-filename",credit
);
441 ioption("credit-enable",enable_credit
);
442 option("log-traffic-directory",log_dir
);
443 option("log-traffic-html-directory",html_log_dir
);
444 option("log-traffic-url-path",log_url
);
445 option("jquery-url",jquery_url
);
446 option("lms-url",lms_url
);
447 ioption("use-jquery-popups",use_jquery_popups
);
448 option("qos-free-zone",qos_free_zone
);
449 ioption("qos-free-delay",qos_free_delay
);
450 ioption("qos-proxy-enable",qos_proxy
);
451 option("qos-proxy-ip",proxy_ip
);
452 option("htb-leaf-discipline",qos_leaf
);
453 ioption("qos-proxy-port",proxy_port
);
454 ioption("free-rate",free_min
);
455 ioption("free-ceil",free_max
);
456 ioption("htb-burst",burst
);
457 ioption("htb-burst-main",burst_main
);
458 ioption("htb-burst-group",burst_group
);
459 ioption("htb-nesting-limit",max_nesting
);
460 ioption("htb-r2q",htb_r2q
);
461 ioption("magic-include-upload",include_upload
);
462 ioption("magic-treshold",magic_treshold
);
463 option("filter-type", cnf
);
464 /* not yet implemented:
465 ioption("magic-fixed-packets",fixed_packets);
466 ioption("magic-relative-packets",packet_limit);
471 perror(config_filename
);
472 puts("Warning - using built-in defaults instead ...");
477 /*leaf discipline for keywords*/
478 for_each(keyword
,keywords
)
480 if(!strcmpi(keyword
->leaf_discipline
, ""))
482 keyword
->leaf_discipline
= qos_leaf
;
486 if(strcmpi(cnf
, "mark"))
490 mark_iptables
= "CLASSIFY --set-class 1:";
496 mark_iptables
= "MARK --set-mark ";
499 /* are supplied values meaningful ?*/
502 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
503 reject_config_and_exit(config_filename
);
507 /* ===================== traffic analyser - uses iptables ================ */
509 void get_traffic_statistics(void)
514 textfile(Pipe
,str
) *line
,*lines
=NULL
;
518 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
530 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
531 unsigned long long traffic
=0;
532 unsigned long pkts
=0;
533 char *ipaddr
=NULL
,*ptr
;
535 /* debug puts(line->str); */
536 valid_columns(ptr
,line
->str
,' ',col
)
537 if(valid
) switch(col
)
539 case 1: if(eq(ptr
,"Chain"))
543 else if(eq(ptr
,"pkts"))
549 sscanf(ptr
,"%lu",&pkts
);
552 case 2: if(setchainname
)
554 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
560 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
565 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
572 sscanf(ptr
,"%Lu",&traffic
);
577 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
581 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
583 case 8: if(downloadflag
)
585 if(strstr(proxy_ip
,ptr
))
595 case 9: if(downloadflag
)ipaddr
=ptr
;break;
598 if(accept
&& traffic
>0 && ipaddr
)
604 else if(!downloadflag
)
608 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
610 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
615 if(eq(ip
->addr
,"0.0.0.0/0"))
617 ip
->name
="(unregistered)";
619 ip
->max
=ip
->desired
=free_max
;
631 ip
->traffic
+=traffic
;
633 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
642 ip
->traffic
+=traffic
;
646 if(traffic
>ip
->traffic
)
658 /* ========== This function executes, logs OR ALSO prints command ========== */
660 void safe_run(char *cmd
)
664 printf("\n=>%s\n",cmd
);
672 fprintf(log_file
,"%s\n",cmd
);
676 void save_line(char *line
)
678 fprintf(iptables_file
,"%s\n",line
);
681 void run_restore(void)
684 string(restor
,STRLEN
);
686 /*-----------------------------------------------------------------*/
687 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
688 /*-----------------------------------------------------------------*/
691 fclose(iptables_file
);
701 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
707 /* == This function strips extra characters after IP address and stores it = */
709 void parse_ip(char *str
)
711 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
717 while(*ptr
&& *ptr
!='}')
725 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
733 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
738 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
744 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
753 ip
->lmsid
=atoi(lmsid
);
758 char *parse_datafile_line(char *str
)
760 char *ptr
=strchr(str
,' ');
785 void parse_ip_log(int argc
, char **argv
)
787 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
788 long traffic
=0l, traffic_month
, total
=0, guaranted
;
789 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
790 char mstr
[4], ystr
[5];
793 string(filename
,STRLEN
);
795 if(argv
[1][1]=='l') /* -l */
799 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
805 if(eq(month
,"Year")) any_month
=1;
811 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
812 struct tm
*timep
= localtime(&t
);
814 if(argv
[1][1]=='m') /* -m yestarday - month */
816 strftime(mstr
, 4, "%b", timep
);
818 strftime(ystr
, 5, "%Y", timep
);
821 else /* -y yesterday - year */
825 strftime(ystr
, 5, "%Y", timep
);
829 printf("Analysing traffic for %s %s ...\n",month
,year
);
831 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
832 sprintf(str
,"%s %s/",ls
,log_dir
);
836 if(strstr(str
,".log"))
838 ptr
=strrchr(str
,'\n');
840 sprintf(filename
,"%s/%s",log_dir
,str
);
841 printf("Parsing %s ...",filename
);
849 valid_columns(ptr
,_
,'\t',col
) switch(col
)
851 case 2: name
= ptr
;break;
852 case 3: traffic
= atol(ptr
);break;
853 /* column number - was 7, now 11...*/
858 case 11: if(isalpha(*ptr
)) /* character, not numeric string = date, just one*/
860 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
862 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
863 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
868 if(col
== 7) guaranted
= atol(ptr
);
869 if(col
== 10) lmsid
= atoi(ptr
);
875 traffic_month
+= traffic
;
885 iplog
->guaranted
= guaranted
;
886 iplog
->traffic
= traffic_month
;
887 iplog
->lmsid
= lmsid
;
888 insert(iplog
,iplogs
,desc_order_by
,traffic
);
889 printf(" %ld MB\n",iplog
->traffic
);
893 puts(" no records.");
897 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
898 printf("Writing %s ...",str
);
902 fprintf(f
, "<table class=\"decorated last\"><thead>\n\
903 <tr><th colspan=\"2\">%s %s</th>\n\
904 <th style=\"text-align: right\">lms</th>\n\
905 <th colspan=\"2\">Data transfers</th>\n\
906 <th style=\"text-align: right\">Min.speed</th>\n\
907 </tr></thead><tbody>\n ",
911 for_each(iplog
, iplogs
)
915 fprintf(f
, "%s<td style=\"text-align: right\">%d</td>\n\
916 <td style=\"text-align: left\"><a class=\"blue\" href=\"%s%s.log\">%s</td>\n\
917 <td style=\"text-align: right\">",
918 tr_odd_even(), i
++, log_url
, iplog
->name
, iplog
->name
);
921 /*base URL will be configurable soon ... */
922 fprintf(f
, "<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
924 else if(iplog
->lmsid
== 0)
928 fprintf(f
, "<td style=\"text-align: right\">%ld MB</td>\n\
929 <td style=\"text-align: right\"><strong>%ld GB</strong></td>\n\
930 <td style=\"text-align: right\">%ld kb/s</th></tr>\n",
931 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
932 total
+=iplog
->traffic
>>10;
938 <td colspan=\"4\" style=\"text-align: left\">Total:</td>\
939 <td style=\"text-align: right\"><strong>%ld GB</strong></td>\
940 <td style=\"text-align: right\"><strong>%Ld kb/s</strong></td></tr>\n", total
, line
);
941 fputs("</tbody></table>\n", f
);
946 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\">\n\
947 <caption>Enterprise Resource Planning (ERP)</caption>\n\
949 <th>Analytic category</th>\n\
950 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
951 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
952 </tr></thead><tbody>\n",f
);
954 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
956 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
957 fprintf(f
,"<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d %%</td><td style=\"text-align: right\">%ld G</td><td style=\"text-align: right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
960 if_exists(iplog
,iplogs
,iplog
->i
==10)
962 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
963 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
964 <td style=\"text-align: right\">%d %%</td>\n\
965 <td style=\"text-align: right\">%ld G</td>\n\
966 <td style=\"text-align: right\">%d %%</td></tr>\n",
967 (100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
970 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
972 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
973 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
974 <td style=\"text-align: right\">%d %%</td>\n\
975 <td style=\"text-align: right\">%ld G</td>\n\
976 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
977 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
980 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
982 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
983 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
984 <td style=\"text-align: right\">%d %%</td>\n\
985 <td style=\"text-align: right\">%ld G</td>\n\
986 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
987 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
990 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
992 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
993 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
994 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
995 <td style=\"text-align: right\">%ld G</td>\n\
996 <td style=\"text-align: right\">%d %%</td></tr>\n",
997 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
1000 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
1002 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1003 fprintf(f
,"<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d %%</td><td style=\"text-align: right\">%ld G</td><td style=\"text-align: right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
1006 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
1008 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
1009 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1010 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1011 <td style=\"text-align: right\">%ld G</td><td style=\"text-align: right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
1014 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
1016 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
1017 fprintf(f
,"<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d %%</td><td style=\"text-align: right\">%ld G</td><td style=\"text-align: right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
1020 fprintf(f
,"</tbody><thead><tr>\n\
1021 <th>All users, all traffic</th>\n\
1022 <th style=\"text-align: right\">%d</th>\n\
1023 <th style=\"text-align: right\">100 %%</th>\n\
1024 <th style=\"text-align: right\">%ld G</th>\n\
1025 <th style=\"text-align: right\">100 %%</th></tr>\n",i
-1,total
);
1026 fputs("</thead></table>\n", f
);
1029 fprintf(f
, stats_html_signature
, version
);
1035 /*-----------------------------------------------------------------*/
1036 /* Are you looking for int main(int argc, char **argv) ? :-)) */
1037 /*-----------------------------------------------------------------*/
1043 char *str
, *ptr
, *d
;
1045 int class_count
=0,ip_count
=0;
1047 int just_flush
=FALSE
;
1049 int just_preview
=FALSE
; /* preview - generate just stats */
1050 int just_logs
=FALSE
; /* just parse logs */
1054 char *chain_forward
, *chain_postrouting
;
1055 char *althosts
=NULL
;
1058 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1059 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1060 iptables-restore & burst tunning & classify modification by Ludva\n\
1061 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
1063 /*----- Boring... we have to check command line options first: ----*/
1067 argument("-c") { nextargument(config
); }
1068 argument("-h") { nextargument(althosts
);}
1069 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
1070 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
1071 argument("-9") { run
=TRUE
; just_flush
=9; }
1072 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
1073 argument("-r") { run
=TRUE
; }
1074 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
1075 argument("-l") { just_logs
=TRUE
; }
1076 argument("-m") { just_logs
=TRUE
; }
1077 argument("-y") { just_logs
=TRUE
; }
1078 argument("-?") { help(); exit(0); }
1079 argument("--help") { help(); exit(0); }
1080 argument("-v") { exit(0); }
1081 argument("--version") { exit(0); }
1086 puts("*** THIS IS JUST DRY RUN ! ***\n");
1089 date(d
); /* this is typical cll1.h macro - prints current date */
1091 /*-----------------------------------------------------------------*/
1092 printf("Parsing configuration file %s ...\n", config
);
1093 /*-----------------------------------------------------------------*/
1098 parse_ip_log(argc
,argv
);
1114 /*-----------------------------------------------------------------*/
1115 puts("Parsing iptables verbose output ...");
1116 /*-----------------------------------------------------------------*/
1117 get_traffic_statistics();
1120 /*-----------------------------------------------------------------*/
1121 printf("Parsing class defintion file %s ...\n", hosts
);
1122 /*-----------------------------------------------------------------*/
1123 int groupidx
= FIRSTGROUPID
;
1128 if(*str
<'0' || *str
>'9')
1130 /* any line starting with non-number is comment ...*/
1134 //Does this IP share QoS class with some other ?
1135 substring
=strstr(str
,"sharing-");
1138 substring
+=8; //"sharing-"
1141 ip
->sharing
=substring
;
1142 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1143 while(*substring
&& *substring
!='\n')
1151 //Do we have to create new QoS class for this IP ?
1153 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1157 ip
->keyword
=keyword
;
1158 keyword
->ip_count
++;
1159 ip
->prio
=keyword
->default_prio
;
1160 substring
+=strlen(keyword
->key
)+1;
1162 while(*ptr
&& *ptr
!='-')
1169 ip
->max
= ip
->desired
=atoi(ptr
+1);
1171 ip
->min
= atoi(substring
);
1174 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
1178 if(ip
->max
<= ip
->min
)
1181 ip
->max
= ip
->min
+ip
->keyword
->reserve_min
;
1185 ip
->max
-= ip
->keyword
->reserve_max
;
1191 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1193 if_exists(group
,groups
,group
->min
==ip
->min
)
1196 group
->desired
+= ip
->min
;
1197 ip
->group
= group
->id
;
1201 create(group
,Group
);
1202 group
->min
= ip
->min
;
1203 group
->id
= groupidx
++;
1204 ip
->group
= group
->id
;
1206 if(group
->min
<8) group
->min
=8;
1207 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1208 /* it is because class IDs are derived from min. bandwidth. - xCh */
1209 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1212 group
->desired
=ip
->min
;
1213 insert(group
,groups
,desc_order_by
,min
);
1225 /*-----------------------------------------------------------------*/
1226 /* cll1.h - let's allocate brand new character buffer... */
1227 /*-----------------------------------------------------------------*/
1230 /*-----------------------------------------------------------------*/
1231 puts("Resolving shared connections ...");
1232 /*-----------------------------------------------------------------*/
1233 for_each(ip
,ips
) if(ip
->sharing
)
1235 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1237 sharedip
->traffic
+=ip
->traffic
;
1239 ip
->mark
=sharedip
->mark
;
1240 ip
->lmsid
=sharedip
->lmsid
;
1245 printf("Unresolved shared connection: %s %s sharing-%s\n",
1246 ip
->addr
, ip
->name
, ip
->sharing
);
1250 if(enable_credit
&& just_flush
<9)
1252 /*-----------------------------------------------------------------*/
1253 printf("Parsing credit file %s ...\n", credit
);
1254 /*-----------------------------------------------------------------*/
1257 ptr
=parse_datafile_line(_
);
1260 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1262 sscanf(ptr
,"%Lu",&(ip
->credit
));
1271 /*-----------------------------------------------------------------*/
1272 puts("Initializing iptables and tc classes ...");
1273 /*-----------------------------------------------------------------*/
1275 iptables_file
=fopen(iptablesfile
,"w");
1276 if(iptables_file
== NULL
)
1278 puts("Cannot open iptablesfile!");
1282 log_file
=fopen(cmdlog
,"w");
1283 if(log_file
== NULL
)
1285 puts("Cannot open logfile!");
1289 save_line(iptablespreamble
);
1292 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1295 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1298 iptables_file
=fopen(iptablesfile
,"w");
1299 save_line(iptablespreamble
);
1301 if(qos_free_zone
&& *qos_free_zone
!='0')
1305 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1310 save_line(":post_noproxy - [0:0]");
1311 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1313 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1315 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1318 chain
="post_noproxy";
1322 chain
="POSTROUTING";
1325 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1329 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1331 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1333 /*-----------------------------------------------------------------*/
1334 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1335 /*-----------------------------------------------------------------*/
1337 save_line(":post_common - [0:0]");
1338 save_line(":forw_common - [0:0]");
1340 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1342 buf
=hash_id(ip
->addr
,bitmask
);
1343 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1352 idx
->bitmask
=bitmask
;
1360 /* brutal perfomance optimalization */
1361 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1363 bitmask
-=idxtable_bitmask2
;
1366 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1368 buf
=hash_id(idx
->addr
,bitmask
);
1369 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1371 metaindex
->children
++;
1375 create(metaindex
,Index
);
1376 metaindex
->addr
=idx
->addr
;
1378 metaindex
->bitmask
=bitmask
;
1379 metaindex
->parent
=NULL
;
1380 metaindex
->children
=0;
1382 push(metaindex
,idxs
);
1384 idx
->parent
=metaindex
;
1388 /* this should slightly optimize throughout ... */
1389 sort(idx
,idxs
,desc_order_by
,children
);
1390 sort(idx
,idxs
,order_by
,bitmask
);
1395 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1396 printf("%d: %s/%d\n",
1397 ++i
, subnet
, idx
->bitmask
);
1399 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1402 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1407 string(buf
,strlen(idx
->parent
->id
)+6);
1408 sprintf(buf
,"post_%s",idx
->parent
->id
);
1415 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1418 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1423 string(buf
,strlen(idx
->parent
->id
)+6);
1424 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1431 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1434 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1437 printf("Total indexed iptables chains created: %d\n", i
);
1439 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1442 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1450 fclose(iptables_file
);
1451 if(log_file
) fclose(log_file
);
1452 puts("Just flushed iptables and tc classes - now exiting ...");
1458 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1460 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1461 sleep(qos_free_delay
);
1464 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1468 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1469 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1472 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1473 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1476 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1479 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1480 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1483 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1484 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1488 /*-----------------------------------------------------------------*/
1489 puts("Locating heavy downloaders and generating root classes ...");
1490 /*-----------------------------------------------------------------*/
1491 sort(ip
,ips
,desc_order_by
,traffic
);
1493 /*-----------------------------------------------------------------*/
1494 /* sub-scope - local variables */
1496 long long int rate
= line
;
1497 long long int max
= line
;
1498 int group_count
= 0;
1499 FILE *credit_file
= NULL
;
1501 if(!just_preview
&& !dry_run
&& enable_credit
)
1503 credit_file
= fopen(credit
,"w");
1506 for_each(group
,groups
)
1511 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",
1512 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1516 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",
1517 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1521 if(group_count
++ < max_nesting
)
1526 rate
-= digital_divide
*group
->min
;
1527 if(rate
< group
->min
)
1532 /*shaping of aggresive downloaders, with credit file support */
1535 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1537 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1539 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1540 && ( ip
->traffic
>ip
->credit
1541 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1543 if(group_rate
<ip
->max
)
1547 group_rate
+=magic_treshold
;
1548 ip
->prio
=lowest_priority
;
1549 if(ip
->prio
<highest_priority
+2)
1551 ip
->prio
=highest_priority
+2;
1556 if( ip
->keyword
->data_prio
1558 && ( ip
->traffic
>ip
->credit
1559 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1561 ip
->prio
=priority_sequence
--;
1562 if(ip
->prio
<highest_priority
+1)
1564 ip
->prio
=highest_priority
+1;
1570 unsigned long long lcredit
=0;
1572 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1574 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1576 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1584 fclose(credit_file
);
1590 f
=fopen(preview
,"w");
1593 else if(!dry_run
&& !just_flush
)
1595 /*-----------------------------------------------------------------*/
1596 printf("Writing data transfer database ...\n");
1597 /*-----------------------------------------------------------------*/
1598 f
=fopen("/var/run/prometheus.previous","w");
1603 if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1605 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",
1606 ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1620 /*-----------------------------------------------------------------*/
1621 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1622 /*-----------------------------------------------------------------*/
1624 if(use_jquery_popups
)
1626 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1628 fputs("<table class=\"decorated last\">\n\
1629 <caption>Bandwidth classes</caption>\n\
1631 <th style=\"text-align: right\">#</th>\n\
1632 <th style=\"text-align: right\">group</th>\n\
1633 <th style=\"text-align: right\">IPs</th>\n\
1634 <th style=\"text-align: right\">requested</th>\n",f
);
1635 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1636 fputs("</tr></thead><tbody>\n",f
);
1639 for_each(group
, groups
)
1642 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group
->min
,group
->count
,group
->desired
);
1644 fprintf(f
, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1645 tr_odd_even(), count
, group
->min
);
1646 fprintf(f
, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1647 group
->count
, group
->desired
);
1649 for_each(keyword
, keywords
)
1651 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d Mb/s</span></td>",
1652 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1654 i
+= group
->desired
;
1655 total
+= group
->count
;
1659 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1662 fprintf(f
,"<tr><th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line
);
1663 fprintf(f
,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total
,i
);
1665 for_each(keyword
, keywords
)
1667 fprintf(f
,"<th style=\"text-align: right\">%d IPs</th>",keyword
->ip_count
);
1669 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1670 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1672 fputs("</tbody></table>\n",f
);
1674 else if(!dry_run
&& !just_flush
)
1682 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1683 int active_classes
=0;
1686 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1687 int limit_count
=0, prio_count
=0;
1695 fprintf(f
,"<p><table class=\"decorated last\">\n<caption>%s",title
);
1696 fprintf(f
," (%s)</caption>\n", d
);
1697 fputs("<thead><tr>\n<th colspan=\"3\"> </th>\n",f
);
1698 fputs("<th style=\"text-align: right\">credit</th>\n\
1699 <th style=\"text-align: right\">FUP</th>\n\
1700 <th style=\"text-align: right\">total</th>\n\
1701 <th style=\"text-align: right\">down</th>\n",f
);
1704 fputs("<th style=\"text-align: right\">proxy</th>\n",f
);
1706 fputs("<th style=\"text-align: right\">up</th>\n\
1707 <th style=\"text-align: right\">min</th>\n\
1708 <th style=\"text-align: right\">max</th>\n\
1709 <th style=\"text-align: right\">limit</th>\n\
1710 <th>prio</th></tr>\n\
1712 <th style=\"text-align: right\">#</th>\n\
1713 <th>hostname [+sharing]</th>\n\
1714 <th style=\"text-align: right\">LMS</th>\n\
1715 <th style=\"text-align: right\">MB</th>\n\
1716 <th style=\"text-align: right\">MB</th>\n\
1717 <th style=\"text-align: right\">MB</th>\n\
1718 <th style=\"text-align: right\">MB</th>\n\
1719 <th style=\"text-align: right\">MB</th>\n\
1720 <th style=\"text-align: right\">kb/s</th>\n\
1721 <th style=\"text-align: right\">kb/s</th>\n\
1722 <th style=\"text-align: right\">kb/s</th>\n\
1724 </tr></thead><tbody>\n",f
);
1727 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1729 char *f1
="", *f2
="";
1732 if(ip
->max
< ip
->desired
)
1734 f1
="<span style=\"color:red\">";
1738 else if(ip
->prio
> highest_priority
+1)
1740 f1
="<span style=\"color:brown\">";
1746 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1748 /* hostnames -------------------------------------- */
1749 fprintf(f
,"%s<td style=\"text-align: right\"><a name=\"%s\"></a>%d</td><td><a class=\"blue\" href=\"%s%s.log\">%s</a>\n",
1750 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1752 if(use_jquery_popups
)
1754 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1756 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1758 fprintf(f
,"<br /><a class=\"blue\" href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1761 fputs("</span>\n",f
);
1764 fprintf(f
,"<span>[<a class=\"blue\" href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1765 i
, i
, i
, popup_button
);
1769 /* ----------------------------------------------- */
1773 fputs("<td style=\"text-align: right\">",f
);
1776 fprintf(f
,"<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1778 else if(ip
->lmsid
== 0)
1784 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->credit
);
1785 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1786 ip
->keyword
->html_color
,
1787 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1788 fprintf(f
,"<td style=\"text-align: right\">%s%Lu%s", f1
, ip
->traffic
, f2
);
1790 /* download --------------------------------------- */
1791 fprintf(f
,"</td><td style=\"text-align: right\">%Lu", ip
->direct
);
1792 if(use_jquery_popups
)
1794 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1795 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1797 fprintf(f
,"<br />%Lu", sharedip
->direct
);
1799 fputs("</span>\n",f
);
1802 /* ----------------------------------------------- */
1806 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->proxy
);
1808 /* upload ---------------------------------------- */
1809 fprintf(f
,"<td style=\"text-align: right\">%Lu", ip
->upload
);
1810 if(use_jquery_popups
)
1812 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1813 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1815 fprintf(f
,"<br />%Lu", sharedip
->upload
);
1817 fputs("</span>\n",f
);
1820 /* ----------------------------------------------- */
1822 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1823 <td style=\"text-align: right\">%d</td>\n\
1824 <td style=\"text-align: right\">%s%d%s</td>\n\
1825 <td>%s%d%s</td></tr>\n",
1826 ip
->min
, ip
->desired
,
1830 total_traffic
+=ip
->traffic
;
1831 total_direct
+=ip
->direct
;
1832 total_proxy
+=ip
->proxy
;
1833 total_upload
+=ip
->upload
;
1837 tmp_sum
+=ip
->traffic
;
1840 sum
->i
=active_classes
;
1841 insert(sum
,sums
,order_by
,i
);
1846 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1847 iplog
=fopen(str
,"a");
1850 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1851 time(NULL
), ip
->name
, ip
->traffic
, ip
->direct
, ip
->proxy
,
1852 ip
->upload
, ip
->min
, ip
->max
, ip
->desired
, ip
->lmsid
, d
); /* d = date*/
1857 fprintf(f
,"<tr><th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan
-7, i
);
1858 fprintf(f
,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic
, total_direct
);
1861 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy
);
1863 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>", total_upload
);
1864 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
);
1867 if(active_classes
>10)
1869 int top20_count
=0,top20_perc1
=0;
1870 long long top20_perc2
=0;
1871 unsigned long long top20_sum
=0l;
1873 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1874 fputs("<thead><tr>\n\
1875 <th>Analytic category</th>\n\
1876 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1877 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1878 </tr></thead><tbody>\n",f
);
1880 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1882 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1883 fprintf(f
,"<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d %%</td><td style=\"text-align: right\">%Lu M</td><td style=\"text-align: right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1886 if_exists(sum
,sums
,sum
->i
==10)
1888 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1889 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1890 <td style=\"text-align: right\">%d %%</td>\n\
1891 <td style=\"text-align: right\">%Lu MB</td>\n\
1892 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1893 (100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1896 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1898 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1899 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1900 <td style=\"text-align: right\">%d %%</td>\n\
1901 <td style=\"text-align: right\">%Lu MB</td>\n\
1902 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1903 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1906 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
1908 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1909 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1910 <td style=\"text-align: right\">%d %%</td>\n\
1911 <td style=\"text-align: right\">%Lu MB</td>\n\
1912 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1913 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1916 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1918 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1920 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1922 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1923 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1924 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1925 <td style=\"text-align: right\">%Lu MB</td>\n\
1926 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1927 top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
1930 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1932 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1933 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1934 <td style=\"text-align: right\">%d %%</td>\n\
1935 <td style=\"text-align: right\">%Lu MB</td>\n\
1936 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1937 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1940 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1942 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1943 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1944 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1945 <td style=\"text-align: right\">%Lu MB</td>\n\
1946 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1947 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1950 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1952 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1953 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1954 <td style=\"text-align: right\">%d %%</td>\n\
1955 <td style=\"text-align: right\">%Lu MB</td>\n\
1956 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
1957 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1960 fprintf(f
,"<tr><thead><th><a class=\"blue\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
1961 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
1962 <th style=\"text-align: right\">100 %%</th>\n\
1963 <th style=\"text-align: right\">%Lu M</th>\n\
1964 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
1965 fputs("</thead></table>\n", f
);
1967 /* write basic ERP data to log directory */
1970 sprintf(str
,"%s/ERP.log",log_dir
);
1971 iplog
=fopen(str
,"a");
1974 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",
1975 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
1976 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
1982 fprintf(f
, stats_html_signature
, version
);
1988 puts("Statistics preview generated (-p switch) - now exiting ...");
1992 /*-----------------------------------------------------------------*/
1993 puts("Generating iptables and tc classes ...");
1994 /*-----------------------------------------------------------------*/
1998 printf("%-22s %-15s mark\n","name","ip");
2001 for_each(ip
,ips
) if(ip
->mark
>0)
2006 duplicate(ip
->addr
,buf
);
2007 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
2009 string(chain_forward
,6+strlen(buf
));
2010 strcpy(chain_forward
,"forw_");
2011 strcat(chain_forward
,buf
);
2013 string(chain_postrouting
,6+strlen(buf
));
2014 strcpy(chain_postrouting
,"post_");
2015 strcat(chain_postrouting
,buf
);
2021 chain_forward
="FORWARD";
2022 chain_postrouting
="POSTROUTING";
2026 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
2029 /* -------------------------------------------------------- mark download */
2031 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
2032 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
2033 /* -m limit --limit 1/s */
2038 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
);
2039 /*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);*/
2043 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
2046 /* -------------------------------------------------------- mark upload */
2047 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
2048 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
2051 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
2056 /* -------------------------------------------------------- download class */
2058 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
2061 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
);
2064 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2066 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*/
2069 if(filter_type
== 1)
2071 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
2075 /* -------------------------------------------------------- upload class */
2077 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2078 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
2081 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2082 tc
, wan
, ip
->group
, ip
->mark
,
2083 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2084 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
2087 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2089 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*/
2092 if(filter_type
== 1)
2094 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
2101 printf("(sharing %s)\n", ip
->sharing
);
2109 chain_forward
= "forw_common";
2110 chain_postrouting
= "post_common";
2114 chain_forward
= "FORWARD";
2115 chain_postrouting
= "POSTROUTING";
2117 /* -------------------------------- classify or reject free download */
2119 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
2120 if(free_min
) final_chain
= "ACCEPT";
2125 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);
2128 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
2133 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
2136 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
2138 /* ------------------------------- classify or reject free upload */
2141 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
2144 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
2148 if(free_min
) /* allocate free bandwith if it is not zero... */
2150 /*-----------------------------------------------------------------*/
2151 puts("Generating free bandwith classes ...");
2152 /*-----------------------------------------------------------------*/
2153 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2154 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2156 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2157 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2160 if(strcmpi(qos_leaf
, "none"))
2162 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
2165 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
2168 /* tc handle 1 fw flowid */
2169 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
2172 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
2175 printf("Total IP count: %d\n", i
);
2182 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2183 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.665165 seconds and 4 git commands to generate.