36574488d931034f05ca4b3a90fee1dd93b3430e
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
= "<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></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*/
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 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 ",
906 for_each(iplog
, iplogs
)
910 fprintf(f
, "%s<td align=\"right\">%d</td><td align=\"left\"><a href=\"%s%s.log\">%s</td></td><td align=\"right\">",
911 tr_odd_even(), i
++, log_url
, iplog
->name
, iplog
->name
);
914 /*base URL will be configurable soon ... */
915 fprintf(f
, "<a href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
917 else if(iplog
->lmsid
== 0)
921 fprintf(f
, "<td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
922 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
923 total
+=iplog
->traffic
>>10;
928 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
);
929 fputs("</tbody></table>\n", f
);
934 fputs("<a name=\"erp\"></a><p><table border=\"0\"><thead><caption>Enterprise Resource Planning (ERP)</caption></tr>\n",f
);
935 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f
);
936 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n</thead><tbody>\n",f
);
938 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
940 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
941 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
));
944 if_exists(iplog
,iplogs
,iplog
->i
==10)
946 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
947 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
));
950 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
952 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
953 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
));
956 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
958 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
959 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
));
962 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
964 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
965 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
));
968 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
970 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
971 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
));
974 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
976 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
977 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
));
980 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
982 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
983 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
));
986 fprintf(f
,"<tr class=\"bgGrey\"><td>All users, all traffic</td>\n");
987 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
);
988 fputs("</tbody></table>\n", f
);
991 fprintf(f
, stats_html_signature
, version
);
997 /*-----------------------------------------------------------------*/
998 /* Are you looking for int main(int argc, char **argv) ? :-)) */
999 /*-----------------------------------------------------------------*/
1005 char *str
, *ptr
, *d
;
1007 int class_count
=0,ip_count
=0;
1009 int just_flush
=FALSE
;
1011 int just_preview
=FALSE
; /* preview - generate just stats */
1012 int just_logs
=FALSE
; /* just parse logs */
1016 char *chain_forward
, *chain_postrouting
;
1017 char *althosts
=NULL
;
1020 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1021 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1022 iptables-restore & burst tunning & classify modification by Ludva\n\
1023 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
1025 /*----- Boring... we have to check command line options first: ----*/
1029 argument("-c") { nextargument(config
); }
1030 argument("-h") { nextargument(althosts
);}
1031 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
1032 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
1033 argument("-9") { run
=TRUE
; just_flush
=9; }
1034 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
1035 argument("-r") { run
=TRUE
; }
1036 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
1037 argument("-l") { just_logs
=TRUE
; }
1038 argument("-m") { just_logs
=TRUE
; }
1039 argument("-y") { just_logs
=TRUE
; }
1040 argument("-?") { help(); exit(0); }
1041 argument("--help") { help(); exit(0); }
1042 argument("-v") { exit(0); }
1043 argument("--version") { exit(0); }
1048 puts("*** THIS IS JUST DRY RUN ! ***\n");
1051 date(d
); /* this is typical cll1.h macro - prints current date */
1053 /*-----------------------------------------------------------------*/
1054 printf("Parsing configuration file %s ...\n", config
);
1055 /*-----------------------------------------------------------------*/
1060 parse_ip_log(argc
,argv
);
1076 /*-----------------------------------------------------------------*/
1077 puts("Parsing iptables verbose output ...");
1078 /*-----------------------------------------------------------------*/
1079 get_traffic_statistics();
1082 /*-----------------------------------------------------------------*/
1083 printf("Parsing class defintion file %s ...\n", hosts
);
1084 /*-----------------------------------------------------------------*/
1085 int groupidx
= FIRSTGROUPID
;
1090 if(*str
<'0' || *str
>'9')
1092 /* any line starting with non-number is comment ...*/
1096 //Does this IP share QoS class with some other ?
1097 substring
=strstr(str
,"sharing-");
1100 substring
+=8; //"sharing-"
1103 ip
->sharing
=substring
;
1104 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1105 while(*substring
&& *substring
!='\n')
1113 //Do we have to create new QoS class for this IP ?
1115 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1119 ip
->keyword
=keyword
;
1120 keyword
->ip_count
++;
1121 ip
->prio
=keyword
->default_prio
;
1122 substring
+=strlen(keyword
->key
)+1;
1124 while(*ptr
&& *ptr
!='-')
1131 ip
->max
= ip
->desired
=atoi(ptr
+1);
1133 ip
->min
= atoi(substring
);
1136 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",
1140 if(ip
->max
<= ip
->min
)
1143 ip
->max
= ip
->min
+ip
->keyword
->reserve_min
;
1147 ip
->max
-= ip
->keyword
->reserve_max
;
1153 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1155 if_exists(group
,groups
,group
->min
==ip
->min
)
1158 group
->desired
+= ip
->min
;
1159 ip
->group
= group
->id
;
1163 create(group
,Group
);
1164 group
->min
= ip
->min
;
1165 group
->id
= groupidx
++;
1166 ip
->group
= group
->id
;
1168 if(group
->min
<8) group
->min
=8;
1169 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1170 /* it is because class IDs are derived from min. bandwidth. - xCh */
1171 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1174 group
->desired
=ip
->min
;
1175 insert(group
,groups
,desc_order_by
,min
);
1187 /*-----------------------------------------------------------------*/
1188 /* cll1.h - let's allocate brand new character buffer... */
1189 /*-----------------------------------------------------------------*/
1192 /*-----------------------------------------------------------------*/
1193 puts("Resolving shared connections ...");
1194 /*-----------------------------------------------------------------*/
1195 for_each(ip
,ips
) if(ip
->sharing
)
1197 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1199 sharedip
->traffic
+=ip
->traffic
;
1201 ip
->mark
=sharedip
->mark
;
1202 ip
->lmsid
=sharedip
->lmsid
;
1207 printf("Unresolved shared connection: %s %s sharing-%s\n",
1208 ip
->addr
, ip
->name
, ip
->sharing
);
1212 if(enable_credit
&& just_flush
<9)
1214 /*-----------------------------------------------------------------*/
1215 printf("Parsing credit file %s ...\n", credit
);
1216 /*-----------------------------------------------------------------*/
1219 ptr
=parse_datafile_line(_
);
1222 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1224 sscanf(ptr
,"%Lu",&(ip
->credit
));
1233 /*-----------------------------------------------------------------*/
1234 puts("Initializing iptables and tc classes ...");
1235 /*-----------------------------------------------------------------*/
1237 iptables_file
=fopen(iptablesfile
,"w");
1238 if(iptables_file
== NULL
)
1240 puts("Cannot open iptablesfile!");
1244 log_file
=fopen(cmdlog
,"w");
1245 if(log_file
== NULL
)
1247 puts("Cannot open logfile!");
1251 save_line(iptablespreamble
);
1254 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1257 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1260 iptables_file
=fopen(iptablesfile
,"w");
1261 save_line(iptablespreamble
);
1263 if(qos_free_zone
&& *qos_free_zone
!='0')
1267 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1272 save_line(":post_noproxy - [0:0]");
1273 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1275 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1277 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1280 chain
="post_noproxy";
1284 chain
="POSTROUTING";
1287 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1291 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1293 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1295 /*-----------------------------------------------------------------*/
1296 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1297 /*-----------------------------------------------------------------*/
1299 save_line(":post_common - [0:0]");
1300 save_line(":forw_common - [0:0]");
1302 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1304 buf
=hash_id(ip
->addr
,bitmask
);
1305 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1314 idx
->bitmask
=bitmask
;
1322 /* brutal perfomance optimalization */
1323 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1325 bitmask
-=idxtable_bitmask2
;
1328 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1330 buf
=hash_id(idx
->addr
,bitmask
);
1331 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1333 metaindex
->children
++;
1337 create(metaindex
,Index
);
1338 metaindex
->addr
=idx
->addr
;
1340 metaindex
->bitmask
=bitmask
;
1341 metaindex
->parent
=NULL
;
1342 metaindex
->children
=0;
1344 push(metaindex
,idxs
);
1346 idx
->parent
=metaindex
;
1350 /* this should slightly optimize throughout ... */
1351 sort(idx
,idxs
,desc_order_by
,children
);
1352 sort(idx
,idxs
,order_by
,bitmask
);
1357 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1358 printf("%d: %s/%d\n",
1359 ++i
, subnet
, idx
->bitmask
);
1361 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1364 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1369 string(buf
,strlen(idx
->parent
->id
)+6);
1370 sprintf(buf
,"post_%s",idx
->parent
->id
);
1377 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1380 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1385 string(buf
,strlen(idx
->parent
->id
)+6);
1386 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1393 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1396 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1399 printf("Total indexed iptables chains created: %d\n", i
);
1401 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1404 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1412 fclose(iptables_file
);
1413 if(log_file
) fclose(log_file
);
1414 puts("Just flushed iptables and tc classes - now exiting ...");
1420 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1422 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1423 sleep(qos_free_delay
);
1426 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1430 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1431 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1434 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1435 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1438 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1441 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1442 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1445 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1446 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1450 /*-----------------------------------------------------------------*/
1451 puts("Locating heavy downloaders and generating root classes ...");
1452 /*-----------------------------------------------------------------*/
1453 sort(ip
,ips
,desc_order_by
,traffic
);
1455 /*-----------------------------------------------------------------*/
1456 /* sub-scope - local variables */
1458 long long int rate
= line
;
1459 long long int max
= line
;
1460 int group_count
= 0;
1461 FILE *credit_file
= NULL
;
1463 if(!just_preview
&& !dry_run
&& enable_credit
)
1465 credit_file
= fopen(credit
,"w");
1468 for_each(group
,groups
)
1473 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",
1474 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1478 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",
1479 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1483 if(group_count
++ < max_nesting
)
1488 rate
-= digital_divide
*group
->min
;
1489 if(rate
< group
->min
)
1494 /*shaping of aggresive downloaders, with credit file support */
1497 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1499 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1501 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1502 && ( ip
->traffic
>ip
->credit
1503 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1505 if(group_rate
<ip
->max
)
1509 group_rate
+=magic_treshold
;
1510 ip
->prio
=lowest_priority
;
1511 if(ip
->prio
<highest_priority
+2)
1513 ip
->prio
=highest_priority
+2;
1518 if( ip
->keyword
->data_prio
1520 && ( ip
->traffic
>ip
->credit
1521 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1523 ip
->prio
=priority_sequence
--;
1524 if(ip
->prio
<highest_priority
+1)
1526 ip
->prio
=highest_priority
+1;
1532 unsigned long long lcredit
=0;
1534 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1536 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1538 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1546 fclose(credit_file
);
1552 f
=fopen(preview
,"w");
1555 else if(!dry_run
&& !just_flush
)
1557 /*-----------------------------------------------------------------*/
1558 printf("Writing data transfer database ...\n");
1559 /*-----------------------------------------------------------------*/
1560 f
=fopen("/var/run/prometheus.previous","w");
1565 if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1567 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",
1568 ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1583 /*-----------------------------------------------------------------*/
1584 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1585 /*-----------------------------------------------------------------*/
1587 if(use_jquery_popups
)
1589 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1591 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
);
1592 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1593 fputs("</tr></thead><tbody>\n",f
);
1596 for_each(group
, groups
)
1599 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1601 fprintf(f
, "%s<td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1602 tr_odd_even(), count
, group
->min
);
1603 fprintf(f
, "<td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1604 group
->count
, group
->desired
);
1606 for_each(keyword
, keywords
)
1608 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%d M</span></td>",
1609 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1611 i
+= group
->desired
;
1612 total
+= group
->count
;
1616 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",
1619 fprintf(f
,"<tr class=\"bgGrey\"><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1620 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1622 for_each(keyword
, keywords
)
1624 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1626 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1627 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1629 fputs("</tbody></table>\n",f
);
1631 else if(!dry_run
&& !just_flush
)
1639 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1640 int active_classes
=0;
1643 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1644 int limit_count
=0, prio_count
=0;
1656 fprintf(f
,"<p><table border>\n<thead><caption>%s",title
);
1657 fprintf(f
," (%s)</caption>\n", d
);
1658 fputs("<tr class=\"bgGrey\"><td align=\"right\">#</td><td>hostname</td>",f
);
1661 fputs("<td align=\"right\">lms</td>\n",f
);
1663 fputs("<td align=\"right\">credit</td>\
1664 <td align=\"right\">limit</td>\
1665 <td align=\"right\">total</td>\
1666 <td align=\"right\">direct</td>\n",f
);
1669 fputs("<td align=\"right\">proxy</td>\n",f
);
1671 fputs("<td align=\"right\">upload</td>\
1672 <td align=\"right\">minimum</td>\
1673 <td align=\"right\">desired</td>\
1674 <td align=\"right\">maximum</td>\
1675 <td>prio</td></tr>\n\
1676 </thead><tbody>\n",f
);
1679 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1681 char *f1
="", *f2
="";
1684 if(ip
->max
< ip
->desired
)
1686 f1
="<span style=\"color:red\">";
1690 else if(ip
->prio
> highest_priority
+1)
1692 f1
="<span style=\"color:brown\">";
1698 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1700 /* hostnames -------------------------------------- */
1701 fprintf(f
,"%s<td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a>\n",
1702 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1703 if(use_jquery_popups
)
1705 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1707 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1709 fprintf(f
,"<br /><a href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1712 fputs("</span>\n",f
);
1715 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>",
1716 i
, i
, i
, popup_button
);
1720 /* ----------------------------------------------- */
1724 fputs("<td align=\"right\">",f
);
1727 /*base URL will be configurable soon ... */
1728 fprintf(f
,"<a href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1730 else if(ip
->lmsid
== 0)
1736 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->credit
);
1737 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%Lu M</span></td>",
1738 ip
->keyword
->html_color
,
1739 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1740 fprintf(f
,"<td align=\"right\">%s%Lu M%s", f1
, ip
->traffic
, f2
);
1742 /* download --------------------------------------- */
1743 fprintf(f
,"</td><td align=\"right\">%Lu M", ip
->direct
);
1744 if(use_jquery_popups
)
1746 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1747 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1749 fprintf(f
,"<br />%Lu M", sharedip
->direct
);
1751 fputs("</span>\n",f
);
1754 /* ----------------------------------------------- */
1758 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1760 /* upload ---------------------------------------- */
1761 fprintf(f
,"<td align=\"right\">%Lu M", ip
->upload
);
1762 if(use_jquery_popups
)
1764 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1765 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1767 fprintf(f
,"<br />%Lu M", sharedip
->upload
);
1769 fputs("</span>\n",f
);
1772 /* ----------------------------------------------- */
1774 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",
1775 ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1777 total_traffic
+=ip
->traffic
;
1778 total_direct
+=ip
->direct
;
1779 total_proxy
+=ip
->proxy
;
1780 total_upload
+=ip
->upload
;
1784 tmp_sum
+=ip
->traffic
;
1787 sum
->i
=active_classes
;
1788 insert(sum
,sums
,order_by
,i
);
1793 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1794 iplog
=fopen(str
,"a");
1797 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1798 time(NULL
), ip
->name
, ip
->traffic
, ip
->direct
, ip
->proxy
,
1799 ip
->upload
, ip
->min
, ip
->max
, ip
->desired
, ip
->lmsid
, d
); /* d = date*/
1804 fprintf(f
,"<tr class=\"bgGrey\"><th colspan=\"%d\" align=\"left\">%d CLASSES</th>", colspan
-7, i
);
1805 fprintf(f
,"<th align=\"right\">%Lu M</th><th align=\"right\">%Lu M</th>\n", total_traffic
, total_direct
);
1808 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1810 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1811 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
);
1814 if(active_classes
>10)
1816 int top20_count
=0,top20_perc1
=0;
1817 long long top20_perc2
=0;
1818 unsigned long long top20_sum
=0l;
1820 fputs("<a name=\"erp\"></a><p><table border><thead><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1821 fputs("<tr class=\"bgGrey\"><td>Analytic category</td>\n",f
);
1822 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr></thead><tbody>\n",f
);
1824 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1826 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1827 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
);
1830 if_exists(sum
,sums
,sum
->i
==10)
1832 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1833 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
);
1836 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1838 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1839 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
);
1842 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
1844 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1845 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
);
1848 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1850 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1852 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1854 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1855 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
);
1858 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1860 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1861 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
);
1864 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1866 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1867 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
);
1870 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1872 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1873 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
);
1876 fprintf(f
,"<tr class=\"bgGrey\"><td><a href=\"%sERP.log\">All users, all traffic</a></td>\n", log_url
);
1877 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
);
1878 fputs("</tbody></table>\n", f
);
1880 /* write basic ERP data to log directory */
1883 sprintf(str
,"%s/ERP.log",log_dir
);
1884 iplog
=fopen(str
,"a");
1887 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",
1888 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
1889 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
1895 fprintf(f
, stats_html_signature
, version
);
1901 puts("Statistics preview generated (-p switch) - now exiting ...");
1905 /*-----------------------------------------------------------------*/
1906 puts("Generating iptables and tc classes ...");
1907 /*-----------------------------------------------------------------*/
1911 printf("%-22s %-15s mark\n","name","ip");
1914 for_each(ip
,ips
) if(ip
->mark
>0)
1919 duplicate(ip
->addr
,buf
);
1920 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1922 string(chain_forward
,6+strlen(buf
));
1923 strcpy(chain_forward
,"forw_");
1924 strcat(chain_forward
,buf
);
1926 string(chain_postrouting
,6+strlen(buf
));
1927 strcpy(chain_postrouting
,"post_");
1928 strcat(chain_postrouting
,buf
);
1934 chain_forward
="FORWARD";
1935 chain_postrouting
="POSTROUTING";
1939 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1942 /* -------------------------------------------------------- mark download */
1944 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1945 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1946 /* -m limit --limit 1/s */
1951 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
);
1952 /*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);*/
1956 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1959 /* -------------------------------------------------------- mark upload */
1960 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1961 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1964 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1969 /* -------------------------------------------------------- download class */
1971 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1974 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
);
1977 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1979 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*/
1982 if(filter_type
== 1)
1984 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1988 /* -------------------------------------------------------- upload class */
1990 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1991 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1994 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1995 tc
, wan
, ip
->group
, ip
->mark
,
1996 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1997 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
2000 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2002 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*/
2005 if(filter_type
== 1)
2007 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
2014 printf("(sharing %s)\n", ip
->sharing
);
2022 chain_forward
= "forw_common";
2023 chain_postrouting
= "post_common";
2027 chain_forward
= "FORWARD";
2028 chain_postrouting
= "POSTROUTING";
2030 /* -------------------------------- classify or reject free download */
2032 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
2033 if(free_min
) final_chain
= "ACCEPT";
2038 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);
2041 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
2046 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
2049 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
2051 /* ------------------------------- classify or reject free upload */
2054 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
2057 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
2061 if(free_min
) /* allocate free bandwith if it is not zero... */
2063 /*-----------------------------------------------------------------*/
2064 puts("Generating free bandwith classes ...");
2065 /*-----------------------------------------------------------------*/
2066 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2067 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2069 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2070 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2073 if(strcmpi(qos_leaf
, "none"))
2075 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
2078 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
2081 /* tc handle 1 fw flowid */
2082 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
2085 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
2088 printf("Total IP count: %d\n", i
);
2095 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2096 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.614255 seconds and 4 git commands to generate.