bd1a8d03737309718e2fcf4426919041244f68af
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;
213 ip
->mark
=ip
->min
=ip
->max
=ip
->desired
=ip
->credit
=0;
214 ip
->upload
=ip
->proxy
=ip
->direct
=ip
->traffic
=0;
215 ip
->pktsup
=ip
->pktsdown
=0;
216 ip
->keyword
=keywords
;
220 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
222 char *very_ugly_ipv4_code(char *inip
,int bitmask
,int format_as_chainname
)
224 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
226 char *ip
,*outip
,*outptr
,*fmt
;
229 /* debug printf("(%s,%d) -> ",ip,bitmask); */
231 if(ip
&& *ip
&& bitmask
>=0 && bitmask
<=32)
232 string(outip
,strlen(ip
)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
234 /* should never exit here */
241 if(dot
<(bitmask
/8-1))
243 if(format_as_chainname
)
252 char *cutdot
=strchr(ip
+1,'.'); /*for bitmask<24*/
253 if(cutdot
)*cutdot
='\0';
254 if(format_as_chainname
)
259 n
=atoi(ip
+1)-atoi(ip
+1)%(1<<(8-bitmask
%8));
263 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
264 sprintf(outptr
,fmt
,n
,bitmask
);
265 if(!format_as_chainname
) while(bitmask
<24)
270 /* debug printf("[%s]\n",outip); */
281 /*should never exit here*/
286 char *hash_id(char *ip
,int bitmask
)
287 { return very_ugly_ipv4_code(ip
,bitmask
,1); }
289 char *subnet_id(char *ip
,int bitmask
)
290 { return very_ugly_ipv4_code(ip
,bitmask
,0); }
292 /* ================= Let's parse configuration file here =================== */
294 void reject_config_and_exit(char *filename
)
296 printf("Configuration file %s rejected - abnormal exit.",filename
);
300 void get_config(char *config_filename
)
304 printf("Configured keywords: ");
305 parse(config_filename
)
307 option("keyword",kwd
);
312 create(keyword
,Keyword
);
314 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
315 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
316 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
317 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
318 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
319 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
320 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
321 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
323 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max
324 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
325 keyword
->default_prio
=highest_priority
+1;
326 keyword
->html_color
="000000";
328 keyword
->leaf_discipline
="";
330 push(keyword
,keywords
);
331 if(!defaultkeyword
) defaultkeyword
=keyword
;
338 for_each(keyword
,keywords
)
340 int l
=strlen(keyword
->key
);
343 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
345 char *tmptr
=_
; /* <---- l+1 ----> */
346 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
347 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
348 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
349 ioption("magic-relative-limit",keyword
->data_limit
);
350 ioption("magic-relative-prio",keyword
->data_prio
);
351 loption("magic-fixed-limit",keyword
->fixed_limit
);
352 loption("magic-fixed-prio",keyword
->fixed_prio
);
353 ioption("htb-default-prio",keyword
->default_prio
);
354 ioption("htb-rate-bonus",keyword
->reserve_min
);
355 ioption("htb-ceil-malus",keyword
->reserve_max
);
357 ioption("htb-ceil-divide",keyword->divide_max);
358 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);
360 option("leaf-discipline",keyword
->leaf_discipline
);
361 option("html-color",keyword
->html_color
);
364 if(keyword
->data_limit
|| keyword
->fixed_limit
||
365 keyword
->data_prio
|| keyword
->fixed_prio
)
372 option("iptables",iptables
);
373 option("iptables-save",iptablessave
); /* new */
374 option("iptables-restore",iptablesrestore
); /* new */
375 option("iptables-file",iptablesfile
); /* new */
376 option("hosts",hosts
);
377 option("lan-interface",lan
);
378 option("wan-interface",wan
);
379 option("lan-medium",lan_medium
);
380 option("wan-medium",wan_medium
);
381 lloption("wan-download",line
);
382 lloption("wan-upload",up
);
383 ioption("hall-of-fame-enable",hall_of_fame
);
384 option("hall-of-fame-title",title
);
385 option("hall-of-fame-filename",html
);
386 option("hall-of-fame-preview",preview
);
387 option("log-filename",cmdlog
);
388 option("credit-filename",credit
);
389 ioption("credit-enable",enable_credit
);
390 option("log-traffic-directory",log_dir
);
391 option("log-traffic-html-directory",html_log_dir
);
392 option("log-traffic-url-path",log_url
);
393 option("qos-free-zone",qos_free_zone
);
394 ioption("qos-free-delay",qos_free_delay
);
395 ioption("qos-proxy-enable",qos_proxy
);
396 option("qos-proxy-ip",proxy_ip
);
397 option("htb-leaf-discipline",qos_leaf
);
398 ioption("qos-proxy-port",proxy_port
);
399 ioption("free-rate",free_min
);
400 ioption("free-ceil",free_max
);
401 ioption("htb-burst",burst
);
402 ioption("htb-burst-main",burst_main
);
403 ioption("htb-burst-group",burst_group
);
404 ioption("htb-nesting-limit",max_nesting
);
405 ioption("htb-r2q",htb_r2q
);
406 ioption("magic-include-upload",include_upload
);
407 ioption("magic-treshold",magic_treshold
);
408 option("filter-type", cnf
);
410 /* not yet implemented:
411 ioption("magic-fixed-packets",fixed_packets);
412 ioption("magic-relative-packets",packet_limit);
417 perror(config_filename
);
418 puts("Warning - using built-in defaults instead ...");
423 /*leaf discipline for keywords*/
424 for_each(keyword
,keywords
)
426 if (!strcmpi(keyword
->leaf_discipline
, ""))
428 keyword
->leaf_discipline
= qos_leaf
;
432 if (strcmpi(cnf
, "mark")){
435 mark_iptables
= "CLASSIFY --set-class 1:";
439 mark_iptables
= "MARK --set-mark ";
442 /* are supplied values meaningful ?*/
445 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
446 reject_config_and_exit(config_filename
);
450 /* ===================== traffic analyser - uses iptables ================ */
452 void get_traffic_statistics(void)
457 textfile(Pipe
,str
) *line
,*lines
=NULL
;
461 sprintf(cmd
,"%s -L -v -x -n -t mangle",iptables
);
473 int col
, accept
=0,proxyflag
=0,valid
=1,setchainname
=0,commonflag
=0;
474 unsigned long long traffic
=0;
475 unsigned long pkts
=0;
476 char *ipaddr
=NULL
,*ptr
;
478 /* debug puts(line->str); */
479 valid_columns(ptr
,line
->str
,' ',col
)
480 if(valid
) switch(col
)
482 case 1: if(eq(ptr
,"Chain"))
484 else if(eq(ptr
,"pkts"))
487 sscanf(ptr
,"%lu",&pkts
);
489 case 2: if(setchainname
)
491 if(!strncmp(ptr
,"post_",5) || eq(ptr
,"POSTROUTING"))
494 if(!strncmp(ptr
,"forw_",5) || eq(ptr
,"FORWARD"))
497 if(eq(ptr
,"post_common") || eq(ptr
,"forw_common"))
501 sscanf(ptr
,"%Lu",&traffic
); traffic
+=(1<<19); traffic
>>=20;
503 case 3: if((strncmp(ptr
,"post_",5) && strncmp(ptr
,"forw_",5)) || commonflag
)
505 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
507 case 8: if(downloadflag
)
509 if(strstr(proxy_ip
,ptr
))proxyflag
=1;
514 case 9: if(downloadflag
)ipaddr
=ptr
;break;
517 if(accept
&& traffic
>0 && ipaddr
)
519 if(proxyflag
)printf("(proxy) ");
520 else if(!downloadflag
) printf("(upload) ");
521 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr
, traffic
, pkts
);
523 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
528 if(eq(ip
->addr
,"0.0.0.0/0"))
530 ip
->name
="(unregistered)";
532 ip
->max
=ip
->desired
=free_max
;
541 ip
->traffic
+=traffic
;
542 ip
->direct
=ip
->traffic
-ip
->upload
-ip
->proxy
;
550 ip
->traffic
+=traffic
;
552 if(traffic
>ip
->traffic
)
561 /* ========== This function executes, logs OR ALSO prints command ========== */
563 void safe_run(char *cmd
)
565 if(dry_run
) printf("\n=>%s\n",cmd
); else system(cmd
);
566 if(log_file
) fprintf(log_file
,"%s\n",cmd
);
569 void save_line(char *line
)
571 fprintf(iptables_file
,"%s\n",line
);
574 void run_restore(void)
577 string(restor
,STRLEN
);
579 /*-----------------------------------------------------------------*/
580 printf("Running %s <%s ...\n",iptablesrestore
,iptablesfile
);
581 /*-----------------------------------------------------------------*/
584 fclose(iptables_file
);
594 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
600 /* == This function strips extra characters after IP address and stores it = */
602 void parse_ip(char *str
)
604 char *ptr
=str
,*ipaddr
=NULL
,*ipname
=NULL
;;
606 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
612 while(*ptr
&& (*ptr
==' ' || *ptr
==9))
615 while(*ptr
&& *ptr
!=' ' && *ptr
!=9)
619 if_exists(ip
,ips
,eq(ip
->addr
,ipaddr
));
628 char *parse_datafile_line(char *str
)
630 char *ptr
=strchr(str
,' ');
652 void parse_ip_log(int argc
, char **argv
)
654 char *month
, *year
, *str
, *name
="(undefined)", *ptr
, *ptr2
, *filename
;
655 long traffic
=0l, traffic_month
, total
=0, guaranted
;
656 int col
, col2
, y_ok
, m_ok
, accept_month
, i
=1, any_month
=0;
657 char mstr
[4], ystr
[5];
660 string(filename
,STRLEN
);
662 if(argv
[1][1]=='l') /* -l */
666 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");
672 if(eq(month
,"Year")) any_month
=1;
678 time_t t
= time(NULL
) - 3600*24 ; /* yesterday's timestamp*/
679 struct tm
*timep
= localtime(&t
);
681 if(argv
[1][1]=='m') /* -m yestarday - month */
683 strftime(mstr
, 4, "%b", timep
);
685 strftime(ystr
, 5, "%Y", timep
);
688 else /* -y yesterday - year */
692 strftime(ystr
, 5, "%Y", timep
);
696 printf("Analysing traffic for %s %s ...\n",month
,year
);
698 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */
699 sprintf(str
,"%s %s/",ls
,log_dir
);
703 if(strstr(str
,".log"))
705 ptr
=strrchr(str
,'\n');
707 sprintf(filename
,"%s/%s",log_dir
,str
);
708 printf("Parsing %s ...",filename
);
715 valid_columns(ptr
,_
,'\t',col
) switch(col
)
717 case 2: name
= ptr
;break;
718 case 3: traffic
= atol(ptr
);break;
719 /* column number - was 7, now 10...*/
723 case 10: if (isalpha(*ptr
)) /* character, not numeric string = date, just one*/
725 valid_columns(ptr2
,ptr
,' ',col2
) switch(col2
)
727 case 2: if(any_month
|| eq(ptr2
,month
)) m_ok
= 1; break;
728 case 5: if(eq(ptr2
,year
)) y_ok
= 1; break;
733 if(col
== 7) guaranted
= atol(ptr
);
739 traffic_month
+= traffic
;
749 iplog
->guaranted
= guaranted
;
750 iplog
->traffic
= traffic_month
;
751 insert(iplog
,iplogs
,desc_order_by
,traffic
);
752 printf(" %ld MB\n",iplog
->traffic
);
756 puts(" no records.");
760 sprintf(str
,"%s/%s-%s.html",html_log_dir
,year
,month
);
761 printf("Writing %s ...",str
);
765 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
);
767 for_each(iplog
,iplogs
)
771 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",
772 i
++, iplog
->name
, iplog
->traffic
, iplog
->traffic
>>10, iplog
->guaranted
);
773 total
+=iplog
->traffic
>>10;
778 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
);
779 fputs("</table>\n", f
);
783 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
784 fputs("<tr><td>Analytic category</td>\n",f
);
785 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
787 if_exists(iplog
,iplogs
,iplog
->l
>=total
/4)
789 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
790 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
));
793 if_exists(iplog
,iplogs
,iplog
->i
==10)
795 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
796 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
));
799 if_exists(iplog
,iplogs
,iplog
->l
>=total
/2)
801 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
802 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
));
805 if_exists(iplog
,iplogs
,iplog
->l
>=4*total
/5)
807 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
808 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
));
811 if_exists (iplog
,iplogs
,iplog
->i
>=i
/5)
813 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
814 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
));
817 if_exists(iplog
,iplogs
,iplog
->i
>=i
/4)
819 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
820 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
));
823 if_exists(iplog
,iplogs
,iplog
->i
>=i
/2)
825 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
826 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
));
829 if_exists(iplog
,iplogs
,iplog
->i
>=4*i
/5)
831 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
832 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
));
835 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
836 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
);
837 fputs("</table>\n", f
);
840 fprintf(f
, stats_html_signature
, version
);
846 /*-----------------------------------------------------------------*/
847 /* Are you looking for int main(int argc, char **argv) ? :-)) */
848 /*-----------------------------------------------------------------*/
856 int class_count
=0,ip_count
=0;
858 int just_flush
=FALSE
;
860 int just_preview
=FALSE
; /* preview - generate just stats */
861 int just_logs
=FALSE
; /* just parse logs */
864 char *chain_forward
, *chain_postrouting
;
868 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
869 Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\
870 iptables-restore & burst tunning & classify modification by Ludva\n\
871 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
873 /*----- Boring... we have to check command line options first: ----*/
877 argument("-c") { nextargument(config
); }
878 argument("-h") { nextargument(althosts
);}
879 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
880 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
881 argument("-9") { run
=TRUE
; just_flush
=9; }
882 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
883 argument("-r") { run
=TRUE
; }
884 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
885 argument("-l") { just_logs
=TRUE
; }
886 argument("-m") { just_logs
=TRUE
; }
887 argument("-y") { just_logs
=TRUE
; }
888 argument("-?") { help(); exit(0); }
889 argument("--help") { help(); exit(0); }
890 argument("-v") { exit(0); }
891 argument("--version") { exit(0); }
896 puts("*** THIS IS JUST DRY RUN ! ***\n");
899 date(d
); /* this is typical cll1.h macro - prints current date */
901 /*-----------------------------------------------------------------*/
902 printf("Parsing configuration file %s ...\n", config
);
903 /*-----------------------------------------------------------------*/
908 parse_ip_log(argc
,argv
);
924 /*-----------------------------------------------------------------*/
925 puts("Parsing iptables verbose output ...");
926 /*-----------------------------------------------------------------*/
927 get_traffic_statistics();
930 /*-----------------------------------------------------------------*/
931 printf("Parsing class defintion file %s ...\n", hosts
);
932 /*-----------------------------------------------------------------*/
933 int groupidx
= FIRSTGROUPID
;
938 if(*str
<'0' || *str
>'9')
941 //Does this IP share QoS class with some other ?
942 substring
=strstr(str
,"sharing-");
945 substring
+=8; //"sharing-"
948 ip
->sharing
=substring
;
949 ip
->keyword
=defaultkeyword
; /* settings for default keyword */
950 while(*substring
&& *substring
!='\n')
956 //Do we have to create new QoS class for this IP ?
958 if_exists(keyword
,keywords
,(substring
=strstr(str
,keyword
->key
)))
964 ip
->prio
=keyword
->default_prio
;
965 substring
+=strlen(keyword
->key
)+1;
967 while(*ptr
&& *ptr
!='-')
972 ip
->max
=ip
->desired
=atoi(ptr
+1);
974 ip
->min
=atoi(substring
);
977 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str
,free_min
);
983 ip
->max
=ip
->min
+ip
->keyword
->reserve_min
;
987 ip
->max
-=ip
->keyword
->reserve_max
;
990 if(ip->keyword->divide_max>1)
991 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;
992 if(ip->keyword->htb_ceil_bonus_divide>0)
993 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;
998 ip
->mark
=FIRSTIPCLASS
+1+class_count
++;
1000 if_exists(group
,groups
,group
->min
==ip
->min
)
1003 group
->desired
+=ip
->min
;
1004 ip
->group
= group
->id
;
1008 create(group
,Group
);
1010 group
->id
= groupidx
++;
1011 ip
->group
= group
->id
;
1013 if(group
->min
<8) group
->min
=8;
1014 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
1015 /* it is because class IDs are derived from min. bandwidth. - xCh */
1016 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
1019 group
->desired
=ip
->min
;
1020 insert(group
,groups
,desc_order_by
,min
);
1032 /*-----------------------------------------------------------------*/
1033 /* cll1.h - let's allocate brand new character buffer... */
1034 /*-----------------------------------------------------------------*/
1037 /*-----------------------------------------------------------------*/
1038 puts("Resolving shared connections ...");
1039 /*-----------------------------------------------------------------*/
1040 for_selected(ip
,ips
,ip
->sharing
)
1042 for_selected(sharedip
,ips
,eq(sharedip
->name
,ip
->sharing
))
1044 sharedip
->traffic
+=ip
->traffic
;
1046 ip
->mark
=sharedip
->mark
;
1050 printf("Unresolved shared connection: %s %s sharing-%s\n",ip
->addr
,ip
->name
,ip
->sharing
);
1053 if(enable_credit
&& just_flush
<9)
1055 /*-----------------------------------------------------------------*/
1056 printf("Parsing credit file %s ...\n", credit
);
1057 /*-----------------------------------------------------------------*/
1060 ptr
=parse_datafile_line(_
);
1063 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1065 sscanf(ptr
,"%Lu",&(ip
->credit
));
1074 /*-----------------------------------------------------------------*/
1075 puts("Initializing iptables and tc classes ...");
1076 /*-----------------------------------------------------------------*/
1078 iptables_file
=fopen(iptablesfile
,"w");
1079 if (iptables_file
== NULL
) {
1080 puts("Cannot open iptablesfile!");
1084 log_file
=fopen(cmdlog
,"w");
1085 if (log_file
== NULL
) {
1086 puts("Cannot open logfile!");
1090 save_line(iptablespreamble
);
1093 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
1096 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
1099 iptables_file
=fopen(iptablesfile
,"w");
1100 save_line(iptablespreamble
);
1102 if(qos_free_zone
&& *qos_free_zone
!='0')
1106 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
1111 save_line(":post_noproxy - [0:0]");
1112 sprintf(str
,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan
);
1114 sprintf(str
,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip
, lan
);
1116 sprintf(str
,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
1119 chain
="post_noproxy";
1122 chain
="POSTROUTING";
1124 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
1128 if(ip_count
>idxtable_treshold1
&& !just_flush
)
1130 int idxcount
=0, bitmask
=32-idxtable_bitmask1
; /* default net mask: 255.255.255.240 */
1132 /*-----------------------------------------------------------------*/
1133 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
1134 /*-----------------------------------------------------------------*/
1136 save_line(":post_common - [0:0]");
1137 save_line(":forw_common - [0:0]");
1139 for_selected(ip
,ips
,ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
1141 buf
=hash_id(ip
->addr
,bitmask
);
1142 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
1151 idx
->bitmask
=bitmask
;
1159 /* brutal perfomance optimalization */
1160 while(idxcount
>idxtable_treshold2
&& bitmask
>2*idxtable_bitmask2
)
1162 bitmask
-=idxtable_bitmask2
;
1165 for_selected(idx
,idxs
,idx
->parent
==NULL
)
1167 buf
=hash_id(idx
->addr
,bitmask
);
1168 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
1170 metaindex
->children
++;
1174 create(metaindex
,Index
);
1175 metaindex
->addr
=idx
->addr
;
1177 metaindex
->bitmask
=bitmask
;
1178 metaindex
->parent
=NULL
;
1179 metaindex
->children
=0;
1181 push(metaindex
,idxs
);
1183 idx
->parent
=metaindex
;
1187 /* this should slightly optimize throughout ... */
1188 sort(idx
,idxs
,desc_order_by
,children
);
1189 sort(idx
,idxs
,order_by
,bitmask
);
1195 subnet
=subnet_id(idx
->addr
,idx
->bitmask
);
1196 printf("%d: %s/%d\n",++i
,subnet
,idx
->bitmask
);
1198 sprintf(str
,":post_%s - [0:0]", idx
->id
);
1201 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
1206 string(buf
,strlen(idx
->parent
->id
)+6);
1207 sprintf(buf
,"post_%s",idx
->parent
->id
);
1212 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
1215 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
1220 string(buf
,strlen(idx
->parent
->id
)+6);
1221 sprintf(buf
,"forw_%s",idx
->parent
->id
);
1226 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
1229 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
1232 printf("Total indexed iptables chains created: %d\n", i
);
1234 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
1237 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
1245 fclose(iptables_file
);
1246 if (log_file
) fclose(log_file
);
1247 puts("Just flushed iptables and tc classes - now exiting ...");
1253 if(!dry_run
&& !nodelay
&& qos_free_delay
)
1255 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
1256 sleep(qos_free_delay
);
1259 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,lan
,htb_r2q
);
1262 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1263 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
1266 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1267 tc
,lan
,line
,line
,burst_main
,highest_priority
);
1270 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
1273 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1274 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
1277 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1278 tc
,wan
,up
,up
,burst_main
,highest_priority
);
1282 /*-----------------------------------------------------------------*/
1283 puts("Locating heavy downloaders and generating root classes ...");
1284 /*-----------------------------------------------------------------*/
1285 sort(ip
,ips
,desc_order_by
,traffic
);
1288 /*-----------------------------------------------------------------*/
1289 /* sub-scope - local variables */
1291 long long int rate
=line
;
1292 long long int max
=line
;
1294 FILE *credit_file
=NULL
;
1296 if(!just_preview
&& !dry_run
&& enable_credit
) credit_file
=fopen(credit
,"w");
1298 for_each(group
,groups
)
1303 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",
1304 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1308 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",
1309 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
1313 if(group_count
++<max_nesting
) parent
=group
->id
;
1315 rate
-=digital_divide
*group
->min
;
1316 if(rate
<group
->min
)rate
=group
->min
;
1318 /*shaping of aggresive downloaders, with credit file support */
1321 int group_rate
=group
->min
, priority_sequence
=lowest_priority
;
1323 for_selected(ip
, ips
, ip
->min
==group
->min
&& ip
->max
>ip
->min
)
1325 if( ip
->keyword
->data_limit
&& !ip
->fixedprio
&&
1326 ip
->traffic
>ip
->credit
+
1327 (ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20)) )
1329 if(group_rate
<ip
->max
) ip
->max
=group_rate
;
1330 group_rate
+=magic_treshold
;
1331 ip
->prio
=lowest_priority
;
1332 if(ip
->prio
<highest_priority
+2) ip
->prio
=highest_priority
+2;
1336 if( ip
->keyword
->data_prio
&& !ip
->fixedprio
&&
1337 ip
->traffic
>ip
->credit
+
1338 (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20)) )
1340 ip
->prio
=priority_sequence
--;
1341 if(ip
->prio
<highest_priority
+1) ip
->prio
=highest_priority
+1;
1346 unsigned long long lcredit
=0;
1348 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
1349 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
1350 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
1357 if(credit_file
)fclose(credit_file
);
1362 f
=fopen(preview
,"w");
1365 else if(!dry_run
&& !just_flush
)
1367 /*-----------------------------------------------------------------*/
1368 printf("Writing data transfer database ...\n");
1369 /*-----------------------------------------------------------------*/
1370 f
=fopen("/var/run/prometheus.previous","w");
1373 for_selected(ip
,ips
,ip
->traffic
|| ip
->direct
|| ip
->proxy
||ip
->upload
)
1374 fprintf(f
,"%s %Lu %Lu %Lu %Lu\n",ip
->addr
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
);
1388 /*-----------------------------------------------------------------*/
1389 printf("Sorting data and generating statistics page %s ...\n",ptr
);
1390 /*-----------------------------------------------------------------*/
1392 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
);
1393 fprintf(f
,"<th colspan=\"%d\">data limits</th>\n",keywordcount
);
1396 for_each(group
,groups
)
1399 printf("%d k group: %d bandwidth requested: %d k\n",group
->min
,group
->count
,group
->desired
);
1401 fprintf(f
,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count
,group
->min
);
1402 fprintf(f
,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group
->count
,group
->desired
);
1404 for_each(keyword
,keywords
)
1406 fprintf(f
,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword
->html_color
,group
->min
*keyword
->data_limit
);
1409 total
+=group
->count
;
1413 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count
,i
,i
/line
);
1415 fprintf(f
,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line
);
1416 fprintf(f
,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total
,i
);
1418 for_each(keyword
,keywords
)
1420 fprintf(f
,"<th align=\"right\">%d IPs</th>",keyword
->ip_count
);
1422 fprintf(f
,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i
/line
));
1423 fprintf(f
,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount
,total
);
1425 fputs("</table>\n",f
);
1427 else if(!dry_run
&& !just_flush
)
1433 unsigned long long total
=0, total_direct
=0, total_proxy
=0, total_upload
=0, tmp_sum
=0;
1434 int active_classes
=0;
1437 struct Sum
{unsigned long long l
; int i
; list(Sum
);} *sum
,*sums
=NULL
;
1444 fprintf(f
,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan
,title
);
1445 fprintf(f
," (%s)</th></tr>\n", d
);
1446 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\
1447 <td align=\"right\">credit</td>\
1448 <td align=\"right\">limit</td>\
1449 <td align=\"right\">total</td>\
1450 <td align=\"right\">direct</td>\n",f
);
1452 fputs("<td align=\"right\">proxy</td>\n",f
);
1453 fputs("<td align=\"right\">upload</td>\
1454 <td align=\"right\">minimum</td>\
1455 <td align=\"right\">desired</td>\
1456 <td align=\"right\">maximum</td>\
1457 <td>prio</td></tr>\n",f
);
1461 char *f1
="", *f2
="";
1462 if(ip
->max
<ip
->desired
)
1464 f1
="<font color=\"red\">";
1467 else if(ip
->prio
>highest_priority
+1)
1469 f1
="<font color=\"brown\">";
1474 printf("%03d. %-22s %10Lu (%d/%d)\n",i
,ip
->name
, ip
->traffic
, ip
->min
, ip
->max
);
1476 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",
1477 ip
->name
, i
, log_url
, ip
->name
, ip
->name
, ip
->credit
);
1478 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)));
1479 fprintf(f
,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1
, ip
->traffic
, f2
, ip
->direct
);
1481 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->proxy
);
1482 fprintf(f
,"<td align=\"right\">%Lu M</td>\n", ip
->upload
);
1483 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
);
1485 total_direct
+=ip
->direct
;
1486 total_proxy
+=ip
->proxy
;
1487 total_upload
+=ip
->upload
;
1491 tmp_sum
+=ip
->traffic
;
1494 sum
->i
=active_classes
;
1495 insert(sum
,sums
,order_by
,i
);
1502 sprintf(str
,"%s/%s.log",log_dir
,ip
->name
);
1503 iplog
=fopen(str
,"a");
1506 fprintf(iplog
,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%s",
1507 time(NULL
),ip
->name
,ip
->traffic
,ip
->direct
,ip
->proxy
,ip
->upload
,ip
->min
,ip
->max
,ip
->desired
,d
); /* d = date*/
1513 fprintf(f
,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");
1514 fprintf(f
,"<th align=\"right\">%Lu M</th>\
1515 <th align=\"right\">%Lu M</th>\n", total
, total_direct
);
1517 fprintf(f
,"<th align=\"right\">%Lu M</th>\n", total_proxy
);
1518 fprintf(f
,"<th align=\"right\">%Lu M</th>", total_upload
);
1519 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f
);
1521 if(active_classes
>10)
1523 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f
);
1524 fputs("<tr><td>Analytic category</td>\n",f
);
1525 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f
);
1527 if_exists(sum
,sums
,sum
->l
>=total
/4)
1529 fprintf(f
,"<tr><td>Top 25%% of traffic</td>\n");
1530 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
);
1533 if_exists(sum
,sums
,sum
->i
==10)
1535 fprintf(f
,"<tr><td>Top 10 downloaders</td>\n");
1536 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
);
1539 if_exists(sum
,sums
,sum
->l
>=total
/2)
1541 fprintf(f
,"<tr><td>Top 50%% of traffic</td>\n");
1542 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
);
1545 if_exists(sum
,sums
,sum
->l
>=4*total
/5)
1547 fprintf(f
,"<tr><td>Top 80%% of traffic</td>\n");
1548 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
);
1551 if_exists (sum
,sums
,sum
->i
>=(active_classes
+1)/5)
1553 fprintf(f
,"<tr><td>Top 20%% downloaders</td>\n");
1554 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
);
1557 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/4)
1559 fprintf(f
,"<tr><td>Top 25%% downloaders</td>\n");
1560 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
);
1563 if_exists(sum
,sums
,sum
->i
>=(active_classes
+1)/2)
1565 fprintf(f
,"<tr><td>Top 50%% downloaders</td>\n");
1566 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
);
1569 if_exists(sum
,sums
,sum
->i
>=4*(active_classes
+1)/5)
1571 fprintf(f
,"<tr><td>Top 80%% downloaders</td>\n");
1572 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
);
1575 fprintf(f
,"<tr><td>All users, all traffic</td>\n");
1576 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
);
1577 fputs("</table>\n", f
);
1579 fprintf(f
, stats_html_signature
, version
);
1585 puts("Statistics preview generated (-p switch) - now exiting ...");
1589 /*-----------------------------------------------------------------*/
1590 puts("Generating iptables and tc classes ...");
1591 /*-----------------------------------------------------------------*/
1594 printf("%-22s %-15s mark\n","name","ip");
1596 for_selected(ip
,ips
,ip
->mark
>0)
1602 duplicate(ip
->addr
,buf
);
1603 buf
=hash_id(ip
->addr
,32-idxtable_bitmask1
);
1605 string(chain_forward
,6+strlen(buf
));
1606 strcpy(chain_forward
,"forw_");
1607 strcat(chain_forward
,buf
);
1609 string(chain_postrouting
,6+strlen(buf
));
1610 strcpy(chain_postrouting
,"post_");
1611 strcat(chain_postrouting
,buf
);
1617 chain_forward
="FORWARD";
1618 chain_postrouting
="POSTROUTING";
1621 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1623 /* -------------------------------------------------------- mark download */
1625 sprintf(str
,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting
,ip
->addr
,lan
,mark_iptables
,ip
->mark
);
1626 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1627 /* -m limit --limit 1/s */
1632 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
);
1633 /*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);*/
1637 sprintf(str
,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting
,ip
->addr
,lan
);
1640 /* -------------------------------------------------------- mark upload */
1641 sprintf(str
,"-A %s -s %s/32 -o %s -j %s%d",chain_forward
,ip
->addr
,wan
,mark_iptables
,ip
->mark
);
1642 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1645 sprintf(str
,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward
,ip
->addr
,wan
);
1650 /* -------------------------------------------------------- download class */
1651 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1653 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
);
1656 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1658 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*/
1661 if (filter_type
== 1)
1663 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, lan
, ip
->mark
, ip
->mark
);
1667 /* -------------------------------------------------------- upload class */
1668 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1669 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1671 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1672 tc
, wan
, ip
->group
, ip
->mark
,
1673 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1674 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1677 if (strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1679 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*/
1682 if (filter_type
== 1)
1684 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",tc
, wan
, ip
->mark
, ip
->mark
);
1689 printf("(sharing %s)\n", ip
->sharing
);
1695 chain_forward
= "forw_common";
1696 chain_postrouting
= "post_common";
1700 chain_forward
= "FORWARD";
1701 chain_postrouting
= "POSTROUTING";
1703 /* -------------------------------- classify or reject free download */
1705 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
1706 if(free_min
) final_chain
= "ACCEPT";
1711 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);
1714 sprintf(str
,"-A %s -s %s -p tcp --sport %d -o %s -j %s",chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1719 sprintf(str
,"-A %s -o %s -j %s%d",chain_postrouting
,lan
,mark_iptables
,3);
1722 sprintf(str
,"-A %s -o %s -j %s",chain_postrouting
,lan
,final_chain
);
1724 /* ------------------------------- classify or reject free upload */
1727 sprintf(str
,"-A %s -o %s -j %s%d",chain_forward
,wan
,mark_iptables
,3);
1730 sprintf(str
,"-A %s -o %s -j %s",chain_forward
,wan
,final_chain
);
1734 if(free_min
) /* allocate free bandwith if it is not zero... */
1736 /*-----------------------------------------------------------------*/
1737 puts("Generating free bandwith classes ...");
1738 /*-----------------------------------------------------------------*/
1739 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1740 tc
,lan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1742 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1743 tc
,wan
,parent
,free_min
,free_max
,burst
,lowest_priority
);
1746 if (strcmpi(qos_leaf
, "none"))
1748 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,lan
,qos_leaf
);
1751 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc
,wan
,qos_leaf
);
1754 /* tc handle 1 fw flowid */
1755 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,lan
);
1758 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc
,wan
);
1761 printf("Total IP count: %d\n", i
);
1763 if (log_file
) fclose(log_file
);
1765 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1766 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 6.07728 seconds and 4 git commands to generate.