f12de1530e477e15cf1fbf45689f2f31aa56f352
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, 20120516
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-d";
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 target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";
45 /* ======= All path names are defined here (for RPM patch) ======= */
47 const char *tc
= "/sbin/tc"; /* requires tc with HTB support */
48 const char *iptables
= "/sbin/iptables"; /* requires iptables utility */
49 const char *iptablessave
= "/sbin/iptables-save"; /* not yet required */
50 const 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 *classmap
= "/var/lib/misc/prometheus.classes"; /* credit log file */
59 char *html
= "/var/www/traffic.html"; /* hall of fame - html version */
60 char *preview
= "/var/www/preview.html"; /* hall of fame preview */
61 char *json
= "/var/www/traffic.json"; /* hall of fame - json version */
62 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
63 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
64 char *log_url
= "/logs/"; /* log directory relative URI prefix (partial URL) */
65 char *html_log_dir
= "/var/www/logs/html/";
67 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
68 char *lms_url
= "/lms/?m=customerinfo&id=";
69 int use_jquery_popups
= 1;
70 int row_odd_even
= 0; /*<tr class="odd/even"> */
73 const char *tr_odd_even(void)
75 row_odd_even
= 1 - row_odd_even
;
78 return "<tr class=\"even\">\n";
82 return "<tr class=\"odd\">\n";
86 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
90 puts("Command line switches:\n\
92 -?, --help this help screen\n\
93 -v, --version show Version number of this utility and exit\n\
94 -c filename force alternative /etc/prometheus.Conf filename\n\
95 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
96 -f just Flush iptables and tc classes and exit (stop shaping)\n\
97 -9 emergency iptables flush (do not read data transfer statistics)\n\
98 -p just generate Preview of data transfer statistics and exit\n\
99 -d Dry run (preview tc and iptables commands on stdout)\n\
100 -r Run (reset all statistics and start shaping)\n\
101 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
102 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
103 -m generate HTML summary of traffic logs for yesterday's Month\n\
104 -y generate HTML summary of traffic logs for yesterday's Year\n");
105 /* not yet implemented:
106 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
110 /* === Configuraration file values defaults - stored in global variables ==== */
112 int filter_type
= 1; /*1 mark, 2 classify*/
114 char *mark_iptables
= "MARK --set-mark ";
115 int dry_run
= 0; /* preview - use puts() instead of system() */
116 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]";
117 FILE *iptables_file
= NULL
;
118 int enable_credit
= 1; /* enable credit file */
119 int use_credit
= 0; /* use credit file (if enabled)*/
120 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
121 int hall_of_fame
= 1; /* enable hall of fame */
122 char *lan
= "eth0"; /* LAN interface */
123 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
124 char *wan
= "eth1"; /* WAN/ISP interface */
125 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
126 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
127 char *qos_free_zone
= NULL
; /* QoS free zone */
128 int qos_proxy
= 1; /* include proxy port to QoS */
129 int found_lmsid
= 0; /* show links to users in LMS information system */
130 int include_upload
= 1; /* upload+download=total traffic */
131 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
132 int proxy_port
= 3128; /* proxy port number */
133 long long int line
= 1024; /* WAN/ISP download in kbps */
134 long long int up
= 1024; /* WAN/ISP upload in kbps */
135 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
136 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
137 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
138 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
139 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
140 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
141 int burst
= 8; /* HTB burst (in kbits) */
143 int burst_group
= 32;
144 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
145 int keywordcount
= 0;
146 /* not yet implemented:
147 int fixed_packets = 0; maximum number of pps per IP address (not class!)
148 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
150 FILE *log_file
= NULL
;
151 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
153 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
154 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
155 const int idxtable_treshold1
= 24; /* this is no longer configurable */
156 const int idxtable_treshold2
= 12; /* this is no longer configurable */
157 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
158 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
160 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
175 unsigned long long direct
;
176 unsigned long long proxy
;
177 unsigned long long upload
;
178 unsigned long long traffic
;
179 unsigned long long credit
;
180 unsigned long pktsup
;
181 unsigned long pktsdown
;
182 struct Keyword
*keyword
;
184 } *ips
=NULL
, *ip
, *sharedip
;
193 } *groups
=NULL
, *group
;
199 struct Index
*parent
;
203 } *idxs
=NULL
, *idx
, *metaindex
;
209 int asymetry_ratio
; /* ratio for ADSL-like upload */
210 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
211 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
212 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
213 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
214 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
215 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
216 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
217 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
218 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
219 int default_prio
; /* default HTB priority for this keyword */
222 char *leaf_discipline
;
225 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
227 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
235 ip
->prio
= highest_priority
+1;
249 ip
->keyword
= keywords
;
253 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
255 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
257 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
259 char *ip
,*outip
,*outptr
,*fmt
;
262 /* debug printf("(%s,%d) -> ",ip,bitmask); */
264 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
266 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
270 /* should never exit here */
278 if(dot
<(bitmask
/8-1))
280 if(format_as_chainname
)
293 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
299 if(format_as_chainname
)
310 n
= atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
317 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
318 sprintf(outptr
,fmt
,n
,bitmask
);
319 if(!format_as_chainname
)
327 /* debug printf("[%s]\n",outip); */
338 /*should never exit here*/
343 char *hash_id(char *ip
,int bitmask
)
345 return very_ugly_ipv4_code(ip
,bitmask
,1);
348 char *subnet_id(char *ip
,int bitmask
)
350 return very_ugly_ipv4_code(ip
,bitmask
,0);
353 /* ================= Let's parse configuration file here =================== */
355 void reject_config_and_exit(char *filename
)
357 printf("Configuration file %s rejected - abnormal exit.",filename
);
361 void get_config(char *config_filename
)
365 printf("Configured keywords: ");
366 parse(config_filename
)
368 option("keyword",kwd
);
373 create(keyword
,Keyword
);
375 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
376 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
377 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
378 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
379 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
380 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
381 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
382 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
383 keyword
->default_prio
=highest_priority
+1;
384 keyword
->html_color
="000000";
386 keyword
->leaf_discipline
="";
388 push(keyword
,keywords
);
389 if(!defaultkeyword
) defaultkeyword
=keyword
;
396 for_each(keyword
,keywords
)
398 int l
=strlen(keyword
->key
);
400 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
402 char *tmptr
=_
; /* <---- l+1 ----> */
403 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
404 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
405 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
406 ioption("magic-relative-limit",keyword
->data_limit
);
407 ioption("magic-relative-prio",keyword
->data_prio
);
408 loption("magic-fixed-limit",keyword
->fixed_limit
);
409 loption("magic-fixed-prio",keyword
->fixed_prio
);
410 ioption("htb-default-prio",keyword
->default_prio
);
411 ioption("htb-rate-bonus",keyword
->reserve_min
);
412 ioption("htb-ceil-malus",keyword
->reserve_max
);
413 option("leaf-discipline",keyword
->leaf_discipline
);
414 option("html-color",keyword
->html_color
);
417 if(keyword
->data_limit
|| keyword
->fixed_limit
||
418 keyword
->data_prio
|| keyword
->fixed_prio
)
427 option("iptables",iptables
);
428 option("iptables-save",iptablessave
); /* new */
429 option("iptables-restore",iptablesrestore
); /* new */
430 option("iptables-in-filename",iptablesfile
); /* new */
431 option("hosts",hosts
);
432 option("lan-interface",lan
);
433 option("wan-interface",wan
);
434 option("lan-medium",lan_medium
);
435 option("wan-medium",wan_medium
);
436 lloption("wan-download",line
);
437 lloption("wan-upload",up
);
438 ioption("hall-of-fame-enable",hall_of_fame
);
439 option("hall-of-fame-title",title
);
440 option("hall-of-fame-filename",html
);
441 option("json-filename",json
);
442 option("hall-of-fame-preview",preview
);
443 option("log-filename",cmdlog
);
444 option("credit-filename",credit
);
445 option("classmap-filename",classmap
);
446 ioption("credit-enable",enable_credit
);
447 option("log-traffic-directory",log_dir
);
448 option("log-traffic-html-directory",html_log_dir
);
449 option("log-traffic-url-path",log_url
);
450 option("jquery-url",jquery_url
);
451 option("lms-url",lms_url
);
452 ioption("use-jquery-popups",use_jquery_popups
);
453 option("qos-free-zone",qos_free_zone
);
454 ioption("qos-free-delay",qos_free_delay
);
455 ioption("qos-proxy-enable",qos_proxy
);
456 option("qos-proxy-ip",proxy_ip
);
457 option("htb-leaf-discipline",qos_leaf
);
458 ioption("qos-proxy-port",proxy_port
);
459 ioption("free-rate",free_min
);
460 ioption("free-ceil",free_max
);
461 ioption("htb-burst",burst
);
462 ioption("htb-burst-main",burst_main
);
463 ioption("htb-burst-group",burst_group
);
464 ioption("htb-nesting-limit",max_nesting
);
465 ioption("htb-r2q",htb_r2q
);
466 ioption("magic-include-upload",include_upload
);
467 ioption("magic-treshold",magic_treshold
);
468 option("filter-type", cnf
);
469 /* not yet implemented:
470 ioption("magic-fixed-packets",fixed_packets);
471 ioption("magic-relative-packets",packet_limit);
476 perror(config_filename
);
477 puts("Warning - using built-in defaults instead ...");
482 /* leaf discipline for keywords */
483 for_each(keyword
,keywords
)
485 if(!strcmpi(keyword
->leaf_discipline
, ""))
487 keyword
->leaf_discipline
= qos_leaf
;
491 if(strcmpi(cnf
, "mark"))
495 mark_iptables
= "CLASSIFY --set-class 1:";
501 mark_iptables
= "MARK --set-mark ";
504 /* are supplied values meaningful ?*/
507 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
508 reject_config_and_exit(config_filename
);
512 /* ===================== traffic analyser - uses iptables ================ */
514 void get_traffic_statistics(void)
519 textfile(Pipe
,str
) *line
,*lines
=NULL
;
523 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
535 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
536 unsigned long long traffic
=0;
537 unsigned long pkts
=0;
538 char *ipaddr
=NULL
,*ptr
;
540 /* debug puts(line->str); */
541 valid_columns(ptr
,line
->str
,' ',col
)
542 if(valid
) switch(col
)
544 case 1: if(eq(ptr
,"Chain"))
548 else if(eq(ptr
,"pkts"))
554 sscanf(ptr
,"%lu",&pkts
);
557 case 2: if(setchainname
)
559 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
565 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
570 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
577 sscanf(ptr
,"%Lu",&traffic
);
582 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
586 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
588 case 8: if(downloadflag
)
590 if(strstr(proxy_ip
,ptr
))
600 case 9: if(downloadflag
)ipaddr
=ptr
;break;
603 if(accept
&& traffic
>0 && ipaddr
)
609 else if(!downloadflag
)
613 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
615 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
620 if(eq(ip
->addr
,"0.0.0.0/0"))
622 ip
->name
="(unregistered)";
624 ip
->max
=ip
->desired
=free_max
;
636 ip
->traffic
+=traffic
;
638 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
647 ip
->traffic
+=traffic
;
651 if(traffic
>ip
->traffic
)
662 /* ========== This function executes, logs OR ALSO prints command ========== */
664 void safe_run(char *cmd
)
668 printf("\n=>%s\n",cmd
);
676 fprintf(log_file
,"%s\n",cmd
);
680 void save_line(char *line
)
682 fprintf(iptables_file
,"%s\n",line
);
685 void run_restore(void)
688 string(restor
,STRLEN
);
690 /*-----------------------------------------------------------------*/
691 printf("Running %s <%s ...\n", iptablesrestore
, iptablesfile
);
692 /*-----------------------------------------------------------------*/
695 fclose(iptables_file
);
705 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
711 /* == This function strips extra characters after IP address and stores it = */
713 void parse_ip(char *str
)
715 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
721 while(*ptr
&& *ptr
!='}')
729 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
737 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
742 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
748 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
757 ip
->lmsid
=atoi(lmsid
);
762 char *parse_datafile_line(char *str
)
764 char *ptr
=strchr(str
,' ');
789 void parse_ip_log(int argc
, char **argv
)
791 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
792 long traffic
=0l, traffic_month
, total
=0, guaranted
;
793 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
794 char mstr
[4], ystr
[5];
797 string(filename
,STRLEN
);
799 if(argv
[1][1]=='l') /* -l */
803 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
809 if(eq(month
,"Year")) any_month
=1;
815 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
816 struct tm
*timep
= localtime(&t
);
818 if(argv
[1][1]=='m') /* -m yestarday - month */
820 strftime(mstr
, 4, "%b", timep
);
822 strftime(ystr
, 5, "%Y", timep
);
825 else /* -y yesterday - year */
829 strftime(ystr
, 5, "%Y", timep
);
833 printf("Analysing traffic for %s %s ...\n",month
,year
);
835 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
836 sprintf(str
,"%s %s/",ls
,log_dir
);
840 if(strstr(str
,".log"))
842 ptr
=strrchr(str
,'\n');
844 sprintf(filename
,"%s/%s",log_dir
,str
);
845 printf("Parsing %s ...",filename
);
853 valid_columns(ptr
,_
,'\t',col
) switch(col
)
855 case 2: name
= ptr
;break;
856 case 3: traffic
= atol(ptr
);break;
857 /* column number - was 7, now 11...*/
862 case 11: if(isalpha(*ptr
)) /* character, not numeric string = date, just one*/
864 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
866 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
867 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
872 if(col
== 7) guaranted
= atol(ptr
);
873 if(col
== 10) lmsid
= atoi(ptr
);
879 traffic_month
+= traffic
;
889 iplog
->guaranted
= guaranted
;
890 iplog
->traffic
= traffic_month
;
891 iplog
->lmsid
= lmsid
;
892 insert(iplog
,iplogs
,desc_order_by
,traffic
);
893 printf(" %ld MB\n",iplog
->traffic
);
897 puts(" no records.");
901 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
902 printf("Writing %s ... ",str
);
906 fprintf(f
, "<table class=\"decorated last\"><thead>\n\
907 <tr><th colspan=\"2\">%s %s</th>\n\
908 <th style=\"text-align: right\">lms</th>\n\
909 <th colspan=\"2\">Data transfers</th>\n\
910 <th style=\"text-align: right\">Min.speed</th>\n\
911 </tr></thead><tbody>\n ",
915 for_each(iplog
, iplogs
)
919 fprintf(f
, "%s<td style=\"text-align: right\">%d</td>\n\
920 <td style=\"text-align: left\"><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</td>\n\
921 <td style=\"text-align: right\">",
922 tr_odd_even(), i
++, log_url
, iplog
->name
, iplog
->name
);
925 /*base URL will be configurable soon ... */
926 fprintf(f
, "<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
928 else if(iplog
->lmsid
== 0)
932 fprintf(f
, "<td style=\"text-align: right\">%ld MB</td>\n\
933 <td style=\"text-align: right\"><strong>%ld GB</strong></td>\n\
934 <td style=\"text-align: right\">%ld kb/s</th></tr>\n",
935 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
936 total
+=iplog
->traffic
>>10;
941 fprintf(f
,"</tbody><thead><tr>\
942 <th colspan=\"3\" style=\"text-align: left\">Total:</th>\
943 <th colspan=\"2\" style=\"text-align: right\"><strong>%ld GB</strong></th>\
944 <th style=\"text-align: right\"><strong>%Ld kb/s</strong></th></tr>\n", total
, line
);
945 fputs("</thead></table>\n", f
);
950 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\">\n\
951 <caption>Enterprise Resource Planning (ERP)</caption>\n\
953 <th>Analytic category</th>\n\
954 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
955 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
956 </tr></thead><tbody>\n",f
);
958 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
960 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
961 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
));
964 if_exists(iplog
,iplogs
,iplog
->i
==10)
966 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
967 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
968 <td style=\"text-align: right\">%d %%</td>\n\
969 <td style=\"text-align: right\">%ld G</td>\n\
970 <td style=\"text-align: right\">%d %%</td></tr>\n",
971 (100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
974 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
976 fprintf(f
,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
977 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
978 <td style=\"text-align: right\">%d %%</td>\n\
979 <td style=\"text-align: right\">%ld G</td>\n\
980 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
981 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
984 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
986 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());
987 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
988 <td style=\"text-align: right\">%d %%</td>\n\
989 <td style=\"text-align: right\">%ld G</td>\n\
990 <td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",
991 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
994 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
996 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());
997 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
998 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
999 <td style=\"text-align: right\">%ld G</td>\n\
1000 <td style=\"text-align: right\">%d %%</td></tr>\n",
1001 iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
1004 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
1006 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1007 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
));
1010 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
1012 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());
1013 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1014 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1015 <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
));
1018 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
1020 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());
1021 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
));
1024 fprintf(f
,"</tbody><thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
1025 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
1026 <th style=\"text-align: right\">100 %%</th>\n\
1027 <th style=\"text-align: right\">%ld G</th>\n\
1028 <th style=\"text-align: right\">100 %%</th></tr>\n",i
-1,total
);
1029 fputs("</thead></table>\n", f
);
1032 fprintf(f
, stats_html_signature
, version
);
1042 void append_log(struct IP
*self
) /*using global variables*/
1047 date(d
); /* this is typical cll1.h macro - prints current date */
1049 sprintf(str
,"%s/%s.log", log_dir
, self
->name
);
1053 fprintf(f
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1054 time(NULL
), self
->name
, self
->traffic
, self
->direct
, self
->proxy
,
1055 self
->upload
, self
->min
, self
->max
, self
->desired
, self
->lmsid
, d
); /* d = date*/
1065 /*-----------------------------------------------------------------*/
1066 /* Are you looking for int main(int argc, char **argv) ? :-)) */
1067 /*-----------------------------------------------------------------*/
1073 char *str
, *ptr
, *d
;
1075 int class_count
=0,ip_count
=0;
1077 int just_flush
=FALSE
;
1079 int just_preview
=FALSE
; /* preview - generate just stats */
1080 int just_logs
=FALSE
; /* just parse logs */
1084 char *chain_forward
, *chain_postrouting
;
1085 char *althosts
=NULL
;
1088 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
1089 Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\
1090 iptables-restore & burst tunning & classify modification by Ludva\n\
1091 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
1093 /*----- Boring... we have to check command line options first: ----*/
1097 argument("-c") { nextargument(config
); }
1098 argument("-h") { nextargument(althosts
);}
1099 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
1100 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
1101 argument("-9") { run
=TRUE
; just_flush
=9; }
1102 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
1103 argument("-r") { run
=TRUE
; }
1104 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
1105 argument("-l") { just_logs
=TRUE
; }
1106 argument("-m") { just_logs
=TRUE
; }
1107 argument("-y") { just_logs
=TRUE
; }
1108 argument("-?") { help(); exit(0); }
1109 argument("--help") { help(); exit(0); }
1110 argument("-v") { exit(0); }
1111 argument("--version") { exit(0); }
1116 puts("*** THIS IS JUST DRY RUN ! ***\n");
1119 date(d
); /* this is typical cll1.h macro - prints current date */
1121 /*-----------------------------------------------------------------*/
1122 printf("Parsing configuration file %s ...\n", config
);
1123 /*-----------------------------------------------------------------*/
1128 parse_ip_log(argc
,argv
);
1144 /*-----------------------------------------------------------------*/
1145 puts("Parsing iptables verbose output ...");
1146 /*-----------------------------------------------------------------*/
1147 get_traffic_statistics();
1150 /*-----------------------------------------------------------------*/
1151 printf("Parsing class defintion file %s ...\n", hosts
);
1152 /*-----------------------------------------------------------------*/
1153 int groupidx
= FIRSTGROUPID
;
1158 if(*str
<'0' || *str
>'9')
1160 /* any line starting with non-number is comment ...*/
1164 //Does this IP share QoS class with some other ?
1165 substring
=strstr(str
,"sharing-");
1168 substring
+=8; //"sharing-"
1171 ip
->sharing
=substring
;
1172 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1173 while(*substring
&& *substring
!='\n')
1181 //Do we have to create new QoS class for this IP ?
1183 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1187 ip
->keyword
=keyword
;
1188 keyword
->ip_count
++;
1189 ip
->prio
=keyword
->default_prio
;
1190 substring
+=strlen(keyword
->key
)+1;
1192 while(*ptr
&& *ptr
!='-')
1199 ip
->max
= ip
->desired
=atoi(ptr
+1);
1201 ip
->min
= atoi(substring
);
1204 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
1208 if(ip
->max
<= ip
->min
)
1211 ip
->max
= ip
->min
+ip
->keyword
->reserve_min
;
1215 ip
->max
-= ip
->keyword
->reserve_max
;
1221 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1223 if_exists(group
,groups
,group
->min
==ip
->min
)
1226 group
->desired
+= ip
->min
;
1227 ip
->group
= group
->id
;
1231 create(group
,Group
);
1232 group
->min
= ip
->min
;
1233 group
->id
= groupidx
++;
1234 ip
->group
= group
->id
;
1236 if(group
->min
<8) group
->min
=8;
1237 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1238 /* it is because class IDs are derived from min. bandwidth. - xCh */
1239 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1242 group
->desired
=ip
->min
;
1243 insert(group
,groups
,desc_order_by
,min
);
1255 /*-----------------------------------------------------------------*/
1256 /* cll1.h - let's allocate brand new character buffer... */
1257 /*-----------------------------------------------------------------*/
1260 /*-----------------------------------------------------------------*/
1261 puts("Resolving shared connections ...");
1262 /*-----------------------------------------------------------------*/
1263 for_each(ip
,ips
) if(ip
->sharing
)
1265 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1267 sharedip
->traffic
+=ip
->traffic
;
1269 ip
->mark
=sharedip
->mark
;
1270 ip
->lmsid
=sharedip
->lmsid
;
1275 printf("Unresolved shared connection: %s %s sharing-%s\n",
1276 ip
->addr
, ip
->name
, ip
->sharing
);
1280 if(enable_credit
&& just_flush
<9)
1282 /*-----------------------------------------------------------------*/
1283 printf("Parsing credit file %s ...\n", credit
);
1284 /*-----------------------------------------------------------------*/
1287 ptr
=parse_datafile_line(_
);
1290 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1292 sscanf(ptr
,"%Lu",&(ip
->credit
));
1301 /*-----------------------------------------------------------------*/
1302 puts("Initializing iptables and tc classes ...");
1303 /*-----------------------------------------------------------------*/
1305 iptables_file
=fopen(iptablesfile
,"w");
1306 if(iptables_file
== NULL
)
1308 puts("Cannot open iptablesfile!");
1312 log_file
=fopen(cmdlog
,"w");
1313 if(log_file
== NULL
)
1315 puts("Cannot open logfile!");
1319 save_line(iptablespreamble
);
1322 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1325 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1328 iptables_file
=fopen(iptablesfile
,"w");
1329 save_line(iptablespreamble
);
1331 if(qos_free_zone
&& *qos_free_zone
!='0')
1335 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1340 save_line(":post_noproxy - [0:0]");
1341 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1343 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1345 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1348 chain
="post_noproxy";
1352 chain
="POSTROUTING";
1355 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1359 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1361 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1363 /*-----------------------------------------------------------------*/
1364 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1365 /*-----------------------------------------------------------------*/
1367 save_line(":post_common - [0:0]");
1368 save_line(":forw_common - [0:0]");
1370 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1372 buf
=hash_id(ip
->addr
,bitmask
);
1373 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1382 idx
->bitmask
=bitmask
;
1390 /* brutal perfomance optimalization */
1391 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1393 bitmask
-=idxtable_bitmask2
;
1396 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1398 buf
=hash_id(idx
->addr
,bitmask
);
1399 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1401 metaindex
->children
++;
1405 create(metaindex
,Index
);
1406 metaindex
->addr
=idx
->addr
;
1408 metaindex
->bitmask
=bitmask
;
1409 metaindex
->parent
=NULL
;
1410 metaindex
->children
=0;
1412 push(metaindex
,idxs
);
1414 idx
->parent
=metaindex
;
1418 /* this should slightly optimize throughout ... */
1419 sort(idx
,idxs
,desc_order_by
,children
);
1420 sort(idx
,idxs
,order_by
,bitmask
);
1425 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1426 printf("%d: %s/%d\n",
1427 ++i
, subnet
, idx
->bitmask
);
1429 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1432 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1437 string(buf
,strlen(idx
->parent
->id
)+6);
1438 sprintf(buf
,"post_%s",idx
->parent
->id
);
1445 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1448 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1453 string(buf
,strlen(idx
->parent
->id
)+6);
1454 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1461 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1464 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1467 printf("Total indexed iptables chains created: %d\n", i
);
1469 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1472 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1480 fclose(iptables_file
);
1485 puts("Just flushed iptables and tc classes - now exiting ...");
1491 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1493 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1494 sleep(qos_free_delay
);
1497 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1501 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1502 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1505 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1506 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1509 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1512 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1513 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1516 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1517 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1521 /*-----------------------------------------------------------------*/
1522 puts("Locating heavy downloaders and generating root classes ...");
1523 /*-----------------------------------------------------------------*/
1524 sort(ip
,ips
,desc_order_by
,traffic
);
1526 /*-----------------------------------------------------------------*/
1527 /* sub-scope - local variables */
1529 long long int rate
= line
;
1530 long long int max
= line
;
1531 int group_count
= 0;
1532 FILE *credit_file
= NULL
;
1534 if(!just_preview
&& !dry_run
&& enable_credit
)
1536 credit_file
= fopen(credit
,"w");
1539 for_each(group
,groups
)
1544 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",
1545 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1549 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",
1550 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1554 if(group_count
++ < max_nesting
)
1559 rate
-= digital_divide
*group
->min
;
1560 if(rate
< group
->min
)
1565 /*shaping of aggresive downloaders, with credit file support */
1568 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1570 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1572 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1573 && ( ip
->traffic
>ip
->credit
1574 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1576 if(group_rate
<ip
->max
)
1580 group_rate
+=magic_treshold
;
1581 ip
->prio
=lowest_priority
;
1582 if(ip
->prio
<highest_priority
+2)
1584 ip
->prio
=highest_priority
+2;
1589 if( ip
->keyword
->data_prio
1591 && ( ip
->traffic
>ip
->credit
1592 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1594 ip
->prio
=priority_sequence
--;
1595 if(ip
->prio
<highest_priority
+1)
1597 ip
->prio
=highest_priority
+1;
1603 unsigned long long lcredit
=0;
1605 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1607 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1609 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1617 fclose(credit_file
);
1623 f
=fopen(preview
,"w");
1626 else if(!dry_run
&& !just_flush
)
1628 /*-----------------------------------------------------------------*/
1629 printf("Writing daily statistics %s ... ", json
);
1630 /*-----------------------------------------------------------------*/
1642 if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1644 fprintf(f
, " %d:{ \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu }",
1645 ip
->lmsid
, ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1666 /*-----------------------------------------------------------------*/
1667 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1668 /*-----------------------------------------------------------------*/
1670 if(use_jquery_popups
)
1672 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1674 fputs("<table class=\"decorated last\">\n\
1675 <caption>Bandwidth classes</caption>\n\
1677 <th style=\"text-align: right\">#</th>\n\
1678 <th style=\"text-align: right\">group</th>\n\
1679 <th style=\"text-align: right\">IPs</th>\n\
1680 <th style=\"text-align: right\">requested</th>\n",f
);
1681 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1682 fputs("</tr></thead><tbody>\n",f
);
1685 for_each(group
, groups
)
1688 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group
->min
,group
->count
,group
->desired
);
1690 fprintf(f
, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1691 tr_odd_even(), count
, group
->min
);
1692 fprintf(f
, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d kb/s</td>",
1693 group
->count
, group
->desired
);
1695 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1697 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d MB</span></td>",
1698 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1700 i
+= group
->desired
;
1701 total
+= group
->count
;
1705 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1708 fprintf(f
,"</tr></tbody>\n\
1710 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line
);
1711 fprintf(f
,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total
,i
);
1713 for_each(keyword
, keywords
) if(keyword
->ip_count
)
1715 fprintf(f
,"<th style=\"text-align: right\">%d IPs</th>",keyword
->ip_count
);
1717 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1718 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1720 fputs("</thead></table>\n",f
);
1722 else if(!dry_run
&& !just_flush
)
1730 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1731 int active_classes
=0;
1733 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1734 int limit_count
=0, prio_count
=0;
1742 fprintf(f
,"<p><table class=\"decorated last\">\n<caption>%s",title
);
1743 fprintf(f
," (%s)</caption>\n", d
);
1744 fputs("<thead><tr>\n<th colspan=\"3\"> </th>\n",f
);
1745 fputs("<th style=\"text-align: right\">credit</th>\n\
1746 <th style=\"text-align: right\">FUP</th>\n\
1747 <th style=\"text-align: right\">total</th>\n\
1748 <th style=\"text-align: right\">down</th>\n",f
);
1751 fputs("<th style=\"text-align: right\">proxy</th>\n",f
);
1753 fputs("<th style=\"text-align: right\">up</th>\n\
1754 <th style=\"text-align: right\">min</th>\n\
1755 <th style=\"text-align: right\">max</th>\n\
1756 <th style=\"text-align: right\">limit</th>\n\
1759 <th style=\"text-align: right\">#</th>\n\
1760 <th>hostname [+sharing]</th>\n\
1761 <th style=\"text-align: right\">LMS</th>\n\
1762 <th style=\"text-align: right\">MB</th>\n\
1763 <th style=\"text-align: right\">MB</th>\n\
1764 <th style=\"text-align: right\">MB</th>\n\
1765 <th style=\"text-align: right\">MB</th>\n\
1766 <th style=\"text-align: right\">MB</th>\n\
1767 <th style=\"text-align: right\">kb/s</th>\n\
1768 <th style=\"text-align: right\">kb/s</th>\n\
1769 <th style=\"text-align: right\">kb/s</th>\n\
1771 </tr></thead><tbody>\n",f
);
1774 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1776 char *f1
="", *f2
="";
1779 if(ip
->max
< ip
->desired
)
1781 f1
="<span style=\"color:red\">";
1785 else if(ip
->prio
> highest_priority
+1)
1787 f1
="<span style=\"color:brown\">";
1793 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1795 /* hostnames -------------------------------------- */
1796 fprintf(f
,"%s<td style=\"text-align: right\"><a name=\"%s\"></a>%d</td><td><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n",
1797 tr_odd_even(), ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1799 if(use_jquery_popups
)
1801 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1803 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1805 fprintf(f
,"<br /><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1808 fputs("</span>\n",f
);
1811 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>",
1812 i
, i
, i
, popup_button
);
1816 /* ----------------------------------------------- */
1820 fputs("<td style=\"text-align: right\">",f
);
1823 fprintf(f
,"<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1825 else if(ip
->lmsid
== 0)
1831 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->credit
);
1832 fprintf(f
,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1833 ip
->keyword
->html_color
,
1834 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1835 fprintf(f
,"<td style=\"text-align: right\">%s%Lu%s", f1
, ip
->traffic
, f2
);
1837 /* download --------------------------------------- */
1838 fprintf(f
,"</td><td style=\"text-align: right\">%Lu", ip
->direct
);
1839 if(use_jquery_popups
)
1841 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1842 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1844 fprintf(f
,"<br />%Lu", sharedip
->direct
);
1846 fputs("</span>\n",f
);
1849 /* ----------------------------------------------- */
1853 fprintf(f
,"<td style=\"text-align: right\">%Lu</td>\n", ip
->proxy
);
1855 /* upload ---------------------------------------- */
1856 fprintf(f
,"<td style=\"text-align: right\">%Lu", ip
->upload
);
1857 if(use_jquery_popups
)
1859 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1860 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1862 fprintf(f
,"<br />%Lu", sharedip
->upload
);
1864 fputs("</span>\n",f
);
1867 /* ----------------------------------------------- */
1869 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1870 <td style=\"text-align: right\">%d</td>\n\
1871 <td style=\"text-align: right\">%s%d%s</td>\n\
1872 <td>%s%d%s</td></tr>\n",
1873 ip
->min
, ip
->desired
,
1877 total_traffic
+=ip
->traffic
;
1878 total_direct
+=ip
->direct
;
1879 total_proxy
+=ip
->proxy
;
1880 total_upload
+=ip
->upload
;
1884 tmp_sum
+=ip
->traffic
;
1887 sum
->i
=active_classes
;
1888 insert(sum
,sums
,order_by
,i
);
1894 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1896 append_log(sharedip
);
1900 fprintf(f
,"</tbody><thead><tr>\n\
1901 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan
-7, i
);
1902 fprintf(f
,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic
, total_direct
);
1905 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy
);
1907 fprintf(f
,"<th style=\"text-align: right\">%Lu</th>", total_upload
);
1908 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
);
1911 if(active_classes
>10)
1913 int top20_count
=0,top20_perc1
=0;
1914 long long top20_perc2
=0;
1915 unsigned long long top20_sum
=0l;
1917 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f
);
1918 fputs("<thead><tr>\n\
1919 <th>Analytic category</th>\n\
1920 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1921 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1922 </tr></thead><tbody>\n",f
);
1924 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1926 fprintf(f
,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1927 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
);
1930 if_exists(sum
,sums
,sum
->i
==10)
1932 fprintf(f
,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1933 fprintf(f
,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1934 <td style=\"text-align: right\">%d %%</td>\n\
1935 <td style=\"text-align: right\">%Lu MB</td>\n\
1936 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1937 (100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1940 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1942 fprintf(f
,"%s<td>Top 50%% 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
->l
>=4*total_traffic
/5)
1952 fprintf(f
,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1953 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1954 <td style=\"text-align: right\">%d %%</td>\n\
1955 <td style=\"text-align: right\">%Lu MB</td>\n\
1956 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1957 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1960 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1962 fprintf(f
,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1964 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1966 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1967 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1968 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1969 <td style=\"text-align: right\">%Lu MB</td>\n\
1970 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1971 top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
1974 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1976 fprintf(f
,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1977 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1978 <td style=\"text-align: right\">%d %%</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
>=(active_classes
+1)/2)
1986 fprintf(f
,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1987 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1988 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1989 <td style=\"text-align: right\">%Lu MB</td>\n\
1990 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1991 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1994 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1996 fprintf(f
,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1997 fprintf(f
,"<td style=\"text-align: right\">%d</td>\n\
1998 <td style=\"text-align: right\">%d %%</td>\n\
1999 <td style=\"text-align: right\">%Lu MB</td>\n\
2000 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
2001 sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
2004 fprintf(f
,"<thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url
);
2005 fprintf(f
,"<th style=\"text-align: right\">%d</th>\n\
2006 <th style=\"text-align: right\">100 %%</th>\n\
2007 <th style=\"text-align: right\">%Lu M</th>\n\
2008 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
2009 fputs("</thead></table>\n", f
);
2011 /* write basic ERP data to log directory */
2015 sprintf(str
,"%s/ERP.log",log_dir
);
2016 iplog
=fopen(str
,"a");
2019 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",
2020 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
2021 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
2031 fprintf(f
, stats_html_signature
, version
);
2037 puts("Statistics preview generated (-p switch) - now exiting ...");
2043 printf("%-22s %-15s mark\n","name","ip");
2046 printf("Writing %s ... ", classmap
);
2047 f
= fopen(classmap
, "w");
2053 /*-----------------------------------------------------------------*/
2054 puts("Generating iptables and tc classes ... ");
2055 /*-----------------------------------------------------------------*/
2057 for_each(ip
, ips
) if(ip
->mark
> 0)
2062 duplicate(ip
->addr
,buf
);
2063 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
2065 string(chain_forward
,6+strlen(buf
));
2066 strcpy(chain_forward
,"forw_");
2067 strcat(chain_forward
,buf
);
2069 string(chain_postrouting
,6+strlen(buf
));
2070 strcpy(chain_postrouting
,"post_");
2071 strcat(chain_postrouting
,buf
);
2077 chain_forward
="FORWARD";
2078 chain_postrouting
="POSTROUTING";
2082 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
2085 /* -------------------------------------------------------- mark download */
2087 sprintf(str
, "-A %s -d %s/32 -o %s -j %s%d",
2088 chain_postrouting
, ip
->addr
, lan
, mark_iptables
, ip
->mark
);
2089 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
2090 /* -m limit --limit 1/s */
2095 sprintf(str
, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
2096 chain_postrouting
, proxy_ip
, proxy_port
, ip
->addr
, lan
, mark_iptables
, ip
->mark
);
2097 /*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);*/
2101 sprintf(str
, "-A %s -d %s/32 -o %s -j ACCEPT",
2102 chain_postrouting
, ip
->addr
, lan
);
2105 /* -------------------------------------------------------- mark upload */
2106 sprintf(str
, "-A %s -s %s/32 -o %s -j %s%d",
2107 chain_forward
, ip
->addr
, wan
, mark_iptables
, ip
->mark
);
2108 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
2111 sprintf(str
, "-A %s -s %s/32 -o %s -j ACCEPT",
2112 chain_forward
, ip
->addr
, wan
);
2117 /* -------------------------------------------------------- download class */
2119 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
2122 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2123 tc
, lan
, ip
->group
, ip
->mark
,ip
->min
,ip
->max
, 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",
2129 tc
, lan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
2133 if(filter_type
== 1)
2135 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2136 tc
, lan
, ip
->mark
, ip
->mark
);
2140 /* -------------------------------------------------------- upload class */
2142 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2143 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
2146 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
2147 tc
, wan
, ip
->group
, ip
->mark
,
2148 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
2149 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
2152 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
2154 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
2155 tc
, wan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
2159 if(filter_type
== 1)
2161 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
2162 tc
, wan
, ip
->mark
, ip
->mark
);
2168 fprintf(f
, "%s %d", ip
->addr
, ip
->mark
);
2174 printf("(sharing %s)\n", ip
->sharing
);
2187 chain_forward
= "forw_common";
2188 chain_postrouting
= "post_common";
2192 chain_forward
= "FORWARD";
2193 chain_postrouting
= "POSTROUTING";
2195 /* -------------------------------- classify or reject free download */
2197 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
2200 final_chain
= "ACCEPT";
2206 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
2207 chain_postrouting
,proxy_ip
,proxy_port
,lan
,mark_iptables
,3);
2210 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
2211 chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
2216 sprintf(str
,"-A %s -o %s -j %s%d", chain_postrouting
, lan
, mark_iptables
, 3);
2219 sprintf(str
,"-A %s -o %s -j %s", chain_postrouting
, lan
, final_chain
);
2221 /* ------------------------------- classify or reject free upload */
2224 sprintf(str
,"-A %s -o %s -j %s%d", chain_forward
, wan
, mark_iptables
, 3);
2227 sprintf(str
,"-A %s -o %s -j %s", chain_forward
, wan
, final_chain
);
2231 if(free_min
) /* allocate free bandwith if it is not zero... */
2233 /*-----------------------------------------------------------------*/
2234 puts("Generating free bandwith classes ...");
2235 /*-----------------------------------------------------------------*/
2236 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2237 tc
, lan
, parent
, free_min
, free_max
,burst
, lowest_priority
);
2239 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2240 tc
, wan
, parent
, free_min
, free_max
, burst
, lowest_priority
);
2243 if(strcmpi(qos_leaf
, "none"))
2245 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, lan
, qos_leaf
);
2248 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, wan
, qos_leaf
);
2251 /* tc handle 1 fw flowid */
2252 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, lan
);
2255 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, wan
);
2258 printf("Total IP count: %d\n", i
);
2265 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2266 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.372404 seconds and 4 git commands to generate.