7e42169cfdd74eac71c491c6478d1be5165bb3fc
1 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2 /* Prometheus QoS - you can "steal fire" from your ISP */
3 /* "fair-per-IP" quality of service (QoS) utility */
4 /* requires Linux 2.4.x or 2.6.x with HTB support */
5 /* Copyright(C) 2005-2008 Michael Polak (xChaos) */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
10 /* Modified by: xChaos, 20111130
13 Prometheus QoS is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2.1 of
16 the License, or (at your option) any later version.
18 Prometheus QoS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with Prometheus Qos; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 GNU General Public License is located in file COPYING */
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
34 #include "cll1-0.6.2.h"
36 const char *version
= "0.8.3-b";
38 /* Version numbers: 0.8.3 is development releases ("beta"), 0.8.4 will be "stable" */
39 /* Debian(RPM) package versions/patchlevels: 0.7.9-2, 0.8.0-1, 0.8.0-2, etc. */
40 /* C source code development versions ("beta"): 0.7.9-a, 0.8.1-b, etc. */
41 /* C source code release versions: 0.8.0, 0.8.2, 0.8.4, etc. */
43 const char *stats_html_signature
= "<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005-2011 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n";
45 /* ======= All path names are defined here (for RPM patch) ======= */
47 char *tc
= "/sbin/tc"; /* requires tc with HTB support */
48 char *iptables
= "/sbin/iptables"; /* requires iptables utility */
49 char *iptablessave
= "/sbin/iptables-save"; /* not yet required */
50 char *iptablesrestore
= "/sbin/iptables-restore"; /* requires iptables-restore */
51 const char *ls
= "/bin/ls"; /* this is not user configurable :-) */
53 char *config
= "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts
= "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
56 char *iptablesfile
= "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
57 char *credit
= "/var/lib/misc/prometheus.credit"; /* credit log file */
58 char *html
= "/var/www/traffic.html"; /* hall of fame filename */
59 char *preview
= "/var/www/preview.html"; /* hall of fame preview */
60 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
61 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
62 char *log_url
= "logs/"; /* log directory relative URI prefix (partial URL) */
63 char *html_log_dir
= "/var/www/logs/html/";
65 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
66 char *lms_url
= "/lms/?m=customerinfo&id=";
67 int use_jquery_popups
= 1;
69 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
73 puts("Command line switches:\n\
75 -?, --help this help screen\n\
76 -v, --version show Version number of this utility and exit\n\
77 -c filename force alternative /etc/prometheus.Conf filename\n\
78 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
79 -f just Flush iptables and tc classes and exit (stop shaping)\n\
80 -9 emergency iptables flush (do not read data transfer statistics)\n\
81 -p just generate Preview of data transfer statistics and exit\n\
82 -d Dry run (preview tc and iptables commands on stdout)\n\
83 -r Run (reset all statistics and start shaping)\n\
84 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
85 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
86 -m generate HTML summary of traffic logs for yesterday's Month\n\
87 -y generate HTML summary of traffic logs for yesterday's Year\n");
88 /* not yet implemented:
89 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
93 /* === Configuraration file values defaults - stored in global variables ==== */
95 int filter_type
= 1; /*1 mark, 2 classify*/
97 char *mark_iptables
= "MARK --set-mark ";
98 int dry_run
= 0; /* preview - use puts() instead of system() */
99 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]";
100 FILE *iptables_file
= NULL
;
101 int enable_credit
= 1; /* enable credit file */
102 int use_credit
= 0; /* use credit file (if enabled)*/
103 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
104 int hall_of_fame
= 1; /* enable hall of fame */
105 char *lan
= "eth0"; /* LAN interface */
106 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
107 char *wan
= "eth1"; /* WAN/ISP interface */
108 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
109 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
110 char *qos_free_zone
= NULL
; /* QoS free zone */
111 int qos_proxy
= 1; /* include proxy port to QoS */
112 int found_lmsid
= 0; /* show links to users in LMS information system */
113 int include_upload
= 1; /* upload+download=total traffic */
114 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
115 int proxy_port
= 3128; /* proxy port number */
116 long long int line
= 1024; /* WAN/ISP download in kbps */
117 long long int up
= 1024; /* WAN/ISP upload in kbps */
118 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
119 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
120 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
121 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
122 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
123 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
124 int burst
= 8; /* HTB burst (in kbits) */
126 int burst_group
= 32;
127 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
128 int keywordcount
= 0;
129 /* not yet implemented:
130 int fixed_packets = 0; maximum number of pps per IP address (not class!)
131 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
133 FILE *log_file
= NULL
;
134 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
136 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
137 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
138 const int idxtable_treshold1
= 24; /* this is no longer configurable */
139 const int idxtable_treshold2
= 12; /* this is no longer configurable */
140 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
141 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
143 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
158 unsigned long long direct
;
159 unsigned long long proxy
;
160 unsigned long long upload
;
161 unsigned long long traffic
;
162 unsigned long long credit
;
163 unsigned long pktsup
;
164 unsigned long pktsdown
;
165 struct Keyword
*keyword
;
167 } *ips
=NULL
, *ip
, *sharedip
;
176 } *groups
=NULL
, *group
;
182 struct Index
*parent
;
186 } *idxs
=NULL
, *idx
, *metaindex
;
192 int asymetry_ratio
; /* ratio for ADSL-like upload */
193 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
194 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
195 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
196 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
197 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
198 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
199 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
200 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
201 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
202 int default_prio
; /* default HTB priority for this keyword */
205 char *leaf_discipline
;
208 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
210 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
218 ip
->prio
= highest_priority
+1;
232 ip
->keyword
= keywords
;
236 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
238 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
240 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
242 char *ip
,*outip
,*outptr
,*fmt
;
245 /* debug printf("(%s,%d) -> ",ip,bitmask); */
247 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
249 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
253 /* should never exit here */
261 if(dot
<(bitmask
/8-1))
263 if(format_as_chainname
)
276 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
277 if(cutdot
)*cutdot
='\0';
278 if(format_as_chainname
)
283 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
287 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
288 sprintf(outptr
,fmt
,n
,bitmask
);
289 if(!format_as_chainname
) while(bitmask
<24)
294 /* debug printf("[%s]\n",outip); */
305 /*should never exit here*/
310 char *hash_id(char *ip
,int bitmask
)
312 return very_ugly_ipv4_code(ip
,bitmask
,1);
315 char *subnet_id(char *ip
,int bitmask
)
317 return very_ugly_ipv4_code(ip
,bitmask
,0);
320 /* ================= Let's parse configuration file here =================== */
322 void reject_config_and_exit(char *filename
)
324 printf("Configuration file %s rejected - abnormal exit.",filename
);
328 void get_config(char *config_filename
)
332 printf("Configured keywords: ");
333 parse(config_filename
)
335 option("keyword",kwd
);
340 create(keyword
,Keyword
);
342 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
343 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
344 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
345 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
346 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
347 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
348 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
349 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
350 keyword
->default_prio
=highest_priority
+1;
351 keyword
->html_color
="000000";
353 keyword
->leaf_discipline
="";
355 push(keyword
,keywords
);
356 if(!defaultkeyword
) defaultkeyword
=keyword
;
363 for_each(keyword
,keywords
)
365 int l
=strlen(keyword
->key
);
367 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
369 char *tmptr
=_
; /* <---- l+1 ----> */
370 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
371 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
372 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
373 ioption("magic-relative-limit",keyword
->data_limit
);
374 ioption("magic-relative-prio",keyword
->data_prio
);
375 loption("magic-fixed-limit",keyword
->fixed_limit
);
376 loption("magic-fixed-prio",keyword
->fixed_prio
);
377 ioption("htb-default-prio",keyword
->default_prio
);
378 ioption("htb-rate-bonus",keyword
->reserve_min
);
379 ioption("htb-ceil-malus",keyword
->reserve_max
);
380 option("leaf-discipline",keyword
->leaf_discipline
);
381 option("html-color",keyword
->html_color
);
384 if(keyword
->data_limit
|| keyword
->fixed_limit
||
385 keyword
->data_prio
|| keyword
->fixed_prio
)
394 option("iptables",iptables
);
395 option("iptables-save",iptablessave
); /* new */
396 option("iptables-restore",iptablesrestore
); /* new */
397 option("iptables-file",iptablesfile
); /* new */
398 option("hosts",hosts
);
399 option("lan-interface",lan
);
400 option("wan-interface",wan
);
401 option("lan-medium",lan_medium
);
402 option("wan-medium",wan_medium
);
403 lloption("wan-download",line
);
404 lloption("wan-upload",up
);
405 ioption("hall-of-fame-enable",hall_of_fame
);
406 option("hall-of-fame-title",title
);
407 option("hall-of-fame-filename",html
);
408 option("hall-of-fame-preview",preview
);
409 option("log-filename",cmdlog
);
410 option("credit-filename",credit
);
411 ioption("credit-enable",enable_credit
);
412 option("log-traffic-directory",log_dir
);
413 option("log-traffic-html-directory",html_log_dir
);
414 option("log-traffic-url-path",log_url
);
415 option("jquery-url",jquery_url
);
416 option("lms-url",lms_url
);
417 ioption("use-jquery-popups",use_jquery_popups
);
418 option("qos-free-zone",qos_free_zone
);
419 ioption("qos-free-delay",qos_free_delay
);
420 ioption("qos-proxy-enable",qos_proxy
);
421 option("qos-proxy-ip",proxy_ip
);
422 option("htb-leaf-discipline",qos_leaf
);
423 ioption("qos-proxy-port",proxy_port
);
424 ioption("free-rate",free_min
);
425 ioption("free-ceil",free_max
);
426 ioption("htb-burst",burst
);
427 ioption("htb-burst-main",burst_main
);
428 ioption("htb-burst-group",burst_group
);
429 ioption("htb-nesting-limit",max_nesting
);
430 ioption("htb-r2q",htb_r2q
);
431 ioption("magic-include-upload",include_upload
);
432 ioption("magic-treshold",magic_treshold
);
433 option("filter-type", cnf
);
435 /* not yet implemented:
436 ioption("magic-fixed-packets",fixed_packets);
437 ioption("magic-relative-packets",packet_limit);
442 perror(config_filename
);
443 puts("Warning - using built-in defaults instead ...");
448 /*leaf discipline for keywords*/
449 for_each(keyword
,keywords
)
451 if (!strcmpi(keyword
->leaf_discipline
, ""))
453 keyword
->leaf_discipline
= qos_leaf
;
457 if (strcmpi(cnf
, "mark"))
461 mark_iptables
= "CLASSIFY --set-class 1:";
467 mark_iptables
= "MARK --set-mark ";
470 /* are supplied values meaningful ?*/
473 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
474 reject_config_and_exit(config_filename
);
478 /* ===================== traffic analyser - uses iptables ================ */
480 void get_traffic_statistics(void)
485 textfile(Pipe
,str
) *line
,*lines
=NULL
;
489 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
501 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
502 unsigned long long traffic
=0;
503 unsigned long pkts
=0;
504 char *ipaddr
=NULL
,*ptr
;
506 /* debug puts(line->str); */
507 valid_columns(ptr
,line
->str
,' ',col
)
508 if(valid
) switch(col
)
510 case 1: if(eq(ptr
,"Chain"))
512 else if(eq(ptr
,"pkts"))
515 sscanf(ptr
,"%lu",&pkts
);
517 case 2: if(setchainname
)
519 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
522 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
525 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
529 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
531 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
533 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
535 case 8: if(downloadflag
)
537 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
542 case 9: if(downloadflag
)ipaddr
=ptr
;break;
545 if(accept
&& traffic
>0 && ipaddr
)
551 else if(!downloadflag
)
555 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
557 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
562 if(eq(ip
->addr
,"0.0.0.0/0"))
564 ip
->name
="(unregistered)";
566 ip
->max
=ip
->desired
=free_max
;
578 ip
->traffic
+=traffic
;
580 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
589 ip
->traffic
+=traffic
;
593 if(traffic
>ip
->traffic
)
605 /* ========== This function executes, logs OR ALSO prints command ========== */
607 void safe_run(char *cmd
)
611 printf("\n=>%s\n",cmd
);
619 fprintf(log_file
,"%s\n",cmd
);
623 void save_line(char *line
)
625 fprintf(iptables_file
,"%s\n",line
);
628 void run_restore(void)
631 string(restor
,STRLEN
);
633 /*-----------------------------------------------------------------*/
634 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
635 /*-----------------------------------------------------------------*/
638 fclose(iptables_file
);
648 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
654 /* == This function strips extra characters after IP address and stores it = */
656 void parse_ip(char *str
)
658 char *ptr
,*ipaddr
=NULL
,*ipname
=NULL
,*lmsid
=NULL
;
664 while(*ptr
&& *ptr
!='}')
672 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
680 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
685 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
691 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
700 ip
->lmsid
=atoi(lmsid
);
705 char *parse_datafile_line(char *str
)
707 char *ptr
=strchr(str
,' ');
732 void parse_ip_log(int argc
, char **argv
)
734 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
735 long traffic
=0l, traffic_month
, total
=0, guaranted
;
736 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0, lmsid
;
737 char mstr
[4], ystr
[5];
740 string(filename
,STRLEN
);
742 if(argv
[1][1]=='l') /* -l */
746 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
752 if(eq(month
,"Year")) any_month
=1;
758 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
759 struct tm
*timep
= localtime(&t
);
761 if(argv
[1][1]=='m') /* -m yestarday - month */
763 strftime(mstr
, 4, "%b", timep
);
765 strftime(ystr
, 5, "%Y", timep
);
768 else /* -y yesterday - year */
772 strftime(ystr
, 5, "%Y", timep
);
776 printf("Analysing traffic for %s %s ...\n",month
,year
);
778 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
779 sprintf(str
,"%s %s/",ls
,log_dir
);
783 if(strstr(str
,".log"))
785 ptr
=strrchr(str
,'\n');
787 sprintf(filename
,"%s/%s",log_dir
,str
);
788 printf("Parsing %s ...",filename
);
796 valid_columns(ptr
,_
,'\t',col
) switch(col
)
798 case 2: name
= ptr
;break;
799 case 3: traffic
= atol(ptr
);break;
800 /* column number - was 7, now 11...*/
805 case 11: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
807 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
809 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
810 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
815 if(col
== 7) guaranted
= atol(ptr
);
816 if(col
== 10) lmsid
= atoi(ptr
);
822 traffic_month
+= traffic
;
832 iplog
->guaranted
= guaranted
;
833 iplog
->traffic
= traffic_month
;
834 iplog
->lmsid
= lmsid
;
835 insert(iplog
,iplogs
,desc_order_by
,traffic
);
836 printf(" %ld MB\n",iplog
->traffic
);
840 puts(" no records.");
844 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
845 printf("Writing %s ...",str
);
849 fprintf(f
, "<table border><tr><th colspan=\"2\">%s %s</th><th align=\"right\">lms</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",
852 for_each(iplog
, iplogs
)
856 fprintf(f
, "<tr><td align=\"right\">%d</td><td align=\"left\"><a href=\"%s%s.log\">%s</td></td><td align=\"right\">",
857 i
++, log_url
, iplog
->name
, iplog
->name
);
860 /*base URL will be configurable soon ... */
861 fprintf(f
, "<a href=\"%s%d\">%04d</a>\n", lms_url
, iplog
->lmsid
, iplog
->lmsid
);
863 else if(iplog
->lmsid
== 0)
867 fprintf(f
, "<td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
868 iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
869 total
+=iplog
->traffic
>>10;
874 fprintf(f
,"<tr><th colspan=\"4\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total
, line
);
875 fputs("</table>\n", f
);
879 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Resource Planning (ERP)</th></tr>\n",f
);
880 fputs("<tr><td>Analytic category</td>\n",f
);
881 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
883 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
885 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
886 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
889 if_exists(iplog
,iplogs
,iplog
->i
==10)
891 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
892 fprintf(f
,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
895 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
897 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
898 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
901 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
903 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
904 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><th align=\"right\">%d %%</th></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
907 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
909 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
910 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
913 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
915 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
916 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
919 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
921 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
922 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
925 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
927 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
928 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%ld G</td><td align=\"right\">%d %%</td></tr>\n",iplog
->i
,(100*iplog
->i
+50)/i
,iplog
->l
,(int)((100*iplog
->l
+50)/total
));
931 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
932 fprintf(f
,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%ld G</th><th align=\"right\">100 %%</th></tr>\n",i
-1,total
);
933 fputs("</table>\n", f
);
936 fprintf(f
, stats_html_signature
, version
);
942 /*-----------------------------------------------------------------*/
943 /* Are you looking for int main(int argc, char **argv) ? :-)) */
944 /*-----------------------------------------------------------------*/
952 int class_count
=0,ip_count
=0;
954 int just_flush
=FALSE
;
956 int just_preview
=FALSE
; /* preview - generate just stats */
957 int just_logs
=FALSE
; /* just parse logs */
961 char *chain_forward
, *chain_postrouting
;
965 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
966 Version %s - Copyright (C)2005-2011 Michael Polak (xChaos)\n\
967 iptables-restore & burst tunning & classify modification by Ludva\n\
968 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
970 /*----- Boring... we have to check command line options first: ----*/
974 argument("-c") { nextargument(config
); }
975 argument("-h") { nextargument(althosts
);}
976 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
977 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
978 argument("-9") { run
=TRUE
; just_flush
=9; }
979 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
980 argument("-r") { run
=TRUE
; }
981 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
982 argument("-l") { just_logs
=TRUE
; }
983 argument("-m") { just_logs
=TRUE
; }
984 argument("-y") { just_logs
=TRUE
; }
985 argument("-?") { help(); exit(0); }
986 argument("--help") { help(); exit(0); }
987 argument("-v") { exit(0); }
988 argument("--version") { exit(0); }
993 puts("*** THIS IS JUST DRY RUN ! ***\n");
996 date(d
); /* this is typical cll1.h macro - prints current date */
998 /*-----------------------------------------------------------------*/
999 printf("Parsing configuration file %s ...\n", config
);
1000 /*-----------------------------------------------------------------*/
1005 parse_ip_log(argc
,argv
);
1021 /*-----------------------------------------------------------------*/
1022 puts("Parsing iptables verbose output ...");
1023 /*-----------------------------------------------------------------*/
1024 get_traffic_statistics();
1027 /*-----------------------------------------------------------------*/
1028 printf("Parsing class defintion file %s ...\n", hosts
);
1029 /*-----------------------------------------------------------------*/
1030 int groupidx
= FIRSTGROUPID
;
1035 if(*str
<'0' || *str
>'9')
1037 /* any line starting with non-number is comment ...*/
1041 //Does this IP share QoS class with some other ?
1042 substring
=strstr(str
,"sharing-");
1045 substring
+=8; //"sharing-"
1048 ip
->sharing
=substring
;
1049 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
1050 while(*substring
&& *substring
!='\n')
1058 //Do we have to create new QoS class for this IP ?
1060 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
1064 ip
->keyword
=keyword
;
1065 keyword
->ip_count
++;
1066 ip
->prio
=keyword
->default_prio
;
1067 substring
+=strlen(keyword
->key
)+1;
1069 while(*ptr
&& *ptr
!='-')
1076 ip
->max
=ip
->desired
=atoi(ptr
+1);
1078 ip
->min
=atoi(substring
);
1081 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
1084 if(ip
->max
<=ip
->min
)
1087 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
1091 ip
->max
-=ip
->keyword
->reserve_max
;
1097 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1099 if_exists(group
,groups
,group
->min
==ip
->min
)
1102 group
->desired
+=ip
->min
;
1103 ip
->group
= group
->id
;
1107 create(group
,Group
);
1109 group
->id
= groupidx
++;
1110 ip
->group
= group
->id
;
1112 if(group
->min
<8) group
->min
=8;
1113 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1114 /* it is because class IDs are derived from min. bandwidth. - xCh */
1115 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1118 group
->desired
=ip
->min
;
1119 insert(group
,groups
,desc_order_by
,min
);
1131 /*-----------------------------------------------------------------*/
1132 /* cll1.h - let's allocate brand new character buffer... */
1133 /*-----------------------------------------------------------------*/
1136 /*-----------------------------------------------------------------*/
1137 puts("Resolving shared connections ...");
1138 /*-----------------------------------------------------------------*/
1139 for_each(ip
,ips
) if(ip
->sharing
)
1141 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
1143 sharedip
->traffic
+=ip
->traffic
;
1145 ip
->mark
=sharedip
->mark
;
1146 ip
->lmsid
=sharedip
->lmsid
;
1151 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1155 if(enable_credit
&& just_flush
<9)
1157 /*-----------------------------------------------------------------*/
1158 printf("Parsing credit file %s ...\n", credit
);
1159 /*-----------------------------------------------------------------*/
1162 ptr
=parse_datafile_line(_
);
1165 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1167 sscanf(ptr
,"%Lu",&(ip
->credit
));
1176 /*-----------------------------------------------------------------*/
1177 puts("Initializing iptables and tc classes ...");
1178 /*-----------------------------------------------------------------*/
1180 iptables_file
=fopen(iptablesfile
,"w");
1181 if (iptables_file
== NULL
)
1183 puts("Cannot open iptablesfile!");
1187 log_file
=fopen(cmdlog
,"w");
1188 if (log_file
== NULL
)
1190 puts("Cannot open logfile!");
1194 save_line(iptablespreamble
);
1197 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1200 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1203 iptables_file
=fopen(iptablesfile
,"w");
1204 save_line(iptablespreamble
);
1206 if(qos_free_zone
&& *qos_free_zone
!='0')
1210 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1215 save_line(":post_noproxy - [0:0]");
1216 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1218 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1220 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1223 chain
="post_noproxy";
1227 chain
="POSTROUTING";
1230 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1234 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1236 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1238 /*-----------------------------------------------------------------*/
1239 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1240 /*-----------------------------------------------------------------*/
1242 save_line(":post_common - [0:0]");
1243 save_line(":forw_common - [0:0]");
1245 for_each(ip
,ips
) if (ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1247 buf
=hash_id(ip
->addr
,bitmask
);
1248 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1257 idx
->bitmask
=bitmask
;
1265 /* brutal perfomance optimalization */
1266 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1268 bitmask
-=idxtable_bitmask2
;
1271 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
1273 buf
=hash_id(idx
->addr
,bitmask
);
1274 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1276 metaindex
->children
++;
1280 create(metaindex
,Index
);
1281 metaindex
->addr
=idx
->addr
;
1283 metaindex
->bitmask
=bitmask
;
1284 metaindex
->parent
=NULL
;
1285 metaindex
->children
=0;
1287 push(metaindex
,idxs
);
1289 idx
->parent
=metaindex
;
1293 /* this should slightly optimize throughout ... */
1294 sort(idx
,idxs
,desc_order_by
,children
);
1295 sort(idx
,idxs
,order_by
,bitmask
);
1300 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1301 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1303 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1306 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1311 string(buf
,strlen(idx
->parent
->id
)+6);
1312 sprintf(buf
,"post_%s",idx
->parent
->id
);
1319 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1322 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1327 string(buf
,strlen(idx
->parent
->id
)+6);
1328 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1335 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1338 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1341 printf("Total indexed iptables chains created: %d\n", i
);
1343 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1346 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1354 fclose(iptables_file
);
1355 if (log_file
) fclose(log_file
);
1356 puts("Just flushed iptables and tc classes - now exiting ...");
1362 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1364 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1365 sleep(qos_free_delay
);
1368 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1372 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1373 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1376 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1377 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1380 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1383 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1384 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1387 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1388 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1392 /*-----------------------------------------------------------------*/
1393 puts("Locating heavy downloaders and generating root classes ...");
1394 /*-----------------------------------------------------------------*/
1395 sort(ip
,ips
,desc_order_by
,traffic
);
1397 /*-----------------------------------------------------------------*/
1398 /* sub-scope - local variables */
1400 long long int rate
= line
;
1401 long long int max
= line
;
1402 int group_count
= 0;
1403 FILE *credit_file
= NULL
;
1405 if(!just_preview
&& !dry_run
&& enable_credit
)
1407 credit_file
= fopen(credit
,"w");
1410 for_each(group
,groups
)
1415 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",
1416 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1420 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",
1421 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1425 if(group_count
++ < max_nesting
)
1430 rate
-= digital_divide
*group
->min
;
1431 if(rate
< group
->min
)
1436 /*shaping of aggresive downloaders, with credit file support */
1439 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
1441 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
1443 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
1444 && ( ip
->traffic
>ip
->credit
1445 + (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))) )
1447 if(group_rate
<ip
->max
)
1451 group_rate
+=magic_treshold
;
1452 ip
->prio
=lowest_priority
;
1453 if(ip
->prio
<highest_priority
+2)
1455 ip
->prio
=highest_priority
+2;
1460 if( ip
->keyword
->data_prio
1462 && ( ip
->traffic
>ip
->credit
1463 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
1465 ip
->prio
=priority_sequence
--;
1466 if(ip
->prio
<highest_priority
+1)
1468 ip
->prio
=highest_priority
+1;
1474 unsigned long long lcredit
=0;
1476 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1478 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1480 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1488 fclose(credit_file
);
1494 f
=fopen(preview
,"w");
1497 else if(!dry_run
&& !just_flush
)
1499 /*-----------------------------------------------------------------*/
1500 printf("Writing data transfer database ...\n");
1501 /*-----------------------------------------------------------------*/
1502 f
=fopen("/var/run/prometheus.previous","w");
1505 for_each(ip
,ips
) if(ip
->traffic
|| ip
->direct
|| ip
->proxy
|| ip
->upload
)
1507 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",
1508 ip
->addr
, ip
->traffic
, ip
->direct
, ip
->proxy
, ip
->upload
);
1522 /*-----------------------------------------------------------------*/
1523 printf("Sorting data and generating statistics page %s ...\n", ptr
);
1524 /*-----------------------------------------------------------------*/
1526 if(use_jquery_popups
)
1528 fprintf(f
,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url
);
1530 fputs("<table border>\n<tr><th align=\"right\">#</th><th align=\"right\">group</th><th align=\"right\">IPs</th><th align=\"right\">requested</th>\n",f
);
1531 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n", keywordcount
);
1534 for_each(group
, groups
)
1537 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1539 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1541 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",
1542 group
->count
, group
->desired
);
1544 for_each(keyword
, keywords
)
1546 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%d M</span></td>",
1547 keyword
->html_color
, group
->min
*keyword
->data_limit
);
1549 i
+= group
->desired
;
1550 total
+= group
->count
;
1554 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",
1557 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1558 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1560 for_each(keyword
, keywords
)
1562 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1564 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i
/line
));
1565 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount
, total
);
1567 fputs("</table>\n",f
);
1569 else if(!dry_run
&& !just_flush
)
1577 unsigned long long total_traffic
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1578 int active_classes
=0;
1581 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1582 int limit_count
=0, prio_count
=0;
1594 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1595 fprintf(f
," (%s)</th></tr>\n", d
);
1596 fputs("<tr><td align=\"right\">#</td><td>hostname</td>",f
);
1599 fputs("<td align=\"right\">lms</td>\n",f
);
1601 fputs("<td align=\"right\">credit</td>\
1602 <td align=\"right\">limit</td>\
1603 <td align=\"right\">total</td>\
1604 <td align=\"right\">direct</td>\n",f
);
1607 fputs("<td align=\"right\">proxy</td>\n",f
);
1609 fputs("<td align=\"right\">upload</td>\
1610 <td align=\"right\">minimum</td>\
1611 <td align=\"right\">desired</td>\
1612 <td align=\"right\">maximum</td>\
1613 <td>prio</td></tr>\n",f
);
1615 for_each(ip
,ips
) if(!use_jquery_popups
|| !ip
->sharing
)
1617 char *f1
="", *f2
="";
1620 if(ip
->max
< ip
->desired
)
1622 f1
="<span style=\"color:red\">";
1626 else if(ip
->prio
> highest_priority
+1)
1628 f1
="<span style=\"color:brown\">";
1634 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1636 /* hostnames -------------------------------------- */
1637 fprintf(f
,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a>\n", ip
->name
, i
, log_url
, ip
->name
, ip
->name
);
1638 if(use_jquery_popups
)
1640 fprintf(f
,"<span id=\"sharing_%d\" style=\"display:none\">",i
);
1642 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1644 fprintf(f
,"<br /><a href=\"%s%s.log\">%s</a>\n", log_url
, sharedip
->name
, sharedip
->name
);
1647 fputs("</span>\n",f
);
1650 fprintf(f
,"<span>[<a href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1651 i
, i
, i
, popup_button
);
1655 /* ----------------------------------------------- */
1659 fputs("<td align=\"right\">",f
);
1662 /*base URL will be configurable soon ... */
1663 fprintf(f
,"<a href=\"%s%d\">%04d</a>\n", lms_url
, ip
->lmsid
, ip
->lmsid
);
1665 else if(ip
->lmsid
== 0)
1671 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->credit
);
1672 fprintf(f
,"<td align=\"right\"><span style=\"color:#%s\">%Lu M</span></td>",
1673 ip
->keyword
->html_color
,
1674 ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1675 fprintf(f
,"<td align=\"right\">%s%Lu M%s", f1
, ip
->traffic
, f2
);
1677 /* download --------------------------------------- */
1678 fprintf(f
,"</td><td align=\"right\">%Lu M", ip
->direct
);
1679 if(use_jquery_popups
)
1681 fprintf(f
,"<span id=\"download_%d\" style=\"display:none\">",i
);
1682 for_each(sharedip
, ips
) if(eq(ip
->name
, sharedip
->sharing
))
1684 fprintf(f
,"<br />%Lu M", sharedip
->direct
);
1686 fputs("</span>\n",f
);
1689 /* ----------------------------------------------- */
1693 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1695 /* upload ---------------------------------------- */
1696 fprintf(f
,"<td align=\"right\">%Lu M", ip
->upload
);
1697 if(use_jquery_popups
)
1699 fprintf(f
,"<span id=\"upload_%d\" style=\"display:none\">",i
);
1700 for_each(sharedip
,ips
) if(eq(ip
->name
, sharedip
->sharing
))
1702 fprintf(f
,"<br />%Lu M", sharedip
->upload
);
1704 fputs("</span>\n",f
);
1707 /* ----------------------------------------------- */
1709 fprintf(f
,"<td align=\"right\">%d k</td><td align=\"right\">%d k</td><td align=\"right\">%s%d k%s</td><td>%s%d%s</td></tr>\n",
1710 ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1712 total_traffic
+=ip
->traffic
;
1713 total_direct
+=ip
->direct
;
1714 total_proxy
+=ip
->proxy
;
1715 total_upload
+=ip
->upload
;
1719 tmp_sum
+=ip
->traffic
;
1722 sum
->i
=active_classes
;
1723 insert(sum
,sums
,order_by
,i
);
1728 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1729 iplog
=fopen(str
,"a");
1732 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
1733 time(NULL
), ip
->name
, ip
->traffic
, ip
->direct
, ip
->proxy
,
1734 ip
->upload
, ip
->min
, ip
->max
, ip
->desired
, ip
->lmsid
, d
); /* d = date*/
1739 fprintf(f
,"<tr><th colspan=\"%d\" align=\"left\">%d CLASSES</th>", colspan
-7, i
);
1740 fprintf(f
,"<th align=\"right\">%Lu M</th><th align=\"right\">%Lu M</th>\n", total_traffic
, total_direct
);
1743 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1745 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1746 fprintf(f
,"<th colspan=\"4\"><span style=\"color:red\">FUP-LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</table>\n",limit_count
,prio_count
);
1748 if(active_classes
>10)
1750 int top20_count
=0,top20_perc1
=0;
1751 long long top20_perc2
=0;
1752 unsigned long long top20_sum
=0l;
1754 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Resource Planning (ERP)</th></tr>\n",f
);
1755 fputs("<tr><td>Analytic category</td>\n",f
);
1756 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1758 if_exists(sum
,sums
,sum
->l
>=total_traffic
/4)
1760 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1761 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1764 if_exists(sum
,sums
,sum
->i
==10)
1766 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1767 fprintf(f
,"<th align=\"right\">10</th><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1770 if_exists(sum
,sums
,sum
->l
>=total_traffic
/2)
1772 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1773 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1776 if_exists(sum
,sums
,sum
->l
>=4*total_traffic
/5)
1778 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1779 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><th align=\"right\">%Ld %%</th></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1782 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1784 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1786 top20_perc1
=(100*sum
->i
+50)/active_classes
;
1788 top20_perc2
=(100*sum
->l
+50)/total_traffic
;
1789 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",top20_count
,top20_perc1
,top20_sum
,top20_perc2
);
1792 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1794 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1795 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1798 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1800 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1801 fprintf(f
,"<td align=\"right\">%d</td><th align=\"right\">%d %%</th><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1804 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1806 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1807 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d %%</td><td align=\"right\">%Lu M</td><td align=\"right\">%Ld %%</td></tr>\n",sum
->i
,(100*sum
->i
+50)/active_classes
,sum
->l
,(100*sum
->l
+50)/total_traffic
);
1810 fprintf(f
,"<tr><td><a href=\"%sERP.log\">All users, all traffic</a></td>\n", log_url
);
1811 fprintf(f
,"<th align=\"right\">%d</th><th align=\"right\">100 %%</th><th align=\"right\">%Lu M</th><th align=\"right\">100 %%</th></tr>\n",active_classes
,total_traffic
);
1812 fputs("</table>\n", f
);
1814 /* write basic ERP data to log directory */
1817 sprintf(str
,"%s/ERP.log",log_dir
);
1818 iplog
=fopen(str
,"a");
1821 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",
1822 time(NULL
), top20_count
, top20_perc1
, top20_sum
, top20_perc2
,
1823 active_classes
, total_traffic
, i
, limit_count
, prio_count
, d
); /* d = date*/
1829 fprintf(f
, stats_html_signature
, version
);
1835 puts("Statistics preview generated (-p switch) - now exiting ...");
1839 /*-----------------------------------------------------------------*/
1840 puts("Generating iptables and tc classes ...");
1841 /*-----------------------------------------------------------------*/
1844 printf("%-22s %-15s mark\n","name","ip");
1846 for_each(ip
,ips
) if(ip
->mark
>0)
1851 duplicate(ip
->addr
,buf
);
1852 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1854 string(chain_forward
,6+strlen(buf
));
1855 strcpy(chain_forward
,"forw_");
1856 strcat(chain_forward
,buf
);
1858 string(chain_postrouting
,6+strlen(buf
));
1859 strcpy(chain_postrouting
,"post_");
1860 strcat(chain_postrouting
,buf
);
1866 chain_forward
="FORWARD";
1867 chain_postrouting
="POSTROUTING";
1870 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1872 /* -------------------------------------------------------- mark download */
1874 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1875 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1876 /* -m limit --limit 1/s */
1881 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
);
1882 /*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);*/
1886 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1889 /* -------------------------------------------------------- mark upload */
1890 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1891 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1894 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1899 /* -------------------------------------------------------- download class */
1900 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1902 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
);
1905 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1907 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*/
1910 if (filter_type
== 1)
1912 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1916 /* -------------------------------------------------------- upload class */
1917 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1918 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1920 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1921 tc
, wan
, ip
->group
, ip
->mark
,
1922 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1923 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1926 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1928 sprintf(str
,"%s qdisc add dev %s parent 1:%d handle %d %s",tc
, wan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
1931 if (filter_type
== 1)
1933 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1938 printf("(sharing %s)\n", ip
->sharing
);
1944 chain_forward
= "forw_common";
1945 chain_postrouting
= "post_common";
1949 chain_forward
= "FORWARD";
1950 chain_postrouting
= "POSTROUTING";
1952 /* -------------------------------- classify or reject free download */
1954 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1955 if(free_min
) final_chain
= "ACCEPT";
1960 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);
1963 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1968 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1971 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1973 /* ------------------------------- classify or reject free upload */
1976 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1979 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1983 if(free_min
) /* allocate free bandwith if it is not zero... */
1985 /*-----------------------------------------------------------------*/
1986 puts("Generating free bandwith classes ...");
1987 /*-----------------------------------------------------------------*/
1988 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1989 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1991 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1992 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1995 if (strcmpi(qos_leaf
, "none"))
1997 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
2000 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
2003 /* tc handle 1 fw flowid */
2004 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
2007 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
2010 printf("Total IP count: %d\n", i
);
2012 if (log_file
) fclose(log_file
);
2014 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2015 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.704824 seconds and 4 git commands to generate.