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
);
1039 void append_log(struct IP
*self
) /*using global variables*/
1044 date(d
); /* this is typical cll1.h macro - prints current date */
1046 sprintf(str
,"%s/%s.log", log_dir
, self
->name
);
1050 fprintf(f
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1051 time(NULL
), self
->name
, self
->traffic
, self
->direct
, self
->proxy
,
1052 self
->upload
, self
->min
, self
->max
, self
->desired
, self
->lmsid
, d
); /* d = date*/
1062 /*-----------------------------------------------------------------*/
1063 /* Are you looking for int main(int argc, char **argv) ? :-)) */
1064 /*-----------------------------------------------------------------*/
1070 char *str
, *ptr
, *d
;
1072 int class_count
=0,ip_count
=0;
1074 int just_flush
=FALSE
;
1076 int just_preview
=FALSE
; /* preview - generate just stats */
1077 int just_logs
=FALSE
; /* just parse logs */
1081 char *chain_forward
, *chain_postrouting
;
1082 char *althosts
=NULL
;
1085 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1086 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1087 iptables-restore & burst tunning & classify modification by Ludva\n\
1088 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
1090 /*----- Boring... we have to check command line options first: ----*/
1094 argument("-c") { nextargument(config
); }
1095 argument("-h") { nextargument(althosts
);}
1096 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
1097 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
1098 argument("-9") { run
=TRUE
; just_flush
=9; }
1099 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
1100 argument("-r") { run
=TRUE
; }
1101 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
1102 argument("-l") { just_logs
=TRUE
; }
1103 argument("-m") { just_logs
=TRUE
; }
1104 argument("-y") { just_logs
=TRUE
; }
1105 argument("-?") { help(); exit(0); }
1106 argument("--help") { help(); exit(0); }
1107 argument("-v") { exit(0); }
1108 argument("--version") { exit(0); }
1113 puts("*** THIS IS JUST DRY RUN ! ***\n");
1116 date(d
); /* this is typical cll1.h macro - prints current date */
1118 /*-----------------------------------------------------------------*/
1119 printf("Parsing configuration file %s ...\n", config
);
1120 /*-----------------------------------------------------------------*/
1125 parse_ip_log(argc
,argv
);
1141 /*-----------------------------------------------------------------*/
1142 puts("Parsing iptables verbose output ...");
1143 /*-----------------------------------------------------------------*/
1144 get_traffic_statistics();
1147 /*-----------------------------------------------------------------*/
1148 printf("Parsing class defintion file %s ...\n", hosts
);
1149 /*-----------------------------------------------------------------*/
1150 int groupidx
= FIRSTGROUPID
;
1155 if(*str
<'0' || *str
>'9')
1157 /* any line starting with non-number is comment ...*/
1161 //Does this IP share QoS class with some other ?
1162 substring
=strstr(str
,"sharing-");
1165 substring
+=8; //"sharing-"
1168 ip
->sharing
=substring
;
1169 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1170 while(*substring
&& *substring
!='\n')
1178 //Do we have to create new QoS class for this IP ?
1180 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1184 ip
->keyword
=keyword
;
1185 keyword
->ip_count
++;
1186 ip
->prio
=keyword
->default_prio
;
1187 substring
+=strlen(keyword
->key
)+1;
1189 while(*ptr
&& *ptr
!='-')
1196 ip
->max
= ip
->desired
=atoi(ptr
+1);
1198 ip
->min
= atoi(substring
);
1201 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
1205 if(ip
->max
<= ip
->min
)
1208 ip
->max
= ip
->min
+ip
->keyword
->reserve_min
;
1212 ip
->max
-= ip
->keyword
->reserve_max
;
1218 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1220 if_exists(group
,groups
,group
->min
==ip
->min
)
1223 group
->desired
+= ip
->min
;
1224 ip
->group
= group
->id
;
1228 create(group
,Group
);
1229 group
->min
= ip
->min
;
1230 group
->id
= groupidx
++;
1231 ip
->group
= group
->id
;
1233 if(group
->min
<8) group
->min
=8;
1234 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1235 /* it is because class IDs are derived from min. bandwidth. - xCh */
1236 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1239 group
->desired
=ip
->min
;
1240 insert(group
,groups
,desc_order_by
,min
);
1252 /*-----------------------------------------------------------------*/
1253 /* cll1.h - let's allocate brand new character buffer... */
1254 /*-----------------------------------------------------------------*/
1257 /*-----------------------------------------------------------------*/
1258 puts("Resolving shared connections ...");
1259 /*-----------------------------------------------------------------*/
1260 for_each(ip
,ips
) if(ip
->sharing
)
1262 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1264 sharedip
->traffic
+=ip
->traffic
;
1266 ip
->mark
=sharedip
->mark
;
1267 ip
->lmsid
=sharedip
->lmsid
;
1272 printf("Unresolved shared connection: %s %s sharing-%s\n",
1273 ip
->addr
, ip
->name
, ip
->sharing
);
1277 if(enable_credit
&& just_flush
<9)
1279 /*-----------------------------------------------------------------*/
1280 printf("Parsing credit file %s ...\n", credit
);
1281 /*-----------------------------------------------------------------*/
1284 ptr
=parse_datafile_line(_
);
1287 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1289 sscanf(ptr
,"%Lu",&(ip
->credit
));
1298 /*-----------------------------------------------------------------*/
1299 puts("Initializing iptables and tc classes ...");
1300 /*-----------------------------------------------------------------*/
1302 iptables_file
=fopen(iptablesfile
,"w");
1303 if(iptables_file
== NULL
)
1305 puts("Cannot open iptablesfile!");
1309 log_file
=fopen(cmdlog
,"w");
1310 if(log_file
== NULL
)
1312 puts("Cannot open logfile!");
1316 save_line(iptablespreamble
);
1319 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1322 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1325 iptables_file
=fopen(iptablesfile
,"w");
1326 save_line(iptablespreamble
);
1328 if(qos_free_zone
&& *qos_free_zone
!='0')
1332 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1337 save_line(":post_noproxy - [0:0]");
1338 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1340 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1342 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1345 chain
="post_noproxy";
1349 chain
="POSTROUTING";
1352 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1356 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1358 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1360 /*-----------------------------------------------------------------*/
1361 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1362 /*-----------------------------------------------------------------*/
1364 save_line(":post_common - [0:0]");
1365 save_line(":forw_common - [0:0]");
1367 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1369 buf
=hash_id(ip
->addr
,bitmask
);
1370 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1379 idx
->bitmask
=bitmask
;
1387 /* brutal perfomance optimalization */
1388 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1390 bitmask
-=idxtable_bitmask2
;
1393 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1395 buf
=hash_id(idx
->addr
,bitmask
);
1396 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1398 metaindex
->children
++;
1402 create(metaindex
,Index
);
1403 metaindex
->addr
=idx
->addr
;
1405 metaindex
->bitmask
=bitmask
;
1406 metaindex
->parent
=NULL
;
1407 metaindex
->children
=0;
1409 push(metaindex
,idxs
);
1411 idx
->parent
=metaindex
;
1415 /* this should slightly optimize throughout ... */
1416 sort(idx
,idxs
,desc_order_by
,children
);
1417 sort(idx
,idxs
,order_by
,bitmask
);
1422 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1423 printf("%d: %s/%d\n",
1424 ++i
, subnet
, idx
->bitmask
);
1426 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1429 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1434 string(buf
,strlen(idx
->parent
->id
)+6);
1435 sprintf(buf
,"post_%s",idx
->parent
->id
);
1442 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1445 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1450 string(buf
,strlen(idx
->parent
->id
)+6);
1451 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1458 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1461 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1464 printf("Total indexed iptables chains created: %d\n", i
);
1466 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1469 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1477 fclose(iptables_file
);
1482 puts("Just flushed iptables and tc classes - now exiting ...");
1488 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1490 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1491 sleep(qos_free_delay
);
1494 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1498 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1499 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1502 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1503 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1506 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1509 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1510 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1513 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1514 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1518 /*-----------------------------------------------------------------*/
1519 puts("Locating heavy downloaders and generating root classes ...");
1520 /*-----------------------------------------------------------------*/
1521 sort(ip
,ips
,desc_order_by
,traffic
);
1523 /*-----------------------------------------------------------------*/
1524 /* sub-scope - local variables */
1526 long long int rate
= line
;
1527 long long int max
= line
;
1528 int group_count
= 0;
1529 FILE *credit_file
= NULL
;
1531 if(!just_preview
&& !dry_run
&& enable_credit
)
1533 credit_file
= fopen(credit
,"w");
1536 for_each(group
,groups
)
1541 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",
1542 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1546 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",
1547 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1551 if(group_count
++ < max_nesting
)
1556 rate
-= digital_divide
*group
->min
;
1557 if(rate
< group
->min
)
1562 /*shaping of aggresive downloaders, with credit file support */
1565 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1567 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1569 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1570 && ( ip
->traffic
>ip
->credit
1571 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1573 if(group_rate
<ip
->max
)
1577 group_rate
+=magic_treshold
;
1578 ip
->prio
=lowest_priority
;
1579 if(ip
->prio
<highest_priority
+2)
1581 ip
->prio
=highest_priority
+2;
1586 if( ip
->keyword
->data_prio
1588 && ( ip
->traffic
>ip
->credit
1589 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1591 ip
->prio
=priority_sequence
--;
1592 if(ip
->prio
<highest_priority
+1)
1594 ip
->prio
=highest_priority
+1;
1600 unsigned long long lcredit
=0;
1602 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1604 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1606 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1614 fclose(credit_file
);
1620 f
=fopen(preview
,"w");
1623 else if(!dry_run
&& !just_flush
)
1625 const char *previous
="/var/run/prometheus.previous";
1626 /*-----------------------------------------------------------------*/
1627 printf("Writing data transfer database %s ... ", previous
);
1628 /*-----------------------------------------------------------------*/
1629 f
=fopen(previous
,"w");
1634 if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1636 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",
1637 ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1656 /*-----------------------------------------------------------------*/
1657 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1658 /*-----------------------------------------------------------------*/
1660 if(use_jquery_popups
)
1662 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1664 fputs("<table class=\"decorated last\">\n\
1665 <caption>Bandwidth classes</caption>\n\
1667 <th style=\"text-align: right\">#</th>\n\
1668 <th style=\"text-align: right\">group</th>\n\
1669 <th style=\"text-align: right\">IPs</th>\n\
1670 <th style=\"text-align: right\">requested</th>\n",f
);
1671 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1672 fputs("</tr></thead><tbody>\n",f
);
1675 for_each(group
, groups
)
1678 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group
->min
,group
->count
,group
->desired
);
1680 fprintf(f
, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1681 tr_odd_even(), count
, group
->min
);
1682 fprintf(f
, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1683 group
->count
, group
->desired
);
1685 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1687 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d MB</span></td>",
1688 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1690 i
+= group
->desired
;
1691 total
+= group
->count
;
1695 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1698 fprintf(f
,"</tr></tbody>\n\
1700 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line
);
1701 fprintf(f
,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total
,i
);
1703 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1705 fprintf(f
,"<th style=\"text-align: right\">%d IPs</th>",keyword
->ip_count
);
1707 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1708 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1710 fputs("</thead></table>\n",f
);
1712 else if(!dry_run
&& !just_flush
)
1720 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1721 int active_classes
=0;
1723 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1724 int limit_count
=0, prio_count
=0;
1732 fprintf(f
,"<p><table class=\"decorated last\">\n<caption>%s",title
);
1733 fprintf(f
," (%s)</caption>\n", d
);
1734 fputs("<thead><tr>\n<th colspan=\"3\"> </th>\n",f
);
1735 fputs("<th style=\"text-align: right\">credit</th>\n\
1736 <th style=\"text-align: right\">FUP</th>\n\
1737 <th style=\"text-align: right\">total</th>\n\
1738 <th style=\"text-align: right\">down</th>\n",f
);
1741 fputs("<th style=\"text-align: right\">proxy</th>\n",f
);
1743 fputs("<th style=\"text-align: right\">up</th>\n\
1744 <th style=\"text-align: right\">min</th>\n\
1745 <th style=\"text-align: right\">max</th>\n\
1746 <th style=\"text-align: right\">limit</th>\n\
1749 <th style=\"text-align: right\">#</th>\n\
1750 <th>hostname [+sharing]</th>\n\
1751 <th style=\"text-align: right\">LMS</th>\n\
1752 <th style=\"text-align: right\">MB</th>\n\
1753 <th style=\"text-align: right\">MB</th>\n\
1754 <th style=\"text-align: right\">MB</th>\n\
1755 <th style=\"text-align: right\">MB</th>\n\
1756 <th style=\"text-align: right\">MB</th>\n\
1757 <th style=\"text-align: right\">kb/s</th>\n\
1758 <th style=\"text-align: right\">kb/s</th>\n\
1759 <th style=\"text-align: right\">kb/s</th>\n\
1761 </tr></thead><tbody>\n",f
);
1764 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1766 char *f1
="", *f2
="";
1769 if(ip
->max
< ip
->desired
)
1771 f1
="<span style=\"color:red\">";
1775 else if(ip
->prio
> highest_priority
+1)
1777 f1
="<span style=\"color:brown\">";
1783 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1785 /* hostnames -------------------------------------- */
1786 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",
1787 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1789 if(use_jquery_popups
)
1791 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1793 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1795 fprintf(f
,"<br /><a class=\"blue\" href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1798 fputs("</span>\n",f
);
1801 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>",
1802 i
, i
, i
, popup_button
);
1806 /* ----------------------------------------------- */
1810 fputs("<td style=\"text-align: right\">",f
);
1813 fprintf(f
,"<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1815 else if(ip
->lmsid
== 0)
1821 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->credit
);
1822 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1823 ip
->keyword
->html_color
,
1824 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1825 fprintf(f
,"<td style=\"text-align: right\">%s%Lu%s", f1
, ip
->traffic
, f2
);
1827 /* download --------------------------------------- */
1828 fprintf(f
,"</td><td style=\"text-align: right\">%Lu", ip
->direct
);
1829 if(use_jquery_popups
)
1831 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1832 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1834 fprintf(f
,"<br />%Lu", sharedip
->direct
);
1836 fputs("</span>\n",f
);
1839 /* ----------------------------------------------- */
1843 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->proxy
);
1845 /* upload ---------------------------------------- */
1846 fprintf(f
,"<td style=\"text-align: right\">%Lu", ip
->upload
);
1847 if(use_jquery_popups
)
1849 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1850 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1852 fprintf(f
,"<br />%Lu", sharedip
->upload
);
1855 append_log(sharedip
);
1858 fputs("</span>\n",f
);
1861 /* ----------------------------------------------- */
1863 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1864 <td style=\"text-align: right\">%d</td>\n\
1865 <td style=\"text-align: right\">%s%d%s</td>\n\
1866 <td>%s%d%s</td></tr>\n",
1867 ip
->min
, ip
->desired
,
1871 total_traffic
+=ip
->traffic
;
1872 total_direct
+=ip
->direct
;
1873 total_proxy
+=ip
->proxy
;
1874 total_upload
+=ip
->upload
;
1878 tmp_sum
+=ip
->traffic
;
1881 sum
->i
=active_classes
;
1882 insert(sum
,sums
,order_by
,i
);
1890 fprintf(f
,"</tbody><thead><tr>\n\
1891 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan
-7, i
);
1892 fprintf(f
,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic
, total_direct
);
1895 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy
);
1897 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>", total_upload
);
1898 fprintf(f
,"<th colspan=\"4\"><span style=\"color:red\">LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</thead></table>\n",limit_count
,prio_count
);
1901 if(active_classes
>10)
1903 int top20_count
=0,top20_perc1
=0;
1904 long long top20_perc2
=0;
1905 unsigned long long top20_sum
=0l;
1907 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1908 fputs("<thead><tr>\n\
1909 <th>Analytic category</th>\n\
1910 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1911 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1912 </tr></thead><tbody>\n",f
);
1914 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1916 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1917 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
);
1920 if_exists(sum
,sums
,sum
->i
==10)
1922 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1923 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1924 <td style=\"text-align: right\">%d %%</td>\n\
1925 <td style=\"text-align: right\">%Lu MB</td>\n\
1926 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1927 (100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1930 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1932 fprintf(f
,"%s<td>Top 50%% of traffic</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\"><strong>%Ld %%</strong></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
->l
>=4*total_traffic
/5)
1942 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1943 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1944 <td style=\"text-align: right\">%d %%</td>\n\
1945 <td style=\"text-align: right\">%Lu MB</td>\n\
1946 <td style=\"text-align: right\"><strong>%Ld %%</strong></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
>=(active_classes
+1)/5)
1952 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1954 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1956 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1957 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1958 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1959 <td style=\"text-align: right\">%Lu MB</td>\n\
1960 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1961 top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
1964 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1966 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1967 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1968 <td style=\"text-align: right\">%d %%</td>\n\
1969 <td style=\"text-align: right\">%Lu MB</td>\n\
1970 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1971 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1974 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1976 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1977 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1978 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1979 <td style=\"text-align: right\">%Lu MB</td>\n\
1980 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1981 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1984 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1986 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1987 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1988 <td style=\"text-align: right\">%d %%</td>\n\
1989 <td style=\"text-align: right\">%Lu MB</td>\n\
1990 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
1991 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1994 fprintf(f
,"<tr><thead><th><a class=\"blue\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
1995 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
1996 <th style=\"text-align: right\">100 %%</th>\n\
1997 <th style=\"text-align: right\">%Lu M</th>\n\
1998 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
1999 fputs("</thead></table>\n", f
);
2001 /* write basic ERP data to log directory */
2005 sprintf(str
,"%s/ERP.log",log_dir
);
2006 iplog
=fopen(str
,"a");
2009 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",
2010 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
2011 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
2021 fprintf(f
, stats_html_signature
, version
);
2027 puts("Statistics preview generated (-p switch) - now exiting ...");
2031 /*-----------------------------------------------------------------*/
2032 puts("Generating iptables and tc classes ...");
2033 /*-----------------------------------------------------------------*/
2037 printf("%-22s %-15s mark\n","name","ip");
2040 for_each(ip
,ips
) if(ip
->mark
>0)
2045 duplicate(ip
->addr
,buf
);
2046 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
2048 string(chain_forward
,6+strlen(buf
));
2049 strcpy(chain_forward
,"forw_");
2050 strcat(chain_forward
,buf
);
2052 string(chain_postrouting
,6+strlen(buf
));
2053 strcpy(chain_postrouting
,"post_");
2054 strcat(chain_postrouting
,buf
);
2060 chain_forward
="FORWARD";
2061 chain_postrouting
="POSTROUTING";
2065 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
2068 /* -------------------------------------------------------- mark download */
2070 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
2071 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
2072 /* -m limit --limit 1/s */
2077 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
);
2078 /*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);*/
2082 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
2085 /* -------------------------------------------------------- mark upload */
2086 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
2087 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
2090 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
2095 /* -------------------------------------------------------- download class */
2097 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
2100 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
);
2103 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2105 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*/
2108 if(filter_type
== 1)
2110 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
2114 /* -------------------------------------------------------- upload class */
2116 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2117 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
2120 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2121 tc
, wan
, ip
->group
, ip
->mark
,
2122 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2123 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
2126 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2128 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*/
2131 if(filter_type
== 1)
2133 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
2140 printf("(sharing %s)\n", ip
->sharing
);
2148 chain_forward
= "forw_common";
2149 chain_postrouting
= "post_common";
2153 chain_forward
= "FORWARD";
2154 chain_postrouting
= "POSTROUTING";
2156 /* -------------------------------- classify or reject free download */
2158 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
2159 if(free_min
) final_chain
= "ACCEPT";
2164 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);
2167 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
2172 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
2175 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
2177 /* ------------------------------- classify or reject free upload */
2180 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
2183 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
2187 if(free_min
) /* allocate free bandwith if it is not zero... */
2189 /*-----------------------------------------------------------------*/
2190 puts("Generating free bandwith classes ...");
2191 /*-----------------------------------------------------------------*/
2192 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2193 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2195 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2196 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
2199 if(strcmpi(qos_leaf
, "none"))
2201 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
2204 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
2207 /* tc handle 1 fw flowid */
2208 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
2211 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
2214 printf("Total IP count: %d\n", i
);
2221 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2222 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 2.203526 seconds and 5 git commands to generate.