474d5cd76a711ac3842f893fa8cf7ea243d1aadb
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-2019 Michael Polak, Arachne Aerospace */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
10 /* Modified by: xChaos, 20190912
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 */
29 #include "cll1-0.6.2.h"
32 const char *version
= "0.9.0-c";
34 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
35 /* Versions: 0.9.0 is development release, 1.0 will be "stable" */
36 /* Official Trac URL: https://dev.arachne.cz/svn/prometheus */
37 /* Official SVN URL: https://dev.arachne.cz/repos/prometheus */
38 /* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */
39 /* CZK donations account: 2900242944/2010 (transparent account) */
40 /* Warning: unofficial Github mirror is not supported by author! */
41 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
43 const char *stats_html_signature
= "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2019 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";
48 /* ======= All path names are defined here (for RPM patch) ======= */
50 const char *tc
= "/sbin/tc"; /* requires tc with HTB support */
51 const char *iptables
= "/sbin/iptables"; /* requires iptables utility */
52 const char *ip6tables
= "/sbin/ip6tables"; /* requires iptables utility */
53 const char *iptablessave
= "/sbin/iptables-save"; /* not yet required */
54 const char *iptablesrestore
= "/sbin/iptables-restore"; /* requires iptables-restore */
55 const char *ip6tablessave
= "/sbin/ip6tables-save"; /* not yet required */
56 const char *ip6tablesrestore
= "/sbin/ip6tables-restore"; /* requires iptables-restore */
57 const char *ls
= "/bin/ls"; /* this is not user configurable :-) */
59 char *config
= "/etc/prometheus/prometheus.conf"; /* main configuration file */
60 char *hosts
= "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
61 char *macrosfile
= "/etc/prometheus/prometheus.macros"; /* rewrite rules for most common tariffs */
62 char *upstreamfile
= "/etc/prometheus/upstream.interfaces"; /* list of interfaces to manage */
63 char *downstreamfile
= "/etc/prometheus/downstream.interfaces"; /* list of interfaces to manage */
64 char *qosfreefile
= "/etc/prometheus/qosfree.interfaces"; /* list of interfaces to manage */
65 char *iptablesfile
= "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
66 char *ip6tablesfile
= "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/
67 char *credit
= "/var/lib/misc/prometheus.credit"; /* credit log file */
68 char *classmap
= "/var/lib/misc/prometheus.classes"; /* credit log file */
69 char *html
= "/var/www/traffic.html"; /* hall of fame - html version */
70 char *preview
= "/var/www/preview.html"; /* hall of fame preview - html version */
71 char *json_traffic
= "/var/www/logs/traffic.json"; /* hall of fame - json version */
72 char *json_preview
= "/var/www/logs/preview.json"; /* hall of fame preview - json version */
73 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
74 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
75 char *log_url
= "/logs/"; /* log directory relative URI prefix (partial URL) */
76 char *html_log_dir
= "/var/www/logs/html/";
78 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
79 char *lms_url
= "/lms/?m=customerinfo&id=";
80 int use_jquery_popups
= TRUE
;
81 int row_odd_even
= 0; /*<tr class="odd/even"> */
83 /* === Configuraration file values defaults - stored in global variables ==== */
85 int filter_type
= 1; /*1 mark, 2 classify*/
86 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
88 char *mark_iptables
= "MARK --set-mark ";
89 int dry_run
= FALSE
; /* preview - use puts() instead of system() */
90 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]";
91 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";
92 FILE *iptables_file
= NULL
;
93 FILE *ip6tables_file
= NULL
;
94 int enable_credit
= TRUE
; /* enable credit file */
95 int use_credit
= FALSE
; /* use credit file (if enabled)*/
96 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
97 int hall_of_fame
= TRUE
; /* enable hall of fame */
98 char *medium
= "1000Mbit"; /* 10Mbit/100Mbit ethernet */
99 //obsolete: char *lan = "eth0"; /* LAN interface */
100 //obsolete: char *lan_medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */
101 char *ip6prefix
= NULL
; /* Prefix for global /48 IPv6 subnet */
102 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
103 char *qos_free_zone
= NULL
; /* QoS free zone */
104 char *qos_free_dst_ipset
= NULL
; /* QoS free zone - dst match ipset name, must be prepared outside prometheus */
105 char *qos_free_src_ipset
= NULL
; /* QoS free zone - src match ipset name, must be prepared outside prometheus */
106 /* int qos_proxy = TRUE; include proxy port to QoS */
107 int found_lmsid
= FALSE
; /* show links to users in LMS information system */
108 int include_upload
= TRUE
; /* upload+download=total traffic */
109 /* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */
110 /* int proxy_port = 3128; proxy port number */
111 //obsolete: long long int line = 1024; /* WAN/ISP download in kbps */
112 //obsolete: long long int up = 1024; /* WAN/ISP upload in kbps */
113 int free_min
= 256; /* minimum guaranted bandwidth for all undefined hosts */
114 int free_max
= 512; /* maximum allowed bandwidth for all undefined hosts */
115 int overlimit_min
= 256; /* minimum guaranted bandwidth for all undefined hosts */
116 int overlimit_max
= 512; /* maximum allowed bandwidth for all undefined hosts */
117 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
118 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
119 int max_nesting
= 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */
120 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
121 int burst
= 8; /* HTB burst (in kbits) */
123 int burst_group
= 32;
124 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
125 int keywordcount
= 0;
128 FILE *log_file
= NULL
;
129 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
131 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
132 const int lowest_priority
= 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */
133 const int idxtable_treshold1
= 24; /* this is no longer configurable */
134 const int idxtable_treshold2
= 12; /* this is no longer configurable */
135 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
136 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
138 struct IP
*ips
= NULL
, *networks
= NULL
, *ip
, *sharedip
;
139 struct Group
*groups
= NULL
, *group
;
140 struct Keyword
*keyword
, *defaultkeyword
=NULL
, *keywords
= NULL
;
141 struct Macro
*macro
, *macros
= NULL
;
142 struct Index
*idxs
= NULL
, *idx
, *metaindex
;
143 struct Interface
*interfaces
= NULL
, *interface
;
144 struct QosFreeInterface
*qosfreeinterfaces
= NULL
, *qosfreeinterface
;
147 #define OVERLIMIT_CLASS 4
150 /* implemented in help.c */
152 void get_traffic_statistics(const char *whichiptables
, int ipv6
);
153 /* implemented in parseiptables.c */
155 void parse_ip_log(int argc
, char **argv
);
156 /* implemented in parselog.c */
158 void parse_hosts(char *hosts
);
159 /* implemented in parsehosts.c */
161 void write_json_traffic(char *json
);
162 /* implemented in json.c */
164 void write_htmlandlogs(char *html
, char *d
, int total
, int just_preview
);
165 /* implemented in htmlandlogs.c */
167 void analyse_topology(char *traceroute
);
168 /* implemented in networks.c */
170 char *parse_datafile_line(char *str
);
171 /* implemented in utils.c */
173 time_t get_mtime(const char *path
);
174 /* implemented in utils.c */
176 const char *tr_odd_even(void)
178 row_odd_even
= 1 - row_odd_even
;
181 return "<tr class=\"even\">\n";
185 return "<tr class=\"odd\">\n";
190 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
192 char *index_id(char *ip
, int bitmask
);
193 /* function implemented in ipv4subnets.c */
195 char *subnet_id(char *ip
, int bitmask
);
196 /* function implemented in ipv4subnets.c */
198 char *index6_id(char *ip
, int bitmask
);
199 /* function implemented in ipv6subnets.c */
201 char *subnet6_id(char *ip
, int bitmask
);
202 /* function implemented in ipv6subnets.c */
204 /* ================= Let's parse configuration file here ================ */
206 void reject_config_and_exit(char *filename
)
208 printf("Configuration file %s rejected - abnormal exit.",filename
);
212 void get_config(char *config_filename
)
216 printf("Configured keywords: ");
217 parse(config_filename
)
219 option("keyword",kwd
);
224 create(keyword
,Keyword
);
226 keyword
->asymetry_ratio
= 1; /* ratio for ADSL-like upload */
227 keyword
->asymetry_fixed
= 0; /* fixed treshold for ADSL-like upload */
228 keyword
->data_limit
= 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
229 keyword
->data_prio
= 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
230 keyword
->fixed_limit
= 0; /* fixed data limit for setting lower HTB ceil */
231 keyword
->fixed_prio
= 0; /* fixed data limit for setting lower HTB prio */
232 keyword
->reserve_min
= 8; /* bonus for nominal HTB rate bandwidth (in kbps) */
233 keyword
->reserve_max
= 0; /* malus for nominal HTB ceil (in kbps) */
234 keyword
->default_prio
= highest_priority
+1;
235 keyword
->download_aggregation
= keyword
->upload_aggregation
= 0; /* disable by default */
236 keyword
->html_color
= "000000";
237 keyword
->ip_count
= 0;
238 keyword
->leaf_discipline
= "";
239 keyword
->allowed_avgmtu
= 0;
241 push(keyword
, keywords
);
244 defaultkeyword
= keyword
;
252 for_each(keyword
,keywords
)
254 int l
=strlen(keyword
->key
);
256 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
258 char *tmptr
=_
; /* <---- l+1 ----> */
259 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
260 foption("asymetry-ratio", keyword
->asymetry_ratio
);
261 ioption("asymetry-treshold", keyword
->asymetry_fixed
);
262 ioption("magic-relative-limit", keyword
->data_limit
);
263 ioption("magic-relative-prio", keyword
->data_prio
);
264 loption("magic-fixed-limit", keyword
->fixed_limit
);
265 loption("magic-fixed-prio", keyword
->fixed_prio
);
266 ioption("htb-default-prio", keyword
->default_prio
);
267 ioption("htb-rate-bonus", keyword
->reserve_min
);
268 ioption("htb-ceil-malus", keyword
->reserve_max
);
269 ioption("download-aggregation", keyword
->download_aggregation
);
270 ioption("upload-aggregation", keyword
->upload_aggregation
);
271 option("leaf-discipline", keyword
->leaf_discipline
);
272 option("html-color", keyword
->html_color
);
273 ioption("allowed-avgmtu" ,keyword
->allowed_avgmtu
);
276 if(keyword
->data_limit
|| keyword
->fixed_limit
||
277 keyword
->data_prio
|| keyword
->fixed_prio
)
286 option("iptables",iptables
);
287 option("iptables-save",iptablessave
);
288 option("iptables-restore",iptablesrestore
);
289 option("ip6tables",ip6tables
);
290 option("ip6tables-save",ip6tablessave
);
291 option("ip6tables-restore",ip6tablesrestore
);
292 option("iptables-in-filename",iptablesfile
);
293 option("ip6tables-in-filename",ip6tablesfile
);
294 option("hosts",hosts
);
295 option("downstream-interfaces-list-filename",downstreamfile
);
296 option("upstream-interfaces-list-filename",upstreamfile
);
297 option("qos-free-interfaces-list-filename",qosfreefile
);
298 option("macros-filename",macrosfile
);
299 option("ip6-prefix",ip6prefix
);
300 option("medium",medium
);
301 ioption("hall-of-fame-enable",hall_of_fame
);
302 ioption("digital-divide-weirdness-ratio",digital_divide
);
303 option("hall-of-fame-title",title
);
304 option("hall-of-fame-filename",html
);
305 option("json-filename",json_traffic
);
306 option("hall-of-fame-preview",preview
);
307 option("json-preview",json_preview
);
308 option("log-filename",cmdlog
);
309 option("credit-filename",credit
);
310 option("classmap-filename",classmap
);
311 ioption("credit-enable",enable_credit
);
312 option("log-traffic-directory",log_dir
);
313 option("log-traffic-html-directory",html_log_dir
);
314 option("log-traffic-url-path",log_url
);
315 option("jquery-url",jquery_url
);
316 option("lms-url",lms_url
);
317 ioption("use-jquery-popups",use_jquery_popups
);
318 option("qos-free-zone",qos_free_zone
);
319 option("qos-free-dst-ipset",qos_free_dst_ipset
);
320 option("qos-free-src-ipset",qos_free_src_ipset
);
321 ioption("qos-free-delay",qos_free_delay
);
322 /* ioption("qos-proxy-enable",qos_proxy); */
323 /* option("qos-proxy-ip",proxy_ip);*/
324 option("htb-leaf-discipline",qos_leaf
);
325 /* ioption("qos-proxy-port",proxy_port); */
326 ioption("free-rate",free_min
);
327 ioption("free-ceil",free_max
);
328 ioption("overlimit-rate",overlimit_min
);
329 ioption("overlimit-ceil",overlimit_max
);
330 ioption("htb-burst",burst
);
331 ioption("htb-burst-main",burst_main
);
332 ioption("htb-burst-group",burst_group
);
333 ioption("htb-nesting-limit",max_nesting
);
334 ioption("htb-r2q",htb_r2q
);
335 ioption("magic-include-upload",include_upload
);
336 ioption("magic-treshold",magic_treshold
);
337 option("filter-type", cnf
);
338 /* not yet implemented:
339 ioption("magic-fixed-packets",fixed_packets);
340 ioption("magic-relative-packets",packet_limit);
345 perror(config_filename
);
346 puts("Warning - using built-in defaults instead ...");
348 done
; /* ugly macro end */
351 /* leaf discipline for keywords */
352 for_each(keyword
,keywords
)
354 if(!strcmpi(keyword
->leaf_discipline
, ""))
356 keyword
->leaf_discipline
= qos_leaf
;
360 if(strcmpi(cnf
, "mark"))
364 mark_iptables
= "CLASSIFY --set-class 1:";
370 mark_iptables
= "MARK --set-mark ";
375 /* ========== This function executes, logs OR ALSO prints command ========== */
377 void safe_run(char *cmd
)
381 printf("\n=>%s\n",cmd
);
389 fprintf(log_file
,"%s\n",cmd
);
393 void iptables_save_line(char *line
, int ipv6
)
397 fprintf(ip6tables_file
,"%s\n",line
);
401 fprintf(iptables_file
,"%s\n",line
);
409 void run_iptables_restore(void)
412 string(restor
, STRLEN
);
414 /*-----------------------------------------------------------------*/
415 printf("Running %s <%s ...\n", iptablesrestore
, iptablesfile
);
416 /*-----------------------------------------------------------------*/
418 iptables_save_line("COMMIT", IPv4
);
419 fclose(iptables_file
);
426 done
; /* ugly macro end */
429 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
434 /*-----------------------------------------------------------------*/
435 printf("Running %s <%s ...\n", ip6tablesrestore
, ip6tablesfile
);
436 /*-----------------------------------------------------------------*/
437 iptables_save_line("COMMIT", IPv6
);
438 fclose(ip6tables_file
);
445 done
; /* ugly macro end */
447 sprintf(restor
,"%s <%s",ip6tablesrestore
, ip6tablesfile
);
455 char *parse_datafile_line(char *str
);
456 time_t get_mtime(const char *path
);
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$ :-) */
467 char *substring
, *limit_pkts
;
470 int just_networks
= FALSE
;
471 int just_flush
= FALSE
; /* deactivates all previous actions */
473 int just_preview
= FALSE
; /* preview - generate just stats */
474 int start_shaping
= FALSE
; /* apply FUP - requires classmap file */
475 int stop_shaping
= FALSE
; /* lift FUP - requires classmap file */
476 int reduce_ceil
= 0; /* allow only rate+(ceil-rate)/2, /4, etc. */
477 int just_logs
= FALSE
; /* just parse logs */
484 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
485 Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\
486 iptables-restore & burst tunning & classify modification by Ludva\n\
487 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
489 /*----- Boring... we have to check command line options first: ----*/
492 argument("-c") { nextargument(config
); }
493 argument("-h") { nextargument(althosts
);}
494 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
495 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
496 argument("-9") { run
=TRUE
; just_flush
=9; }
497 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
498 argument("-q") { run
=TRUE
; just_preview
=TRUE
; stop_shaping
=TRUE
; }
499 argument("-2") { run
=TRUE
; just_preview
=TRUE
; reduce_ceil
=2; }
500 argument("-4") { run
=TRUE
; just_preview
=TRUE
; reduce_ceil
=4; }
501 argument("-s") { run
=TRUE
; just_preview
=TRUE
; start_shaping
=TRUE
; }
502 argument("-r") { run
=TRUE
; }
503 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
504 argument("-a") { run
=TRUE
; just_networks
=TRUE
; }
505 argument("-l") { just_logs
=TRUE
; }
506 argument("-m") { just_logs
=TRUE
; }
507 argument("-y") { just_logs
=TRUE
; }
508 argument("-?") { help(); exit(0); }
509 argument("--help") { help(); exit(0); }
510 argument("-v") { exit(0); }
511 argument("--version") { exit(0); }
516 puts("*** THIS IS JUST DRY RUN ! ***\n");
519 date(d
); /* this is typical cll1.h macro - prints current date */
521 /*-----------------------------------------------------------------*/
522 printf("Parsing configuration file %s ...\n", config
);
523 /*-----------------------------------------------------------------*/
525 /*-----------------------------------------------------------------*/
526 printf("Parsing upstream interfaces list %s ...\n", upstreamfile
);
527 /*-----------------------------------------------------------------*/
530 ptr
= parse_datafile_line(_
);
533 create(interface
, Interface
);
535 interface
->speed
= (long long)atol(ptr
);
536 /* is supplied value meaningful ?*/
537 if(interface
->speed
<= 0)
539 printf("Illegal value of %s interface bandwidth.\n", interface
->name
);
540 reject_config_and_exit(upstreamfile
);
542 interface
->is_upstream
= TRUE
;
543 interface
->chain
= "FORWARD";
544 interface
->idxprefix
= "forw";
545 push(interface
, interfaces
);
546 printf("Upstream interface %s: medium %s capacity %ld kbps\n", interface
->name
, medium
, interface
->speed
);
549 done
; /* ugly macro end */
551 /*-----------------------------------------------------------------*/
552 printf("Parsing downstream interfaces list %s ...\n", downstreamfile
);
553 /*-----------------------------------------------------------------*/
554 parse(downstreamfile
)
556 ptr
= parse_datafile_line(_
);
559 create(interface
, Interface
);
561 interface
->speed
= (long long)atol(ptr
);
562 /* is supplied value meaningful ?*/
563 if(interface
->speed
<= 0)
565 printf("Illegal value of %s interface bandwidth.\n", interface
->name
);
566 reject_config_and_exit(downstreamfile
);
568 interface
->is_upstream
= FALSE
;
569 interface
->chain
= "POSTROUTING";
570 interface
->idxprefix
= "post";
571 push(interface
, interfaces
);
572 printf("Downstream interface %s: medium %s capacity %ld kbps\n", interface
->name
, medium
, interface
->speed
);
575 done
; /* ugly macro end */
579 parse_ip_log(argc
,argv
);
595 /*-----------------------------------------------------------------*/
596 puts("Parsing iptables verbose output ...");
597 /*-----------------------------------------------------------------*/
598 get_traffic_statistics(iptables
, FALSE
);
601 /*-----------------------------------------------------------------*/
602 puts("Parsing ip6tables verbose output ...");
603 /*-----------------------------------------------------------------*/
604 get_traffic_statistics(ip6tables
, TRUE
);
608 /*-----------------------------------------------------------------*/
609 /* cll1.h - let's allocate brand new character buffer... */
610 /*-----------------------------------------------------------------*/
612 string(limit_pkts
, STRLEN
);
614 /*-----------------------------------------------------------------*/
615 printf("Parsing qos free interfaces file %s ...\n", qosfreefile
);
616 /*-----------------------------------------------------------------*/
617 load(qosfreeinterface
, qosfreeinterfaces
,
618 qosfreefile
, QosFreeInterface
, name
);
620 /*-----------------------------------------------------------------*/
621 printf("Parsing macro definition file %s ...\n", macrosfile
);
622 /*-----------------------------------------------------------------*/
625 ptr
= parse_datafile_line(_
);
628 create(macro
, Macro
);
629 macro
->rewrite_from
= _
;
630 macro
->rewrite_to
= ptr
;
632 printf("%s -> %s\n", macro
->rewrite_from
, macro
->rewrite_to
);
635 done
; /* ugly macro end */
639 /*-----------------------------------------------------------------*/
640 printf("Parsing class defintion file %s ...\n", hosts
);
641 /*-----------------------------------------------------------------*/
644 //this was pretty dumb idea anyway...
647 analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d");
652 /*-----------------------------------------------------------------*/
653 puts("Resolving shared connections ...");
654 /*-----------------------------------------------------------------*/
655 for_each(ip
, ips
) if(ip
->sharing
)
657 for_each(sharedip
, ips
) if(eq(sharedip
->name
, ip
->sharing
))
659 sharedip
->traffic
+= ip
->traffic
;
660 sharedip
->traffic_down
+= ip
->direct
;
661 sharedip
->traffic_up
+= ip
->upload
;
663 ip
->mark
= sharedip
->mark
;
664 ip
->lmsid
= sharedip
->lmsid
;
665 ip
->pps_limit
= sharedip
->pps_limit
; /* no other way to do this */
667 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */
668 ptr
= strchr(ip
->addr
, '+');
669 if(ptr
&& ptr
-ip
->addr
> 1 && !sharedip
->v6
)
672 concatenate(ip
->addr
, sharedip
->addr
, ptr
);
673 ip
->name
= ip
->addr
= ptr
;
674 ptr
= strchr(ip
->addr
, '.');
678 ptr
= strchr(ptr
, '.');
687 printf("Unresolved shared connection: %s %s sharing-%s\n",
688 ip
->addr
, ip
->name
, ip
->sharing
);
692 if(enable_credit
&& just_flush
<9)
694 /*-----------------------------------------------------------------*/
695 printf("Parsing credit file %s ...\n", credit
);
696 /*-----------------------------------------------------------------*/
699 ptr
= parse_datafile_line(_
);
702 if_exists(ip
,ips
,eq(ip
->addr
,_
))
704 sscanf(ptr
,"%Lu",&(ip
->credit
));
708 done
; /* ugly macro end */
714 /*-----------------------------------------------------------------*/
715 puts("Initializing iptables and tc classes ...");
716 /*-----------------------------------------------------------------*/
718 iptables_file
= fopen(iptablesfile
, "w");
719 if(iptables_file
== NULL
)
721 perror(iptablesfile
);
724 iptables_save_line(iptablespreamble
, IPv4
);
728 ip6tables_file
= fopen(ip6tablesfile
, "w");
729 if(ip6tables_file
== NULL
)
731 perror(ip6tablesfile
);
734 iptables_save_line(iptablespreamble
, IPv6
);
735 iptables_save_line(ip6preamble
, IPv6
);
738 run_iptables_restore();
740 log_file
= fopen(cmdlog
, "w");
747 for_each(interface
, interfaces
)
749 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null", tc
, interface
->name
);
753 iptables_file
=fopen(iptablesfile
,"w");
754 iptables_save_line(iptablespreamble
, IPv4
);
757 ip6tables_file
=fopen(ip6tablesfile
,"w");
758 iptables_save_line(iptablespreamble
, IPv6
);
759 iptables_save_line(ip6preamble
, IPv6
);
762 if(qos_free_zone
&& *qos_free_zone
!= '0') /* this is currently supported only for IPv4 */
764 for_each(interface
, interfaces
)
766 sprintf(str
,"-A %s -%c %s -o %s -j ACCEPT", interface
->chain
, (interface
->is_upstream
?'d':'s'), qos_free_zone
, interface
->name
);
767 iptables_save_line(str
, IPv4
);
771 if(qos_free_dst_ipset
&& *qos_free_dst_ipset
!= '0') /* this is currently supported only for IPv4 */
773 for_each(interface
, interfaces
)
775 sprintf(str
,"-A %s -m set --match-set %s %s -o %s -j ACCEPT", interface
->chain
, qos_free_dst_ipset
, (interface
->is_upstream
?"dst":"src"), interface
->name
);
776 iptables_save_line(str
, IPv4
);
780 if(qos_free_src_ipset
&& *qos_free_src_ipset
!= '0') /* this is currently supported only for IPv4 */
782 for_each(interface
, interfaces
)
784 sprintf(str
,"-A %s -m set --match-set %s %s -o %s -j ACCEPT", interface
->chain
, qos_free_src_ipset
, (interface
->is_upstream
?"src":"dst"), interface
->name
);
785 iptables_save_line(str
, IPv4
);
789 for_each(qosfreeinterface
, qosfreeinterfaces
)
791 sprintf(str
,"-A FORWARD -i %s -j ACCEPT", qosfreeinterface
->name
);
792 iptables_save_line(str
, IPv4
);
793 iptables_save_line(str
, IPv6
);
794 sprintf(str
,"-A POSTROUTING -o %s -j ACCEPT", qosfreeinterface
->name
);
795 iptables_save_line(str
, IPv4
);
796 iptables_save_line(str
, IPv6
);
799 if(ip_count
> idxtable_treshold1
&& !just_flush
)
801 int idxcount
=0, bitmask
=32-idxtable_bitmask1
;
803 /*-----------------------------------------------------------------*/
804 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
805 /*-----------------------------------------------------------------*/
807 iptables_save_line(":post_common - [0:0]", IPv4
);
808 iptables_save_line(":forw_common - [0:0]", IPv4
);
811 iptables_save_line(":post_common - [0:0]", IPv6
);
812 iptables_save_line(":forw_common - [0:0]", IPv6
);
815 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
819 buf
=index6_id(ip
->addr
,bitmask
+32);
823 buf
=index_id(ip
->addr
, bitmask
);
826 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
833 idx
->addr
= ip
->addr
;
835 idx
->bitmask
= bitmask
+32*ip
->v6
;
844 /* brutal perfomance optimalization */
845 while(idxcount
> idxtable_treshold2
&& bitmask
> 2*idxtable_bitmask2
)
847 bitmask
-= idxtable_bitmask2
;
850 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
854 buf
= index6_id(idx
->addr
, bitmask
+32);
858 buf
= index_id(idx
->addr
, bitmask
);
860 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
862 metaindex
->children
++;
866 create(metaindex
,Index
);
867 metaindex
->addr
= idx
->addr
;
869 metaindex
->bitmask
= bitmask
+32*idx
->ipv6
;
870 metaindex
->parent
= NULL
;
871 metaindex
->children
= 0;
872 metaindex
->ipv6
= idx
->ipv6
;
874 push(metaindex
,idxs
);
876 idx
->parent
=metaindex
;
880 /* this should slightly optimize throughput ... */
881 sort(idx
,idxs
,desc_order_by
,children
);
882 sort(idx
,idxs
,order_by
,bitmask
);
889 subnet
=subnet6_id(idx
->addr
, idx
->bitmask
);
893 subnet
=subnet_id(idx
->addr
, idx
->bitmask
);
895 printf("%d: %s/%d\n", ++i
, subnet
, idx
->bitmask
);
897 sprintf(str
,":post_%s - [0:0]", idx
->id
);
898 iptables_save_line(str
, idx
->ipv6
);
900 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
901 iptables_save_line(str
, idx
->ipv6
);
903 for_each(interface
, interfaces
)
907 string(buf
, strlen(idx
->parent
->id
)+6);
908 sprintf(buf
, "%s_%s", interface
->idxprefix
, idx
->parent
->id
);
912 buf
= interface
->chain
;
915 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s_%s",
916 buf
, (interface
->is_upstream
?'s':'d'), subnet
, idx
->bitmask
, interface
->name
, interface
->idxprefix
, idx
->id
);
917 iptables_save_line(str
, idx
->ipv6
);
919 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s_common",
920 buf
, (interface
->is_upstream
?'s':'d'), subnet
, idx
->bitmask
, interface
->name
, interface
->idxprefix
);
921 iptables_save_line(str
, idx
->ipv6
);
924 printf("Total indexed iptables chains created: %d\n", i
);
926 for_each(interface
, interfaces
)
928 sprintf(str
,"-A %s -o %s -j %s_common", interface
->chain
, interface
->name
, interface
->idxprefix
);
929 iptables_save_line(str
, IPv4
);
932 sprintf(str
,"-A %s -o %s -j %s_common", interface
->chain
, interface
->name
, interface
->idxprefix
);
933 iptables_save_line(str
, IPv6
);
941 fclose(iptables_file
);
946 puts("Just flushed iptables and tc classes - now exiting ...");
952 if(!dry_run
&& !nodelay
&& qos_free_delay
)
954 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay
);
955 sleep(qos_free_delay
);
958 for_each(interface
, interfaces
)
960 sprintf(str
, "%s qdisc add dev %s root handle 1: htb r2q %d default 1",
961 tc
, interface
->name
, htb_r2q
);
964 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
965 tc
, interface
->name
, medium
, medium
, burst_main
, highest_priority
);
968 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
969 tc
, interface
->name
, interface
->speed
, interface
->speed
, burst_main
, highest_priority
);
974 /*-----------------------------------------------------------------*/
975 puts("Locating heavy downloaders and generating root classes ...");
976 /*-----------------------------------------------------------------*/
977 sort(ip
,ips
,desc_order_by
,traffic
);
979 /*-----------------------------------------------------------------*/
980 for_each(interface
, interfaces
)
982 long long int rate
= interface
->speed
;
983 long long int max
= interface
->speed
;
985 //obsolete: FILE *credit_file = NULL;
987 //obsolete: if(!just_preview && !dry_run && enable_credit)
989 //obsolete: credit_file = fopen(credit,"w");
992 for_each(group
,groups
)
996 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",
997 tc
, interface
->name
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1001 if(group_count
++ < max_nesting
)
1006 rate
-= digital_divide
*group
->min
;
1007 if(rate
< group
->min
)
1012 /*shaping of aggresive downloaders, with credit file support */
1016 int group_rate = group->min, priority_sequence = lowest_priority;
1018 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
1020 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));
1021 if( ip->keyword->data_limit
1022 and not ip->fixedprio
1023 and ip->traffic > ip->realquota )
1025 if(group_rate < ip->max)
1027 ip->max = group_rate;
1029 group_rate+=magic_treshold;
1030 ip->prio=lowest_priority;
1031 if(ip->prio<highest_priority+2)
1033 ip->prio=highest_priority+2;
1038 if( ip->keyword->data_prio
1040 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1042 ip->prio=priority_sequence--;
1043 if(ip->prio<highest_priority+1)
1045 ip->prio=highest_priority+1;
1051 unsigned long long lcredit=0;
1053 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1055 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1057 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1066 fclose(credit_file);
1072 if(start_shaping
|| stop_shaping
|| reduce_ceil
)
1074 time_t how_much_seconds
= time(NULL
) - get_mtime(classmap
); /* sice start of daily aggregation session */
1075 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap
, how_much_seconds
);
1084 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1086 int unshape_this_ip
= 0;
1087 long avg_mbps_down
= ip
->traffic_down
* 8 / how_much_seconds
;
1088 long avg_mbps_up
= ip
->traffic_up
* 8 / how_much_seconds
;
1089 int agreg
= 1, print_stats
= 1;
1091 if(ip
->keyword
->download_aggregation
)
1093 int min_mbps
= (ip
->min
/ip
->keyword
->download_aggregation
)>>10;
1099 if(min_mbps
<= avg_mbps_down
)
1101 unshape_this_ip
= 0;
1102 agreg
= (int)((float)(avg_mbps_down
+1)/min_mbps
+.5);
1104 ip
->pps_limit
/= agreg
;
1105 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg
, ip
->name
, min_mbps
, avg_mbps_down
);
1109 unshape_this_ip
= 1;
1112 else if(ip
->keyword
->upload_aggregation
)
1114 int min_mbps
= (ip
->min
/ip
->keyword
->upload_aggregation
)>>10;
1120 if(min_mbps
<= avg_mbps_up
)
1122 unshape_this_ip
= 0;
1123 agreg
= (int)((float)(avg_mbps_up
+1)/min_mbps
+.5);
1125 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg
, ip
->name
, min_mbps
, avg_mbps_up
);
1129 unshape_this_ip
= 1;
1134 unshape_this_ip
= 1;
1136 ip
->aggregated
= agreg
;
1137 ip
->mark
= atoi(ptr
);
1138 if(ip
->max
< ip
->desired
|| unshape_this_ip
|| reduce_ceil
) /* apply or disable FUP limit immediately.... */
1142 ip
->max
= ip
->desired
;
1143 if(stop_shaping
) /* all limits removed, but not printed with -s (start_shaping) switch */
1145 printf("Removing limit for %s (%s) ", ip
->name
, ip
->addr
);
1154 printf("Updating %s (%s) ", ip
->name
, ip
->addr
);
1157 ip
->max
= ip
->min
+ (ip
->desired
-ip
->min
)/reduce_ceil
;
1159 else if(ip
->max
< ip
->min
)
1164 for_each(interface
, interfaces
)
1166 if(!interface
->is_upstream
)
1170 printf("[down %s: %dk-%dk wants %d]", interface
->name
, ip
->min
, ip
->max
, ip
->desired
);
1172 sprintf(str
, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1173 tc
, interface
->name
, ip
->group
, ip
->mark
, ip
->min
, ip
->max
, burst
, ip
->prio
);
1180 printf("[up %s: %dk-%dk wants %dk]", interface
->name
, (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1181 (int)((ip
->desired
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1182 (int)((ip
->desired
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1184 sprintf(str
,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1185 tc
, interface
->name
, ip
->group
, ip
->mark
,
1186 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1187 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1202 puts("Warning - classmap file not fund, just generating preview ...");
1203 start_shaping
=FALSE
;
1206 done
; /* ugly macro end */
1209 json_traffic
=json_preview
;
1212 if(!dry_run
&& !just_flush
)
1214 /*-----------------------------------------------------------------*/
1215 printf("Writing json traffic overview %s ... ", json_traffic
);
1216 /*-----------------------------------------------------------------*/
1217 write_json_traffic(json_traffic
);
1219 /*-----------------------------------------------------------------*/
1220 printf("Writing statistics into HTML page %s ...\n", html
);
1221 /*-----------------------------------------------------------------*/
1222 write_htmlandlogs(html
, d
, total
, just_preview
);
1232 else if(reduce_ceil
)
1234 swchar
='0'+reduce_ceil
; /* -2, -4 */
1236 else if(stop_shaping
)
1241 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar
);
1247 printf("%-22s %-15s mark\n","name","ip");
1250 printf("Writing %s", classmap
);
1251 f
= fopen(classmap
, "w");
1257 /*-----------------------------------------------------------------*/
1258 printf(" + generating iptables and tc classes ... ");
1259 /*-----------------------------------------------------------------*/
1261 for_each(ip
, ips
) if(ip
->mark
> 0)
1263 for_each(interface
, interfaces
)
1269 duplicate(ip
->addr
,buf
);
1272 buf
=index6_id(ip
->addr
,64-idxtable_bitmask1
);
1276 buf
=index_id(ip
->addr
,32-idxtable_bitmask1
);
1279 string(chain
, 6+strlen(buf
));
1280 sprintf(chain
, "%s_", interface
->idxprefix
);
1287 chain
= interface
->chain
;
1290 /* packet limits - this will be optional in future */
1293 sprintf(limit_pkts
, "-m limit --limit %d/s --limit-burst %d ",
1294 ip
->pps_limit
, ip
->pps_limit
);
1302 printf("%-22s %-16s %04d %d/s\n", ip
->name
, ip
->addr
, ip
->mark
, ip
->pps_limit
);
1305 /* ------------------------------------------------ iptables classify */
1306 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s%d",
1307 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1308 interface
->name
, mark_iptables
, ip
->mark
);
1309 iptables_save_line(str
, ip
->v6
);
1311 sprintf(str
, "-A %s -%c %s/%d -o %s %s-j ACCEPT",
1312 chain
, (interface
->is_upstream
?'s':'d'),ip
->addr
, ip
->mask
,
1313 interface
->name
, limit_pkts
);
1314 iptables_save_line(str
, ip
->v6
);
1316 if(*limit_pkts
) /* non-empty string?*/
1318 /* classify overlimit packets to separate overlimit class */
1319 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s%d",
1320 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1321 interface
->name
, mark_iptables
, OVERLIMIT_CLASS
);
1322 iptables_save_line(str
, ip
->v6
);
1324 sprintf(str
, "-A %s -%c %s/%d -o %s -j ACCEPT",
1325 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1327 iptables_save_line(str
, ip
->v6
);
1332 //TODO - min and max should not exceed interface->speed
1334 /* -------------------------------------------------------- tc class */
1336 printf("[down: %dk-%dk]", ip
->min
, ip
->max
);
1339 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1340 tc
, interface
->name
, ip
->group
, ip
->mark
, ip
->min
, ip
->max
, burst
, ip
->prio
);
1343 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1345 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
1346 tc
, interface
->name
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
1350 if(filter_type
== 1)
1352 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1353 tc
, interface
->name
, ip
->mark
, ip
->mark
);
1360 printf("(sharing %s)\n", ip
->sharing
);
1365 if(ip
->min
&& f
> 0)
1367 fprintf(f
, "%s %d\n", ip
->addr
, ip
->mark
);
1376 for_each(interface
, interfaces
)
1381 string(chain
, STRLEN
);
1382 sprintf(chain
, "%s_common", interface
->idxprefix
);
1386 chain
= interface
->chain
;
1391 final_chain
= "ACCEPT";
1393 sprintf(str
, "-A %s -o %s -j %s%d",
1394 chain
, interface
->name
, mark_iptables
, FREE_CLASS
);
1395 iptables_save_line(str
, IPv4
); /* only for IPv4 */
1398 sprintf(str
,"-A %s -o %s -j %s", chain
, interface
->name
, final_chain
);
1399 iptables_save_line(str
, IPv4
);
1402 sprintf(str
,"-A %s -o %s -j %s", chain
, interface
->name
, final_chain
);
1403 iptables_save_line(str
, IPv6
);
1406 if(free_min
) /* allocate free bandwith if it is not zero... */
1408 /*-----------------------------------------------------------------*/
1409 puts("Generating free bandwith class ...");
1410 /*-----------------------------------------------------------------*/
1411 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1412 tc
, interface
->name
, parent
, FREE_CLASS
, free_min
, free_max
,burst
, lowest_priority
);
1415 if(strcmpi(qos_leaf
, "none"))
1417 sprintf(str
,"%s qdisc add dev %s parent 1:%d handle %d %s", tc
, interface
->name
, FREE_CLASS
, FREE_CLASS
, qos_leaf
);
1420 /* tc handle 1 fw flowid */
1421 sprintf(str
,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc
, interface
->name
, FREE_CLASS
, FREE_CLASS
);
1424 /*-----------------------------------------------------------------*/
1425 puts("Generating bandwith class for overlimit packets...");
1426 /*-----------------------------------------------------------------*/
1427 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1428 tc
, interface
->name
, parent
, OVERLIMIT_CLASS
, overlimit_min
, overlimit_max
, burst
, lowest_priority
);
1431 printf("Total IP count: %d\n", i
);
1432 run_iptables_restore();
1438 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1439 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.103177 seconds and 3 git commands to generate.