a4dd301d7689cc257ea50ce2327d888ee3bd381b
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, 20110221
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";
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-2008 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 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
69 puts("Command line switches:\n\
71 -?, --help this help screen\n\
72 -v, --version show Version number of this utility and exit\n\
73 -c filename force alternative /etc/prometheus.Conf filename\n\
74 -h filename force alternative /etc/Hosts filename (overrides hosts keyword)\n\
75 -f just Flush iptables and tc classes and exit (stop shaping)\n\
76 -9 emergency iptables flush (do not read data transfer statistics)\n\
77 -p just generate Preview of data transfer statistics and exit\n\
78 -d Dry run (preview tc and iptables commands on stdout)\n\
79 -r Run (reset all statistics and start shaping)\n\
80 -n run Now (start shaping without delay - overrides qos-free-delay keyword)\n\
81 -l Mmm YYYY generate HTML summary of traffic Logs (Mmm=Jan-Dec or Year, YYYY=year)\n\
82 -m generate HTML summary of traffic logs for yesterday's Month\n\
83 -y generate HTML summary of traffic logs for yesterday's Year\n");
84 /* not yet implemented:
85 -s start shaping! (keep data transfer statistics - but apply shaping)\n\
88 /* === Configuraration file values defaults - stored in global variables ==== */
90 int filter_type
= 1; /*1 mark, 2 classify*/
92 char *mark_iptables
= "MARK --set-mark ";
93 int dry_run
= 0; /* preview - use puts() instead of system() */
94 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]";
95 FILE *iptables_file
= NULL
;
96 int enable_credit
= 1; /* enable credit file */
97 int use_credit
= 0; /* use credit file (if enabled)*/
98 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
99 int hall_of_fame
= 1; /* enable hall of fame */
100 char *lan
= "eth0"; /* LAN interface */
101 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
102 char *wan
= "eth1"; /* WAN/ISP interface */
103 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
104 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
105 char *qos_free_zone
= NULL
; /* QoS free zone */
106 int qos_proxy
= 1; /* include proxy port to QoS */
107 int include_upload
= 1; /* upload+download=total traffic */
108 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
109 int proxy_port
= 3128; /* proxy port number */
110 long long int line
= 1024; /* WAN/ISP download in kbps */
111 long long int up
= 1024; /* WAN/ISP upload in kbps */
112 int free_min
= 32; /* minimum guaranted bandwidth for all undefined hosts */
113 int free_max
= 64; /* maximum allowed bandwidth for all undefined hosts */
114 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
115 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
116 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
117 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
118 int burst
= 8; /* HTB burst (in kbits) */
120 int burst_group
= 32;
121 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
122 int keywordcount
= 0;
123 /* not yet implemented:
124 int fixed_packets = 0; maximum number of pps per IP address (not class!)
125 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
127 FILE *log_file
= NULL
;
128 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
130 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
131 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
132 const int idxtable_treshold1
= 24; /* this is no longer configurable */
133 const int idxtable_treshold2
= 12; /* this is no longer configurable */
134 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
135 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
137 /* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */
151 unsigned long long direct
;
152 unsigned long long proxy
;
153 unsigned long long upload
;
154 unsigned long long traffic
;
155 unsigned long long credit
;
156 unsigned long pktsup
;
157 unsigned long pktsdown
;
158 struct Keyword
*keyword
;
160 } *ips
=NULL
, *ip
, *sharedip
;
169 } *groups
=NULL
, *group
;
175 struct Index
*parent
;
179 } *idxs
=NULL
, *idx
, *metaindex
;
185 int asymetry_ratio
; /* ratio for ADSL-like upload */
186 int asymetry_fixed
; /* fixed treshold for ADSL-like upload */
187 int data_limit
; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
188 int data_prio
; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
189 long fixed_limit
; /* fixed data limit for setting lower HTB ceil */
190 long fixed_prio
; /* fixed data lmit for setting lower HTB prio */
191 int reserve_min
; /* bonus for nominal HTB rate bandwidth (in kbps) */
192 int reserve_max
; /* malus for nominal HTB ceil (in kbps) */
193 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
194 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
195 int default_prio
; /* default HTB priority for this keyword */
198 char *leaf_discipline
;
201 } *keyword
,*defaultkeyword
=NULL
,*keywords
=NULL
;
203 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
211 ip
->prio
= highest_priority
+1;
224 ip
->keyword
= keywords
;
228 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
230 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
232 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
234 char *ip
,*outip
,*outptr
,*fmt
;
237 /* debug printf("(%s,%d) -> ",ip,bitmask); */
239 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
240 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
242 /* should never exit here */
249 if(dot
<(bitmask
/8-1))
251 if(format_as_chainname
)
260 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
261 if(cutdot
)*cutdot
='\0';
262 if(format_as_chainname
)
267 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
271 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
272 sprintf(outptr
,fmt
,n
,bitmask
);
273 if(!format_as_chainname
) while(bitmask
<24)
278 /* debug printf("[%s]\n",outip); */
289 /*should never exit here*/
294 char *hash_id(char *ip
,int bitmask
)
295 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
297 char *subnet_id(char *ip
,int bitmask
)
298 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
300 /* ================= Let's parse configuration file here =================== */
302 void reject_config_and_exit(char *filename
)
304 printf("Configuration file %s rejected - abnormal exit.",filename
);
308 void get_config(char *config_filename
)
312 printf("Configured keywords: ");
313 parse(config_filename
)
315 option("keyword",kwd
);
320 create(keyword
,Keyword
);
322 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
323 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
324 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
325 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
326 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
327 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
328 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
329 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
331 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
332 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
333 keyword
->default_prio
=highest_priority
+1;
334 keyword
->html_color
="000000";
336 keyword
->leaf_discipline
="";
338 push(keyword
,keywords
);
339 if(!defaultkeyword
) defaultkeyword
=keyword
;
346 for_each(keyword
,keywords
)
348 int l
=strlen(keyword
->key
);
351 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
353 char *tmptr
=_
; /* <---- l+1 ----> */
354 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
355 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
356 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
357 ioption("magic-relative-limit",keyword
->data_limit
);
358 ioption("magic-relative-prio",keyword
->data_prio
);
359 loption("magic-fixed-limit",keyword
->fixed_limit
);
360 loption("magic-fixed-prio",keyword
->fixed_prio
);
361 ioption("htb-default-prio",keyword
->default_prio
);
362 ioption("htb-rate-bonus",keyword
->reserve_min
);
363 ioption("htb-ceil-malus",keyword
->reserve_max
);
365 ioption("htb-ceil-divide",keyword->divide_max);
366 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
368 option("leaf-discipline",keyword
->leaf_discipline
);
369 option("html-color",keyword
->html_color
);
372 if(keyword
->data_limit
|| keyword
->fixed_limit
||
373 keyword
->data_prio
|| keyword
->fixed_prio
)
380 option("iptables",iptables
);
381 option("iptables-save",iptablessave
); /* new */
382 option("iptables-restore",iptablesrestore
); /* new */
383 option("iptables-file",iptablesfile
); /* new */
384 option("hosts",hosts
);
385 option("lan-interface",lan
);
386 option("wan-interface",wan
);
387 option("lan-medium",lan_medium
);
388 option("wan-medium",wan_medium
);
389 lloption("wan-download",line
);
390 lloption("wan-upload",up
);
391 ioption("hall-of-fame-enable",hall_of_fame
);
392 option("hall-of-fame-title",title
);
393 option("hall-of-fame-filename",html
);
394 option("hall-of-fame-preview",preview
);
395 option("log-filename",cmdlog
);
396 option("credit-filename",credit
);
397 ioption("credit-enable",enable_credit
);
398 option("log-traffic-directory",log_dir
);
399 option("log-traffic-html-directory",html_log_dir
);
400 option("log-traffic-url-path",log_url
);
401 option("qos-free-zone",qos_free_zone
);
402 ioption("qos-free-delay",qos_free_delay
);
403 ioption("qos-proxy-enable",qos_proxy
);
404 option("qos-proxy-ip",proxy_ip
);
405 option("htb-leaf-discipline",qos_leaf
);
406 ioption("qos-proxy-port",proxy_port
);
407 ioption("free-rate",free_min
);
408 ioption("free-ceil",free_max
);
409 ioption("htb-burst",burst
);
410 ioption("htb-burst-main",burst_main
);
411 ioption("htb-burst-group",burst_group
);
412 ioption("htb-nesting-limit",max_nesting
);
413 ioption("htb-r2q",htb_r2q
);
414 ioption("magic-include-upload",include_upload
);
415 ioption("magic-treshold",magic_treshold
);
416 option("filter-type", cnf
);
418 /* not yet implemented:
419 ioption("magic-fixed-packets",fixed_packets);
420 ioption("magic-relative-packets",packet_limit);
425 perror(config_filename
);
426 puts("Warning - using built-in defaults instead ...");
431 /*leaf discipline for keywords*/
432 for_each(keyword
,keywords
)
434 if (!strcmpi(keyword
->leaf_discipline
, ""))
436 keyword
->leaf_discipline
= qos_leaf
;
440 if (strcmpi(cnf
, "mark")){
443 mark_iptables
= "CLASSIFY --set-class 1:";
447 mark_iptables
= "MARK --set-mark ";
450 /* are supplied values meaningful ?*/
453 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
454 reject_config_and_exit(config_filename
);
458 /* ===================== traffic analyser - uses iptables ================ */
460 void get_traffic_statistics(void)
465 textfile(Pipe
,str
) *line
,*lines
=NULL
;
469 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
481 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
482 unsigned long long traffic
=0;
483 unsigned long pkts
=0;
484 char *ipaddr
=NULL
,*ptr
;
486 /* debug puts(line->str); */
487 valid_columns(ptr
,line
->str
,' ',col
)
488 if(valid
) switch(col
)
490 case 1: if(eq(ptr
,"Chain"))
492 else if(eq(ptr
,"pkts"))
495 sscanf(ptr
,"%lu",&pkts
);
497 case 2: if(setchainname
)
499 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
502 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
505 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
509 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
511 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
513 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
515 case 8: if(downloadflag
)
517 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
522 case 9: if(downloadflag
)ipaddr
=ptr
;break;
525 if(accept
&& traffic
>0 && ipaddr
)
527 if(proxyflag
)printf("(proxy) ");
528 else if(!downloadflag
) printf("(upload) ");
529 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
531 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
536 if(eq(ip
->addr
,"0.0.0.0/0"))
538 ip
->name
="(unregistered)";
540 ip
->max
=ip
->desired
=free_max
;
549 ip
->traffic
+=traffic
;
550 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
558 ip
->traffic
+=traffic
;
560 if(traffic
>ip
->traffic
)
569 /* ========== This function executes, logs OR ALSO prints command ========== */
571 void safe_run(char *cmd
)
573 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
574 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
577 void save_line(char *line
)
579 fprintf(iptables_file
,"%s\n",line
);
582 void run_restore(void)
585 string(restor
,STRLEN
);
587 /*-----------------------------------------------------------------*/
588 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
589 /*-----------------------------------------------------------------*/
592 fclose(iptables_file
);
602 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
608 /* == This function strips extra characters after IP address and stores it = */
610 void parse_ip(char *str
)
612 char *ptr
=str
,*ipaddr
=NULL
,*ipname
=NULL
;;
614 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
620 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
623 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
627 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
636 char *parse_datafile_line(char *str
)
638 char *ptr
=strchr(str
,' ');
660 void parse_ip_log(int argc
, char **argv
)
662 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
663 long traffic
=0l, traffic_month
, total
=0, guaranted
;
664 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0;
665 char mstr
[4], ystr
[5];
668 string(filename
,STRLEN
);
670 if(argv
[1][1]=='l') /* -l */
674 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
680 if(eq(month
,"Year")) any_month
=1;
686 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
687 struct tm
*timep
= localtime(&t
);
689 if(argv
[1][1]=='m') /* -m yestarday - month */
691 strftime(mstr
, 4, "%b", timep
);
693 strftime(ystr
, 5, "%Y", timep
);
696 else /* -y yesterday - year */
700 strftime(ystr
, 5, "%Y", timep
);
704 printf("Analysing traffic for %s %s ...\n",month
,year
);
706 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
707 sprintf(str
,"%s %s/",ls
,log_dir
);
711 if(strstr(str
,".log"))
713 ptr
=strrchr(str
,'\n');
715 sprintf(filename
,"%s/%s",log_dir
,str
);
716 printf("Parsing %s ...",filename
);
723 valid_columns(ptr
,_
,'\t',col
) switch(col
)
725 case 2: name
= ptr
;break;
726 case 3: traffic
= atol(ptr
);break;
727 /* column number - was 7, now 10...*/
731 case 10: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
733 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
735 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
736 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
741 if(col
== 7) guaranted
= atol(ptr
);
747 traffic_month
+= traffic
;
757 iplog
->guaranted
= guaranted
;
758 iplog
->traffic
= traffic_month
;
759 insert(iplog
,iplogs
,desc_order_by
,traffic
);
760 printf(" %ld MB\n",iplog
->traffic
);
764 puts(" no records.");
768 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
769 printf("Writing %s ...",str
);
773 fprintf(f
,"<table border><tr><th colspan=\"2\">%s %s</th><th colspan=\"2\">Data transfers</th><th align=\"right\">Min.speed</th></tr>\n ",month
,year
);
775 for_each(iplog
,iplogs
)
779 fprintf(f
,"<tr><td align=\"right\">%d</td><th align=\"left\">%s</td><td align=\"right\">%ld M</td><th align=\"right\">%ld G</th><td align=\"right\">%ld kbps</th></tr>\n",
780 i
++, iplog
->name
, iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
781 total
+=iplog
->traffic
>>10;
786 fprintf(f
,"<tr><th colspan=\"3\" align=\"left\">Total:</th><th align=\"right\">%ld GB</th><th align=\"right\">%Ld kbps</th></tr>\n", total
, line
);
787 fputs("</table>\n", f
);
791 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
792 fputs("<tr><td>Analytic category</td>\n",f
);
793 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
795 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
797 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
798 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
));
801 if_exists(iplog
,iplogs
,iplog
->i
==10)
803 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
804 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
));
807 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
809 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
810 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
));
813 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
815 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
816 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
));
819 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
821 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
822 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
));
825 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
827 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
828 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
));
831 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
833 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
834 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
));
837 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
839 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
840 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
));
843 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
844 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
);
845 fputs("</table>\n", f
);
848 fprintf(f
, stats_html_signature
, version
);
854 /*-----------------------------------------------------------------*/
855 /* Are you looking for int main(int argc, char **argv) ? :-)) */
856 /*-----------------------------------------------------------------*/
864 int class_count
=0,ip_count
=0;
866 int just_flush
=FALSE
;
868 int just_preview
=FALSE
; /* preview - generate just stats */
869 int just_logs
=FALSE
; /* just parse logs */
872 char *chain_forward
, *chain_postrouting
;
876 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
877 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
878 iptables-restore & burst tunning & classify modification by Ludva\n\
879 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
881 /*----- Boring... we have to check command line options first: ----*/
885 argument("-c") { nextargument(config
); }
886 argument("-h") { nextargument(althosts
);}
887 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
888 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
889 argument("-9") { run
=TRUE
; just_flush
=9; }
890 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
891 argument("-r") { run
=TRUE
; }
892 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
893 argument("-l") { just_logs
=TRUE
; }
894 argument("-m") { just_logs
=TRUE
; }
895 argument("-y") { just_logs
=TRUE
; }
896 argument("-?") { help(); exit(0); }
897 argument("--help") { help(); exit(0); }
898 argument("-v") { exit(0); }
899 argument("--version") { exit(0); }
904 puts("*** THIS IS JUST DRY RUN ! ***\n");
907 date(d
); /* this is typical cll1.h macro - prints current date */
909 /*-----------------------------------------------------------------*/
910 printf("Parsing configuration file %s ...\n", config
);
911 /*-----------------------------------------------------------------*/
916 parse_ip_log(argc
,argv
);
932 /*-----------------------------------------------------------------*/
933 puts("Parsing iptables verbose output ...");
934 /*-----------------------------------------------------------------*/
935 get_traffic_statistics();
938 /*-----------------------------------------------------------------*/
939 printf("Parsing class defintion file %s ...\n", hosts
);
940 /*-----------------------------------------------------------------*/
941 int groupidx
= FIRSTGROUPID
;
946 if(*str
<'0' || *str
>'9')
949 //Does this IP share QoS class with some other ?
950 substring
=strstr(str
,"sharing-");
953 substring
+=8; //"sharing-"
956 ip
->sharing
=substring
;
957 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
958 while(*substring
&& *substring
!='\n')
964 //Do we have to create new QoS class for this IP ?
966 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
972 ip
->prio
=keyword
->default_prio
;
973 substring
+=strlen(keyword
->key
)+1;
975 while(*ptr
&& *ptr
!='-')
980 ip
->max
=ip
->desired
=atoi(ptr
+1);
982 ip
->min
=atoi(substring
);
985 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
991 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
995 ip
->max
-=ip
->keyword
->reserve_max
;
998 if(ip->keyword->divide_max>1)
999 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
1000 if(ip->keyword->htb_ceil_bonus_divide>0)
1001 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
1006 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1008 if_exists(group
,groups
,group
->min
==ip
->min
)
1011 group
->desired
+=ip
->min
;
1012 ip
->group
= group
->id
;
1016 create(group
,Group
);
1018 group
->id
= groupidx
++;
1019 ip
->group
= group
->id
;
1021 if(group
->min
<8) group
->min
=8;
1022 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1023 /* it is because class IDs are derived from min. bandwidth. - xCh */
1024 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1027 group
->desired
=ip
->min
;
1028 insert(group
,groups
,desc_order_by
,min
);
1040 /*-----------------------------------------------------------------*/
1041 /* cll1.h - let's allocate brand new character buffer... */
1042 /*-----------------------------------------------------------------*/
1045 /*-----------------------------------------------------------------*/
1046 puts("Resolving shared connections ...");
1047 /*-----------------------------------------------------------------*/
1048 for_selected(ip
,ips
,ip
->sharing
)
1050 for_selected(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
1052 sharedip
->traffic
+=ip
->traffic
;
1054 ip
->mark
=sharedip
->mark
;
1058 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1061 if(enable_credit
&& just_flush
<9)
1063 /*-----------------------------------------------------------------*/
1064 printf("Parsing credit file %s ...\n", credit
);
1065 /*-----------------------------------------------------------------*/
1068 ptr
=parse_datafile_line(_
);
1071 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1073 sscanf(ptr
,"%Lu",&(ip
->credit
));
1082 /*-----------------------------------------------------------------*/
1083 puts("Initializing iptables and tc classes ...");
1084 /*-----------------------------------------------------------------*/
1086 iptables_file
=fopen(iptablesfile
,"w");
1087 if (iptables_file
== NULL
) {
1088 puts("Cannot open iptablesfile!");
1092 log_file
=fopen(cmdlog
,"w");
1093 if (log_file
== NULL
) {
1094 puts("Cannot open logfile!");
1098 save_line(iptablespreamble
);
1101 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1104 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1107 iptables_file
=fopen(iptablesfile
,"w");
1108 save_line(iptablespreamble
);
1110 if(qos_free_zone
&& *qos_free_zone
!='0')
1114 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1119 save_line(":post_noproxy - [0:0]");
1120 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1122 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1124 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1127 chain
="post_noproxy";
1130 chain
="POSTROUTING";
1132 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1136 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1138 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1140 /*-----------------------------------------------------------------*/
1141 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1142 /*-----------------------------------------------------------------*/
1144 save_line(":post_common - [0:0]");
1145 save_line(":forw_common - [0:0]");
1147 for_selected(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1149 buf
=hash_id(ip
->addr
,bitmask
);
1150 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1159 idx
->bitmask
=bitmask
;
1167 /* brutal perfomance optimalization */
1168 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1170 bitmask
-=idxtable_bitmask2
;
1173 for_selected(idx
,idxs
,idx
->parent
==NULL
)
1175 buf
=hash_id(idx
->addr
,bitmask
);
1176 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1178 metaindex
->children
++;
1182 create(metaindex
,Index
);
1183 metaindex
->addr
=idx
->addr
;
1185 metaindex
->bitmask
=bitmask
;
1186 metaindex
->parent
=NULL
;
1187 metaindex
->children
=0;
1189 push(metaindex
,idxs
);
1191 idx
->parent
=metaindex
;
1195 /* this should slightly optimize throughout ... */
1196 sort(idx
,idxs
,desc_order_by
,children
);
1197 sort(idx
,idxs
,order_by
,bitmask
);
1203 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1204 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1206 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1209 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1214 string(buf
,strlen(idx
->parent
->id
)+6);
1215 sprintf(buf
,"post_%s",idx
->parent
->id
);
1220 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1223 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1228 string(buf
,strlen(idx
->parent
->id
)+6);
1229 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1234 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1237 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1240 printf("Total indexed iptables chains created: %d\n", i
);
1242 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1245 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1253 fclose(iptables_file
);
1254 if (log_file
) fclose(log_file
);
1255 puts("Just flushed iptables and tc classes - now exiting ...");
1261 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1263 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1264 sleep(qos_free_delay
);
1267 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1270 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1271 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1274 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1275 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1278 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1281 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1282 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1285 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1286 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1290 /*-----------------------------------------------------------------*/
1291 puts("Locating heavy downloaders and generating root classes ...");
1292 /*-----------------------------------------------------------------*/
1293 sort(ip
,ips
,desc_order_by
,traffic
);
1296 /*-----------------------------------------------------------------*/
1297 /* sub-scope - local variables */
1299 long long int rate
=line
;
1300 long long int max
=line
;
1302 FILE *credit_file
=NULL
;
1304 if(!just_preview
&& !dry_run
&& enable_credit
) credit_file
=fopen(credit
,"w");
1306 for_each(group
,groups
)
1311 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",
1312 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1316 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",
1317 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1321 if(group_count
++<max_nesting
) parent
=group
->id
;
1323 rate
-=digital_divide
*group
->min
;
1324 if(rate
<group
->min
)rate
=group
->min
;
1326 /*shaping of aggresive downloaders, with credit file support */
1329 int group_rate
=group
->min
, priority_sequence
=lowest_priority
;
1331 for_selected(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1333 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
&&
1334 ip
->traffic
>ip
->credit
+
1335 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)) )
1337 if(group_rate
<ip
->max
) ip
->max
=group_rate
;
1338 group_rate
+=magic_treshold
;
1339 ip
->prio
=lowest_priority
;
1340 if(ip
->prio
<highest_priority
+2) ip
->prio
=highest_priority
+2;
1344 if( ip
->keyword
->data_prio
&& !ip
->fixedprio
&&
1345 ip
->traffic
>ip
->credit
+
1346 (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20)) )
1348 ip
->prio
=priority_sequence
--;
1349 if(ip
->prio
<highest_priority
+1) ip
->prio
=highest_priority
+1;
1354 unsigned long long lcredit
=0;
1356 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1357 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1358 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1365 if(credit_file
)fclose(credit_file
);
1370 f
=fopen(preview
,"w");
1373 else if(!dry_run
&& !just_flush
)
1375 /*-----------------------------------------------------------------*/
1376 printf("Writing data transfer database ...\n");
1377 /*-----------------------------------------------------------------*/
1378 f
=fopen("/var/run/prometheus.previous","w");
1381 for_selected(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1382 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1396 /*-----------------------------------------------------------------*/
1397 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1398 /*-----------------------------------------------------------------*/
1400 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
);
1401 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1404 for_each(group
,groups
)
1407 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1409 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1410 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1412 for_each(keyword
,keywords
)
1414 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1417 total
+=group
->count
;
1421 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1423 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1424 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1426 for_each(keyword
,keywords
)
1428 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1430 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1431 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1433 fputs("</table>\n",f
);
1435 else if(!dry_run
&& !just_flush
)
1441 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1442 int active_classes
=0;
1445 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1452 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1453 fprintf(f
," (%s)</th></tr>\n", d
);
1454 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1455 <td align=\"right\">credit</td>\
1456 <td align=\"right\">limit</td>\
1457 <td align=\"right\">total</td>\
1458 <td align=\"right\">direct</td>\n",f
);
1460 fputs("<td align=\"right\">proxy</td>\n",f
);
1461 fputs("<td align=\"right\">upload</td>\
1462 <td align=\"right\">minimum</td>\
1463 <td align=\"right\">desired</td>\
1464 <td align=\"right\">maximum</td>\
1465 <td>prio</td></tr>\n",f
);
1469 char *f1
="", *f2
="";
1470 if(ip
->max
<ip
->desired
)
1472 f1
="<font color=\"red\">";
1475 else if(ip
->prio
>highest_priority
+1)
1477 f1
="<font color=\"brown\">";
1482 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1484 fprintf(f
,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td><td align=\"right\">%Lu M</td>\n",
1485 ip
->name
, i
, log_url
, ip
->name
, ip
->name
, ip
->credit
);
1486 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",ip
->keyword
->html_color
,ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)));
1487 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1489 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1490 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1491 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",ip
->min
,ip
->desired
,f1
,ip
->max
,f2
,f1
,ip
->prio
,f2
);
1493 total_direct
+=ip
->direct
;
1494 total_proxy
+=ip
->proxy
;
1495 total_upload
+=ip
->upload
;
1499 tmp_sum
+=ip
->traffic
;
1502 sum
->i
=active_classes
;
1503 insert(sum
,sums
,order_by
,i
);
1510 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1511 iplog
=fopen(str
,"a");
1514 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%s",
1515 time(NULL
),ip
->name
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
,ip
->min
,ip
->max
,ip
->desired
,d
); /* d = date*/
1521 fprintf(f
,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1522 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1523 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1525 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1526 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1527 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1529 if(active_classes
>10)
1531 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1532 fputs("<tr><td>Analytic category</td>\n",f
);
1533 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1535 if_exists(sum
,sums
,sum
->l
>=total
/4)
1537 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1538 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
);
1541 if_exists(sum
,sums
,sum
->i
==10)
1543 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1544 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
);
1547 if_exists(sum
,sums
,sum
->l
>=total
/2)
1549 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1550 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
);
1553 if_exists(sum
,sums
,sum
->l
>=4*total
/5)
1555 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1556 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
);
1559 if_exists (sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1561 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1562 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
);
1565 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1567 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1568 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
);
1571 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1573 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1574 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
);
1577 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1579 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1580 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
);
1583 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
1584 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
);
1585 fputs("</table>\n", f
);
1587 fprintf(f
, stats_html_signature
, version
);
1593 puts("Statistics preview generated (-p switch) - now exiting ...");
1597 /*-----------------------------------------------------------------*/
1598 puts("Generating iptables and tc classes ...");
1599 /*-----------------------------------------------------------------*/
1602 printf("%-22s %-15s mark\n","name","ip");
1604 for_selected(ip
,ips
,ip
->mark
>0)
1610 duplicate(ip
->addr
,buf
);
1611 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1613 string(chain_forward
,6+strlen(buf
));
1614 strcpy(chain_forward
,"forw_");
1615 strcat(chain_forward
,buf
);
1617 string(chain_postrouting
,6+strlen(buf
));
1618 strcpy(chain_postrouting
,"post_");
1619 strcat(chain_postrouting
,buf
);
1625 chain_forward
="FORWARD";
1626 chain_postrouting
="POSTROUTING";
1629 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1631 /* -------------------------------------------------------- mark download */
1633 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1634 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1635 /* -m limit --limit 1/s */
1640 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
);
1641 /*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);*/
1645 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1648 /* -------------------------------------------------------- mark upload */
1649 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1650 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1653 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1658 /* -------------------------------------------------------- download class */
1659 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1661 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
);
1664 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1666 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*/
1669 if (filter_type
== 1)
1671 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1675 /* -------------------------------------------------------- upload class */
1676 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1677 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1679 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1680 tc
, wan
, ip
->group
, ip
->mark
,
1681 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1682 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1685 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1687 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*/
1690 if (filter_type
== 1)
1692 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1697 printf("(sharing %s)\n", ip
->sharing
);
1703 chain_forward
= "forw_common";
1704 chain_postrouting
= "post_common";
1708 chain_forward
= "FORWARD";
1709 chain_postrouting
= "POSTROUTING";
1711 /* -------------------------------- classify or reject free download */
1713 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1714 if(free_min
) final_chain
= "ACCEPT";
1719 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);
1722 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1727 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1730 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1732 /* ------------------------------- classify or reject free upload */
1735 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1738 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1742 if(free_min
) /* allocate free bandwith if it is not zero... */
1744 /*-----------------------------------------------------------------*/
1745 puts("Generating free bandwith classes ...");
1746 /*-----------------------------------------------------------------*/
1747 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1748 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1750 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1751 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1754 if (strcmpi(qos_leaf
, "none"))
1756 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1759 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1762 /* tc handle 1 fw flowid */
1763 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1766 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1769 printf("Total IP count: %d\n", i
);
1771 if (log_file
) fclose(log_file
);
1773 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1774 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.389576 seconds and 3 git commands to generate.