1 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2 /* Prometheus QoS - you can "steal fire" from your ISP *//* "fair-per-IP" quality of service (QoS) utility */
3 /* requires Linux 2.4.x or 2.6.x with HTB support */
4 /* Copyright(C) 2005-2013 Michael Polak, Arachne Aerospace */
5 /* iptables-restore support Copyright(C) 2007-2008 ludva */
6 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
7 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
9 /* Modified by: xChaos, 20130124
12 Prometheus QoS is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2.1 of
15 the License, or (at your option) any later version.
17 Prometheus QoS is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with Prometheus Qos; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 GNU General Public License is located in file COPYING */
28 #include "cll1-0.6.2.h"
31 const char *version
= "0.8.3-i";
33 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
34 /* Versions: 0.8.3 is development release, 0.8.4 will be "stable" */
35 /* Official Trac URL: https://dev.arachne.cz/svn/prometheus */
36 /* Official SVN URL: https://dev.arachne.cz/repos/prometheus */
37 /* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */
38 /* CZK donations account: 2900242944/2010 (transparent account) */
39 /* Warning: unofficial Github mirror is not supported by author! */
40 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
42 const char *stats_html_signature
= "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2013 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";
47 /* ======= All path names are defined here (for RPM patch) ======= */
49 const char *tc
= "/sbin/tc"; /* requires tc with HTB support */
50 const char *iptables
= "/sbin/iptables"; /* requires iptables utility */
51 const char *ip6tables
= "/sbin/ip6tables"; /* requires iptables utility */
52 const char *iptablessave
= "/sbin/iptables-save"; /* not yet required */
53 const char *iptablesrestore
= "/sbin/iptables-restore"; /* requires iptables-restore */
54 const char *ip6tablessave
= "/sbin/ip6tables-save"; /* not yet required */
55 const char *ip6tablesrestore
= "/sbin/ip6tables-restore"; /* requires iptables-restore */
56 const char *ls
= "/bin/ls"; /* this is not user configurable :-) */
58 char *config
= "/etc/prometheus/prometheus.conf"; /* main configuration file */
59 char *hosts
= "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
60 char *iptablesfile
= "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
61 char *ip6tablesfile
= "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/
62 char *credit
= "/var/lib/misc/prometheus.credit"; /* credit log file */
63 char *classmap
= "/var/lib/misc/prometheus.classes"; /* credit log file */
64 char *html
= "/var/www/traffic.html"; /* hall of fame - html version */
65 char *preview
= "/var/www/preview.html"; /* hall of fame preview - html version */
66 char *json_traffic
= "/var/www/logs/traffic.json"; /* hall of fame - json version */
67 char *json_preview
= "/var/www/logs/preview.json"; /* hall of fame preview - json version */
68 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
69 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
70 char *log_url
= "/logs/"; /* log directory relative URI prefix (partial URL) */
71 char *html_log_dir
= "/var/www/logs/html/";
73 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
74 char *lms_url
= "/lms/?m=customerinfo&id=";
75 int use_jquery_popups
= TRUE
;
76 int row_odd_even
= 0; /*<tr class="odd/even"> */
78 /* === Configuraration file values defaults - stored in global variables ==== */
80 int filter_type
= 1; /*1 mark, 2 classify*/
81 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
83 char *mark_iptables
= "MARK --set-mark ";
84 int dry_run
= FALSE
; /* preview - use puts() instead of system() */
85 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]";
86 char *ip6preamble
= "-A FORWARD -p ipv6-icmp -j ACCEPT\n-A POSTROUTING -p ipv6-icmp -j ACCEPT\n-A FORWARD -s fe80::/10 -j ACCEPT\n-A FORWARD -d ff00::/8 -j ACCEPT\n-A POSTROUTING -s fe80::/10 -j ACCEPT\n-A POSTROUTING -d ff00::/8 -j ACCEPT";
87 FILE *iptables_file
= NULL
;
88 FILE *ip6tables_file
= NULL
;
89 int enable_credit
= TRUE
; /* enable credit file */
90 int use_credit
= FALSE
; /* use credit file (if enabled)*/
91 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
92 int hall_of_fame
= TRUE
; /* enable hall of fame */
93 char *lan
= "eth0"; /* LAN interface */
94 char *lan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
95 char *wan
= "eth1"; /* WAN/ISP interface */
96 char *ip6prefix
= NULL
; /* Prefix for global /48 IPv6 subnet */
97 char *wan_medium
= "100Mbit"; /* 10Mbit/100Mbit ethernet */
98 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
99 char *qos_free_zone
= NULL
; /* QoS free zone */
100 int qos_proxy
= TRUE
; /* include proxy port to QoS */
101 int found_lmsid
= FALSE
; /* show links to users in LMS information system */
102 int include_upload
= TRUE
; /* upload+download=total traffic */
103 char *proxy_ip
= "192.168.1.1/32"; /* our IP with proxy port */
104 int proxy_port
= 3128; /* proxy port number */
105 long long int line
= 1024; /* WAN/ISP download in kbps */
106 long long int up
= 1024; /* WAN/ISP upload in kbps */
107 int free_min
= 256; /* minimum guaranted bandwidth for all undefined hosts */
108 int free_max
= 512; /* maximum allowed bandwidth for all undefined hosts */
109 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
110 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
111 int max_nesting
= 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
112 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
113 int burst
= 8; /* HTB burst (in kbits) */
115 int burst_group
= 32;
116 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
117 int keywordcount
= 0;
120 /* not yet implemented:
121 int fixed_packets = 0; maximum number of pps per IP address (not class!)
122 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
124 FILE *log_file
= NULL
;
125 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
127 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
128 const int lowest_priority
= 7; /* lowest HTB priority (HTB built-in value is 7) */
129 const int idxtable_treshold1
= 24; /* this is no longer configurable */
130 const int idxtable_treshold2
= 12; /* this is no longer configurable */
131 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
132 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
134 struct IP
*ips
= NULL
, *ip
, *sharedip
;
135 struct Group
*groups
= NULL
, *group
;
136 struct Keyword
*keyword
, *defaultkeyword
=NULL
, *keywords
=NULL
;
139 /* implemented in help.c */
141 void get_traffic_statistics(const char *whichiptables
, int ipv6
);
142 /* implemented in parseiptables.c */
144 void parse_ip_log(int argc
, char **argv
);
145 /* implemented in parselog.c */
147 void parse_hosts(char *hosts
);
148 /* implemented in parsehosts.c */
150 void write_json_traffic(char *json
);
151 /* implemented in json.c */
153 void write_htmlandlogs(char *html
, char *d
, int total
, int just_preview
);
154 /* implemented in htmlandlogs.c */
156 const char *tr_odd_even(void)
158 row_odd_even
= 1 - row_odd_even
;
161 return "<tr class=\"even\">\n";
165 return "<tr class=\"odd\">\n";
169 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
170 /* (except that this code uses obsolete, archaic version of this header file...) */
176 struct Index
*parent
;
181 } *idxs
=NULL
, *idx
, *metaindex
;
184 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
186 char *index_id(char *ip
, int bitmask
);
187 /* function implemented in ipv4subnets.c */
189 char *subnet_id(char *ip
, int bitmask
);
190 /* function implemented in ipv4subnets.c */
192 char *index6_id(char *ip
, int bitmask
);
193 /* function implemented in ipv6subnets.c */
195 char *subnet6_id(char *ip
, int bitmask
);
196 /* function implemented in ipv6subnets.c */
198 /* ================= Let's parse configuration file here ================ */
200 void reject_config_and_exit(char *filename
)
202 printf("Configuration file %s rejected - abnormal exit.",filename
);
206 void get_config(char *config_filename
)
210 printf("Configured keywords: ");
211 parse(config_filename
)
213 option("keyword",kwd
);
218 create(keyword
,Keyword
);
220 keyword
->asymetry_ratio
=1; /* ratio for ADSL-like upload */
221 keyword
->asymetry_fixed
=0; /* fixed treshold for ADSL-like upload */
222 keyword
->data_limit
=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
223 keyword
->data_prio
=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
224 keyword
->fixed_limit
=0; /* fixed data limit for setting lower HTB ceil */
225 keyword
->fixed_prio
=0; /* fixed data limit for setting lower HTB prio */
226 keyword
->reserve_min
=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
227 keyword
->reserve_max
=0; /* malus for nominal HTB ceil (in kbps) */
228 keyword
->default_prio
=highest_priority
+1;
229 keyword
->html_color
="000000";
231 keyword
->leaf_discipline
="";
233 push(keyword
,keywords
);
236 defaultkeyword
=keyword
;
244 for_each(keyword
,keywords
)
246 int l
=strlen(keyword
->key
);
248 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
250 char *tmptr
=_
; /* <---- l+1 ----> */
251 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
252 ioption("asymetry-ratio",keyword
->asymetry_ratio
);
253 ioption("asymetry-treshold",keyword
->asymetry_fixed
);
254 ioption("magic-relative-limit",keyword
->data_limit
);
255 ioption("magic-relative-prio",keyword
->data_prio
);
256 loption("magic-fixed-limit",keyword
->fixed_limit
);
257 loption("magic-fixed-prio",keyword
->fixed_prio
);
258 ioption("htb-default-prio",keyword
->default_prio
);
259 ioption("htb-rate-bonus",keyword
->reserve_min
);
260 ioption("htb-ceil-malus",keyword
->reserve_max
);
261 option("leaf-discipline",keyword
->leaf_discipline
);
262 option("html-color",keyword
->html_color
);
265 if(keyword
->data_limit
|| keyword
->fixed_limit
||
266 keyword
->data_prio
|| keyword
->fixed_prio
)
275 option("iptables",iptables
);
276 option("iptables-save",iptablessave
);
277 option("iptables-restore",iptablesrestore
);
278 option("ip6tables",ip6tables
);
279 option("ip6tables-save",ip6tablessave
);
280 option("ip6tables-restore",ip6tablesrestore
);
281 option("iptables-in-filename",iptablesfile
);
282 option("ip6tables-in-filename",ip6tablesfile
);
283 option("hosts",hosts
);
284 option("lan-interface",lan
);
285 option("wan-interface",wan
);
286 option("ip6-prefix",ip6prefix
);
287 option("lan-medium",lan_medium
);
288 option("wan-medium",wan_medium
);
289 lloption("wan-download",line
);
290 lloption("wan-upload",up
);
291 ioption("hall-of-fame-enable",hall_of_fame
);
292 option("hall-of-fame-title",title
);
293 option("hall-of-fame-filename",html
);
294 option("json-filename",json_traffic
);
295 option("hall-of-fame-preview",preview
);
296 option("json-preview",json_preview
);
297 option("log-filename",cmdlog
);
298 option("credit-filename",credit
);
299 option("classmap-filename",classmap
);
300 ioption("credit-enable",enable_credit
);
301 option("log-traffic-directory",log_dir
);
302 option("log-traffic-html-directory",html_log_dir
);
303 option("log-traffic-url-path",log_url
);
304 option("jquery-url",jquery_url
);
305 option("lms-url",lms_url
);
306 ioption("use-jquery-popups",use_jquery_popups
);
307 option("qos-free-zone",qos_free_zone
);
308 ioption("qos-free-delay",qos_free_delay
);
309 ioption("qos-proxy-enable",qos_proxy
);
310 option("qos-proxy-ip",proxy_ip
);
311 option("htb-leaf-discipline",qos_leaf
);
312 ioption("qos-proxy-port",proxy_port
);
313 ioption("free-rate",free_min
);
314 ioption("free-ceil",free_max
);
315 ioption("htb-burst",burst
);
316 ioption("htb-burst-main",burst_main
);
317 ioption("htb-burst-group",burst_group
);
318 ioption("htb-nesting-limit",max_nesting
);
319 ioption("htb-r2q",htb_r2q
);
320 ioption("magic-include-upload",include_upload
);
321 ioption("magic-treshold",magic_treshold
);
322 option("filter-type", cnf
);
323 /* not yet implemented:
324 ioption("magic-fixed-packets",fixed_packets);
325 ioption("magic-relative-packets",packet_limit);
330 perror(config_filename
);
331 puts("Warning - using built-in defaults instead ...");
333 done
; /* ugly macro end */
336 /* leaf discipline for keywords */
337 for_each(keyword
,keywords
)
339 if(!strcmpi(keyword
->leaf_discipline
, ""))
341 keyword
->leaf_discipline
= qos_leaf
;
345 if(strcmpi(cnf
, "mark"))
349 mark_iptables
= "CLASSIFY --set-class 1:";
355 mark_iptables
= "MARK --set-mark ";
358 /* are supplied values meaningful ?*/
361 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
362 reject_config_and_exit(config_filename
);
367 /* ========== This function executes, logs OR ALSO prints command ========== */
369 void safe_run(char *cmd
)
373 printf("\n=>%s\n",cmd
);
381 fprintf(log_file
,"%s\n",cmd
);
385 void iptables_save_line(char *line
, int ipv6
)
389 fprintf(ip6tables_file
,"%s\n",line
);
393 fprintf(iptables_file
,"%s\n",line
);
397 void run_iptables_restore(void)
400 string(restor
,STRLEN
);
402 /*-----------------------------------------------------------------*/
403 printf("Running %s <%s ...\n", iptablesrestore
, iptablesfile
);
404 /*-----------------------------------------------------------------*/
406 iptables_save_line("COMMIT", FALSE
);
407 fclose(iptables_file
);
414 done
; /* ugly macro end */
417 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
422 /*-----------------------------------------------------------------*/
423 printf("Running %s <%s ...\n", ip6tablesrestore
, ip6tablesfile
);
424 /*-----------------------------------------------------------------*/
425 iptables_save_line("COMMIT", TRUE
);
426 fclose(ip6tables_file
);
433 done
; /* ugly macro end */
435 sprintf(restor
,"%s <%s",ip6tablesrestore
, ip6tablesfile
);
441 char *parse_datafile_line(char *str
)
443 char *ptr
=strchr(str
,' ');
458 /*-----------------------------------------------------------------*/
459 /* Are you looking for int main(int argc, char **argv) ? :-)) */
460 /*-----------------------------------------------------------------*/
464 int i
=0; /* just plain old Fortran style integer :-) */
465 FILE *f
=NULL
; /* everything is just stream of bytes... */
466 char *str
, *ptr
, *d
; /* LET A$=B$ :-) */
470 int just_flush
= FALSE
; /* deactivates all previous actions */
472 int just_preview
= FALSE
; /* preview - generate just stats */
473 int start_shaping
= FALSE
; /* apply FUP - requires classmap file */
474 int just_logs
= FALSE
; /* just parse logs */
478 char *chain_forward
, *chain_postrouting
;
482 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
483 Version %s - Copyright (C)2005-2013 Michael Polak, Arachne Labs\n\
484 iptables-restore & burst tunning & classify modification by Ludva\n\
485 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
487 /*----- Boring... we have to check command line options first: ----*/
490 argument("-c") { nextargument(config
); }
491 argument("-h") { nextargument(althosts
);}
492 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
493 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
494 argument("-9") { run
=TRUE
; just_flush
=9; }
495 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
496 argument("-s") { run
=TRUE
; just_preview
=TRUE
; start_shaping
=TRUE
; }
497 argument("-r") { run
=TRUE
; }
498 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
499 argument("-l") { just_logs
=TRUE
; }
500 argument("-m") { just_logs
=TRUE
; }
501 argument("-y") { just_logs
=TRUE
; }
502 argument("-?") { help(); exit(0); }
503 argument("--help") { help(); exit(0); }
504 argument("-v") { exit(0); }
505 argument("--version") { exit(0); }
510 puts("*** THIS IS JUST DRY RUN ! ***\n");
513 date(d
); /* this is typical cll1.h macro - prints current date */
515 /*-----------------------------------------------------------------*/
516 printf("Parsing configuration file %s ...\n", config
);
517 /*-----------------------------------------------------------------*/
522 parse_ip_log(argc
,argv
);
538 /*-----------------------------------------------------------------*/
539 puts("Parsing iptables verbose output ...");
540 /*-----------------------------------------------------------------*/
541 get_traffic_statistics(iptables
, FALSE
);
544 /*-----------------------------------------------------------------*/
545 puts("Parsing ip6tables verbose output ...");
546 /*-----------------------------------------------------------------*/
547 get_traffic_statistics(ip6tables
, TRUE
);
551 /*-----------------------------------------------------------------*/
552 printf("Parsing class defintion file %s ...\n", hosts
);
553 /*-----------------------------------------------------------------*/
556 /*-----------------------------------------------------------------*/
557 /* cll1.h - let's allocate brand new character buffer... */
558 /*-----------------------------------------------------------------*/
561 /*-----------------------------------------------------------------*/
562 puts("Resolving shared connections ...");
563 /*-----------------------------------------------------------------*/
564 for_each(ip
,ips
) if(ip
->sharing
)
566 for_each(sharedip
,ips
) if(eq(sharedip
->name
,ip
->sharing
))
568 sharedip
->traffic
+=ip
->traffic
;
570 ip
->mark
=sharedip
->mark
;
571 ip
->lmsid
=sharedip
->lmsid
;
576 printf("Unresolved shared connection: %s %s sharing-%s\n",
577 ip
->addr
, ip
->name
, ip
->sharing
);
581 if(enable_credit
&& just_flush
<9)
583 /*-----------------------------------------------------------------*/
584 printf("Parsing credit file %s ...\n", credit
);
585 /*-----------------------------------------------------------------*/
588 ptr
=parse_datafile_line(_
);
591 if_exists(ip
,ips
,eq(ip
->addr
,_
))
593 sscanf(ptr
,"%Lu",&(ip
->credit
));
597 done
; /* ugly macro end */
602 /*-----------------------------------------------------------------*/
603 puts("Initializing iptables and tc classes ...");
604 /*-----------------------------------------------------------------*/
606 iptables_file
= fopen(iptablesfile
, "w");
607 if(iptables_file
== NULL
)
609 perror(iptablesfile
);
612 iptables_save_line(iptablespreamble
, FALSE
);
616 ip6tables_file
= fopen(ip6tablesfile
, "w");
617 if(ip6tables_file
== NULL
)
619 perror(ip6tablesfile
);
622 iptables_save_line(iptablespreamble
, TRUE
);
623 iptables_save_line(ip6preamble
, TRUE
);
626 run_iptables_restore();
628 log_file
= fopen(cmdlog
, "w");
636 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,lan
);
639 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null",tc
,wan
);
642 iptables_file
=fopen(iptablesfile
,"w");
643 iptables_save_line(iptablespreamble
, FALSE
);
646 ip6tables_file
=fopen(ip6tablesfile
,"w");
647 iptables_save_line(iptablespreamble
, TRUE
);
648 iptables_save_line(ip6preamble
, TRUE
);
651 if(qos_free_zone
&& *qos_free_zone
!='0') /* this is currently supported only for IPv4 */
655 sprintf(str
,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone
, wan
);
656 iptables_save_line(str
, FALSE
); /* this is currently supported only for IPv4 */
660 iptables_save_line(":post_noproxy - [0:0]", FALSE
);
661 sprintf(str
,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan
);
662 iptables_save_line(str
, FALSE
);
663 sprintf(str
,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip
, lan
);
664 iptables_save_line(str
, FALSE
);
665 sprintf(str
,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip
, proxy_port
, lan
);
666 iptables_save_line(str
, FALSE
);
668 chain
="post_noproxy";
675 sprintf(str
,"-A %s -s %s -o %s -j ACCEPT", chain
, qos_free_zone
, lan
);
676 iptables_save_line(str
, FALSE
);
679 if(ip_count
> idxtable_treshold1
&& !just_flush
)
681 int idxcount
=0, bitmask
=32-idxtable_bitmask1
;
683 /*-----------------------------------------------------------------*/
684 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
685 /*-----------------------------------------------------------------*/
687 iptables_save_line(":post_common - [0:0]", FALSE
);
688 iptables_save_line(":forw_common - [0:0]", FALSE
);
691 iptables_save_line(":post_common - [0:0]", TRUE
);
692 iptables_save_line(":forw_common - [0:0]", TRUE
);
695 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
699 buf
=index6_id(ip
->addr
,bitmask
+32);
703 buf
=index_id(ip
->addr
, bitmask
);
706 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
713 idx
->addr
= ip
->addr
;
715 idx
->bitmask
= bitmask
+32*ip
->v6
;
724 /* brutal perfomance optimalization */
725 while(idxcount
> idxtable_treshold2
&& bitmask
> 2*idxtable_bitmask2
)
727 bitmask
-= idxtable_bitmask2
;
730 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
734 buf
= index6_id(idx
->addr
, bitmask
+32);
738 buf
= index_id(idx
->addr
, bitmask
);
740 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
742 metaindex
->children
++;
746 create(metaindex
,Index
);
747 metaindex
->addr
= idx
->addr
;
749 metaindex
->bitmask
= bitmask
+32*idx
->ipv6
;
750 metaindex
->parent
= NULL
;
751 metaindex
->children
= 0;
752 metaindex
->ipv6
= idx
->ipv6
;
754 push(metaindex
,idxs
);
756 idx
->parent
=metaindex
;
760 /* this should slightly optimize throughput ... */
761 sort(idx
,idxs
,desc_order_by
,children
);
762 sort(idx
,idxs
,order_by
,bitmask
);
769 subnet
=subnet6_id(idx
->addr
, idx
->bitmask
);
773 subnet
=subnet_id(idx
->addr
, idx
->bitmask
);
775 printf("%d: %s/%d\n", ++i
, subnet
, idx
->bitmask
);
777 sprintf(str
,":post_%s - [0:0]", idx
->id
);
778 iptables_save_line(str
, idx
->ipv6
);
780 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
781 iptables_save_line(str
, idx
->ipv6
);
785 string(buf
,strlen(idx
->parent
->id
)+6);
786 sprintf(buf
,"post_%s", idx
->parent
->id
);
793 sprintf(str
,"-A %s -d %s/%d -o %s -j post_%s", buf
, subnet
, idx
->bitmask
, lan
, idx
->id
);
794 iptables_save_line(str
, idx
->ipv6
);
796 sprintf(str
,"-A %s -d %s/%d -o %s -j post_common", buf
, subnet
, idx
->bitmask
, lan
);
797 iptables_save_line(str
, idx
->ipv6
);
801 string(buf
,strlen(idx
->parent
->id
)+6);
802 sprintf(buf
,"forw_%s",idx
->parent
->id
);
809 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_%s", buf
, subnet
, idx
->bitmask
, wan
, idx
->id
);
810 iptables_save_line(str
, idx
->ipv6
);
812 sprintf(str
,"-A %s -s %s/%d -o %s -j forw_common", buf
, subnet
, idx
->bitmask
, wan
);
813 iptables_save_line(str
, idx
->ipv6
);
815 printf("Total indexed iptables chains created: %d\n", i
);
817 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
818 iptables_save_line(str
, FALSE
);
820 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
821 iptables_save_line(str
, FALSE
);
825 sprintf(str
,"-A FORWARD -o %s -j forw_common", wan
);
826 iptables_save_line(str
, TRUE
);
828 sprintf(str
,"-A POSTROUTING -o %s -j post_common", lan
);
829 iptables_save_line(str
, TRUE
);
836 fclose(iptables_file
);
841 puts("Just flushed iptables and tc classes - now exiting ...");
847 if(!dry_run
&& !nodelay
&& qos_free_delay
)
849 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay
);
850 sleep(qos_free_delay
);
853 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
857 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
858 tc
,lan
,lan_medium
,lan_medium
,burst_main
,highest_priority
);
861 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
862 tc
,lan
,line
,line
,burst_main
,highest_priority
);
865 sprintf(str
,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc
,wan
,htb_r2q
);
868 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
869 tc
,wan
,wan_medium
,wan_medium
,burst_main
,highest_priority
);
872 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
873 tc
,wan
,up
,up
,burst_main
,highest_priority
);
877 /*-----------------------------------------------------------------*/
878 puts("Locating heavy downloaders and generating root classes ...");
879 /*-----------------------------------------------------------------*/
880 sort(ip
,ips
,desc_order_by
,traffic
);
882 /*-----------------------------------------------------------------*/
883 /* sub-scope - local variables */
885 long long int rate
= line
;
886 long long int max
= line
;
888 FILE *credit_file
= NULL
;
890 if(!just_preview
&& !dry_run
&& enable_credit
)
892 credit_file
= fopen(credit
,"w");
895 for_each(group
,groups
)
900 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",
901 tc
, lan
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
905 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",
906 tc
, wan
, parent
, group
->id
, rate
*up
/line
, max
*up
/line
, burst_group
, highest_priority
+1, group
->desired
);
910 if(group_count
++ < max_nesting
)
915 rate
-= digital_divide
*group
->min
;
916 if(rate
< group
->min
)
921 /*shaping of aggresive downloaders, with credit file support */
924 int group_rate
= group
->min
, priority_sequence
= lowest_priority
;
926 for_each(ip
, ips
) if(ip
->min
== group
->min
&& ip
->max
> ip
->min
)
928 ip
->realquota
=ip
->credit
+(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20));
929 if( ip
->keyword
->data_limit
930 and not ip
->fixedprio
931 and ip
->traffic
> ip
->realquota
)
933 if(group_rate
< ip
->max
)
935 ip
->max
= group_rate
;
937 group_rate
+=magic_treshold
;
938 ip
->prio
=lowest_priority
;
939 if(ip
->prio
<highest_priority
+2)
941 ip
->prio
=highest_priority
+2;
946 if( ip
->keyword
->data_prio
948 && ( ip
->traffic
>ip
->credit
949 + (ip
->min
*ip
->keyword
->data_prio
+(ip
->keyword
->fixed_prio
<<20))) )
951 ip
->prio
=priority_sequence
--;
952 if(ip
->prio
<highest_priority
+1)
954 ip
->prio
=highest_priority
+1;
960 unsigned long long lcredit
=0;
962 if((ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))>ip
->traffic
)
964 lcredit
=(ip
->min
*ip
->keyword
->data_limit
+(ip
->keyword
->fixed_limit
<<20))-ip
->traffic
;
966 fprintf(credit_file
,"%s %Lu\n",ip
->addr
,lcredit
);
982 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap
);
990 if_exists(ip
,ips
,eq(ip
->addr
,_
))
993 if(ip
->max
< ip
->desired
) /* apply FUP limit immediately.... */
995 printf("Applying limit for %-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
996 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
997 sprintf(str
, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
998 tc
, lan
, ip
->group
, ip
->mark
,ip
->min
,ip
->max
, burst
, ip
->prio
);
1000 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1001 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1002 sprintf(str
,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1003 tc
, wan
, ip
->group
, ip
->mark
,
1004 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1005 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1014 puts("Warning - classmap file not fund, just generating preview ...");
1015 start_shaping
=FALSE
;
1017 done
; /* ugly macro end */
1020 json_traffic
=json_preview
;
1023 if(!dry_run
&& !just_flush
)
1025 /*-----------------------------------------------------------------*/
1026 printf("Writing json traffic overview %s ... ", json_traffic
);
1027 /*-----------------------------------------------------------------*/
1028 write_json_traffic(json_traffic
);
1030 /*-----------------------------------------------------------------*/
1031 printf("Writing statistics into HTML page %s ...\n", html
);
1032 /*-----------------------------------------------------------------*/
1033 write_htmlandlogs(html
, d
, total
, just_preview
);
1043 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar
);
1049 printf("%-22s %-15s mark\n","name","ip");
1052 printf("Writing %s", classmap
);
1053 f
= fopen(classmap
, "w");
1059 /*-----------------------------------------------------------------*/
1060 printf(" + generating iptables and tc classes ... ");
1061 /*-----------------------------------------------------------------*/
1063 for_each(ip
, ips
) if(ip
->mark
> 0) /* works only for IPv4 so far */
1068 duplicate(ip
->addr
,buf
);
1071 buf
=index6_id(ip
->addr
,64-idxtable_bitmask1
);
1075 buf
=index_id(ip
->addr
,32-idxtable_bitmask1
);
1078 string(chain_forward
,6+strlen(buf
));
1079 strcpy(chain_forward
,"forw_");
1080 strcat(chain_forward
,buf
);
1082 string(chain_postrouting
,6+strlen(buf
));
1083 strcpy(chain_postrouting
,"post_");
1084 strcat(chain_postrouting
,buf
);
1090 chain_forward
="FORWARD";
1091 chain_postrouting
="POSTROUTING";
1095 printf("%-22s %-16s %04d ", ip
->name
, ip
->addr
, ip
->mark
);
1098 /* -------------------------------------------------------- mark download */
1100 sprintf(str
, "-A %s -d %s/%d -o %s -j %s%d",
1101 chain_postrouting
, ip
->addr
, 32*(1+ip
->v6
), lan
, mark_iptables
, ip
->mark
);
1102 /* -m limit --limit 1/s */
1103 iptables_save_line(str
, ip
->v6
);
1107 sprintf(str
, "-A %s -s %s -p tcp --sport %d -d %s/%d -o %s -j %s%d",
1108 chain_postrouting
, proxy_ip
, proxy_port
, ip
->addr
, 32*(1+ip
->v6
), lan
, mark_iptables
, ip
->mark
);
1109 iptables_save_line(str
, ip
->v6
);
1112 sprintf(str
, "-A %s -d %s/%d -o %s -j ACCEPT",
1113 chain_postrouting
, ip
->addr
, 32*(1+ip
->v6
), lan
);
1114 iptables_save_line(str
, ip
->v6
);
1116 /* -------------------------------------------------------- mark upload */
1117 sprintf(str
, "-A %s -s %s/%d -o %s -j %s%d",
1118 chain_forward
, ip
->addr
, 32*(1+ip
->v6
), wan
, mark_iptables
, ip
->mark
);
1119 iptables_save_line(str
, ip
->v6
);
1121 sprintf(str
, "-A %s -s %s/%d -o %s -j ACCEPT",
1122 chain_forward
, ip
->addr
, 32*(1+ip
->v6
), wan
);
1123 iptables_save_line(str
, ip
->v6
);
1127 /* -------------------------------------------------------- download class */
1129 printf("(down: %dk-%dk ", ip
->min
, ip
->max
);
1132 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1133 tc
, lan
, ip
->group
, ip
->mark
,ip
->min
,ip
->max
, burst
, ip
->prio
);
1136 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1138 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
1139 tc
, lan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
1143 if(filter_type
== 1)
1145 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1146 tc
, lan
, ip
->mark
, ip
->mark
);
1150 /* -------------------------------------------------------- upload class */
1152 printf("up: %dk-%dk)\n", (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1153 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1156 sprintf(str
,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1157 tc
, wan
, ip
->group
, ip
->mark
,
1158 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1159 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1162 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1164 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
1165 tc
, wan
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
1169 if(filter_type
== 1)
1171 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1172 tc
, wan
, ip
->mark
, ip
->mark
);
1178 fprintf(f
, "%s %d\n", ip
->addr
, ip
->mark
);
1184 printf("(sharing %s)\n", ip
->sharing
);
1197 chain_forward
= "forw_common";
1198 chain_postrouting
= "post_common";
1202 chain_forward
= "FORWARD";
1203 chain_postrouting
= "POSTROUTING";
1208 final_chain
= "ACCEPT";
1215 sprintf(str
, "-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
1216 chain_postrouting
,proxy_ip
,proxy_port
,lan
,mark_iptables
, 3);
1217 iptables_save_line(str
, FALSE
); /* only for IPv4 */
1219 sprintf(str
, "-A %s -s %s -p tcp --sport %d -o %s -j %s",
1220 chain_postrouting
,proxy_ip
,proxy_port
,lan
,final_chain
);
1221 iptables_save_line(str
, FALSE
); /* only for IPv4 */
1226 sprintf(str
, "-A %s -o %s -j %s%d",
1227 chain_postrouting
, lan
, mark_iptables
, 3);
1228 iptables_save_line(str
, FALSE
); /* only for IPv4 */
1231 sprintf(str
,"-A %s -o %s -j %s", chain_postrouting
, lan
, final_chain
);
1232 iptables_save_line(str
, FALSE
);
1235 sprintf(str
,"-A %s -o %s -j %s", chain_postrouting
, lan
, final_chain
);
1236 iptables_save_line(str
, TRUE
);
1241 sprintf(str
,"-A %s -o %s -j %s%d", chain_forward
, wan
, mark_iptables
, 3);
1242 iptables_save_line(str
, FALSE
); /* only for IPv4 */
1245 sprintf(str
,"-A %s -o %s -j %s", chain_forward
, wan
, final_chain
);
1246 iptables_save_line(str
, FALSE
);
1249 sprintf(str
,"-A %s -o %s -j %s", chain_postrouting
, lan
, final_chain
);
1250 iptables_save_line(str
, TRUE
);
1253 if(free_min
) /* allocate free bandwith if it is not zero... */
1255 /*-----------------------------------------------------------------*/
1256 puts("Generating free bandwith classes ...");
1257 /*-----------------------------------------------------------------*/
1258 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1259 tc
, lan
, parent
, free_min
, free_max
,burst
, lowest_priority
);
1261 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1262 tc
, wan
, parent
, free_min
, free_max
, burst
, lowest_priority
);
1265 if(strcmpi(qos_leaf
, "none"))
1267 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, lan
, qos_leaf
);
1270 sprintf(str
,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc
, wan
, qos_leaf
);
1273 /* tc handle 1 fw flowid */
1274 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, lan
);
1277 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc
, wan
);
1280 printf("Total IP count: %d\n", i
);
1281 run_iptables_restore();
1287 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1288 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.080022 seconds and 4 git commands to generate.