1c917386c82e7d68cb1d747f7fc6733f73bd59e8
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-2020 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, 20200107
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
= "1.0.0-a";
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-2020 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 *iptablesdump
= "/var/spool/prometheus.iptables-dump"; /* temporary file for iptables -L -v -x -n -t mangle */
67 char *ip6tablesfile
= "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/
68 char *credit
= "/var/lib/misc/prometheus.credit"; /* credit log file */
69 char *classmap
= "/var/lib/misc/prometheus.classes"; /* credit log file */
70 char *html
= "/var/www/traffic.html"; /* hall of fame - html version */
71 char *preview
= "/var/www/preview.html"; /* hall of fame preview - html version */
72 char *json_traffic
= "/var/www/logs/traffic.json"; /* hall of fame - json version */
73 char *json_preview
= "/var/www/logs/preview.json"; /* hall of fame preview - json version */
74 char *cmdlog
= "/var/log/prometheuslog"; /* command log filename */
75 char *log_dir
= "/var/www/logs/"; /* log directory pathname, ended with slash */
76 char *log_url
= "/logs/"; /* log directory relative URI prefix (partial URL) */
77 char *html_log_dir
= "/var/www/logs/html/";
79 char *jquery_url
= "http://code.jquery.com/jquery-latest.js";
80 char *lms_url
= "/lms/?m=customerinfo&id=";
81 int use_jquery_popups
= TRUE
;
82 int row_odd_even
= 0; /*<tr class="odd/even"> */
84 /* === Configuraration file values defaults - stored in global variables ==== */
86 int filter_type
= 1; /*1 mark, 2 classify*/
87 char *final_chain
= "DROP"; /* REJECT would be better, but it is impossible in mangle */
89 char *mark_iptables
= "MARK --set-mark ";
90 int dry_run
= FALSE
; /* preview - use puts() instead of system() */
91 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]";
92 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";
93 FILE *iptables_file
= NULL
;
94 FILE *ip6tables_file
= NULL
;
95 int enable_credit
= TRUE
; /* enable credit file */
96 int use_credit
= FALSE
; /* use credit file (if enabled)*/
97 char *title
= "Hall of Fame - Greatest Suckers"; /* hall of fame title */
98 int hall_of_fame
= TRUE
; /* enable hall of fame */
99 char *medium
= "1000Mbit"; /* 10Mbit/100Mbit ethernet */
100 //obsolete: char *lan = "eth0"; /* LAN interface */
101 //obsolete: char *lan_medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */
102 char *ip6prefix
= NULL
; /* Prefix for global /48 IPv6 subnet */
103 char *qos_leaf
= "sfq perturb 5"; /* leaf discipline */
104 char *qos_free_zone
= NULL
; /* QoS free zone */
105 char *qos_free_dst_ipset
= NULL
; /* QoS free zone - dst match ipset name, must be prepared outside prometheus */
106 char *qos_free_src_ipset
= NULL
; /* QoS free zone - src match ipset name, must be prepared outside prometheus */
107 /* int qos_proxy = TRUE; include proxy port to QoS */
108 int found_lmsid
= FALSE
; /* show links to users in LMS information system */
109 int include_upload
= TRUE
; /* upload+download=total traffic */
110 /* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */
111 /* int proxy_port = 3128; proxy port number */
112 //obsolete: long long int line = 1024; /* WAN/ISP download in kbps */
113 //obsolete: long long int up = 1024; /* WAN/ISP upload in kbps */
114 int free_min
= 256; /* minimum guaranted bandwidth for all undefined hosts */
115 int free_max
= 512; /* maximum allowed bandwidth for all undefined hosts */
116 int overlimit_min
= 256; /* minimum guaranted bandwidth for all undefined hosts */
117 int overlimit_max
= 512; /* maximum allowed bandwidth for all undefined hosts */
118 int qos_free_delay
= 0; /* seconds to sleep before applying new QoS rules */
119 int digital_divide
= 2; /* controls digital divide weirdness ratio, 1...3 */
120 int max_nesting
= 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */
121 int htb_r2q
= 256; /* should work for leaf values 512 kbps to 8 Mbps */
122 int burst
= 8; /* HTB burst (in kbits) */
124 int burst_group
= 32;
125 int magic_treshold
= 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
126 int keywordcount
= 0;
129 FILE *log_file
= NULL
;
130 char *kwd
= "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
132 const int highest_priority
= 0; /* highest HTB priority (HTB built-in value is 0) */
133 const int lowest_priority
= 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */
134 const int idxtable_treshold1
= 24; /* this is no longer configurable */
135 const int idxtable_treshold2
= 12; /* this is no longer configurable */
136 const int idxtable_bitmask1
= 3; /* this is no longer configurable */
137 const int idxtable_bitmask2
= 3; /* this is no longer configurable */
139 struct IP
*ips
= NULL
, *networks
= NULL
, *ip
, *sharedip
;
140 struct Group
*groups
= NULL
, *group
;
141 struct Keyword
*keyword
, *defaultkeyword
=NULL
, *keywords
= NULL
;
142 struct Macro
*macro
, *macros
= NULL
;
143 struct Index
*idxs
= NULL
, *idx
, *metaindex
;
144 struct Interface
*interfaces
= NULL
, *interface
;
145 struct QosFreeInterface
*qosfreeinterfaces
= NULL
, *qosfreeinterface
;
148 #define OVERLIMIT_CLASS 4
151 /* implemented in help.c */
153 void get_traffic_statistics(const char *whichiptables
, int ipv6
);
154 /* implemented in parseiptables.c */
156 void parse_ip_log(int argc
, char **argv
);
157 /* implemented in parselog.c */
159 void parse_hosts(char *hosts
);
160 /* implemented in parsehosts.c */
162 void write_json_traffic(char *json
);
163 /* implemented in json.c */
165 void write_htmlandlogs(char *html
, char *d
, int total
, int just_preview
);
166 /* implemented in htmlandlogs.c */
168 void analyse_topology(char *traceroute
);
169 /* implemented in networks.c */
171 char *parse_datafile_line(char *str
);
172 /* implemented in utils.c */
174 time_t get_mtime(const char *path
);
175 /* implemented in utils.c */
177 const char *tr_odd_even(void)
179 row_odd_even
= 1 - row_odd_even
;
182 return "<tr class=\"even\">\n";
186 return "<tr class=\"odd\">\n";
191 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
193 char *index_id(char *ip
, int bitmask
);
194 /* function implemented in ipv4subnets.c */
196 char *subnet_id(char *ip
, int bitmask
);
197 /* function implemented in ipv4subnets.c */
199 char *index6_id(char *ip
, int bitmask
);
200 /* function implemented in ipv6subnets.c */
202 char *subnet6_id(char *ip
, int bitmask
);
203 /* function implemented in ipv6subnets.c */
205 /* ================= Let's parse configuration file here ================ */
207 void reject_config_and_exit(char *filename
)
209 printf("Configuration file %s rejected - abnormal exit.",filename
);
213 void get_config(char *config_filename
)
217 printf("Configured keywords: ");
218 parse(config_filename
)
220 option("keyword",kwd
);
225 create(keyword
,Keyword
);
227 keyword
->asymetry_ratio
= 1; /* ratio for ADSL-like upload */
228 keyword
->asymetry_fixed
= 0; /* fixed treshold for ADSL-like upload */
229 keyword
->data_limit
= 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
230 keyword
->data_prio
= 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
231 keyword
->fixed_limit
= 0; /* fixed data limit for setting lower HTB ceil */
232 keyword
->fixed_prio
= 0; /* fixed data limit for setting lower HTB prio */
233 keyword
->reserve_min
= 8; /* bonus for nominal HTB rate bandwidth (in kbps) */
234 keyword
->reserve_max
= 0; /* malus for nominal HTB ceil (in kbps) */
235 keyword
->default_prio
= highest_priority
+1;
236 keyword
->download_aggregation
= keyword
->upload_aggregation
= 0; /* disable by default */
237 keyword
->html_color
= "000000";
238 keyword
->ip_count
= 0;
239 keyword
->leaf_discipline
= "";
240 keyword
->allowed_avgmtu
= 0;
242 push(keyword
, keywords
);
245 defaultkeyword
= keyword
;
253 for_each(keyword
,keywords
)
255 int l
=strlen(keyword
->key
);
257 if(!strncmp(keyword
->key
,_
,l
) && strlen(_
)>l
+2)
259 char *tmptr
=_
; /* <---- l+1 ----> */
260 _
+=l
+1; /* via-prometheus-asymetry-ratio, etc. */
261 foption("asymetry-ratio", keyword
->asymetry_ratio
);
262 ioption("asymetry-treshold", keyword
->asymetry_fixed
);
263 ioption("magic-relative-limit", keyword
->data_limit
);
264 ioption("magic-relative-prio", keyword
->data_prio
);
265 loption("magic-fixed-limit", keyword
->fixed_limit
);
266 loption("magic-fixed-prio", keyword
->fixed_prio
);
267 ioption("htb-default-prio", keyword
->default_prio
);
268 ioption("htb-rate-bonus", keyword
->reserve_min
);
269 ioption("htb-ceil-malus", keyword
->reserve_max
);
270 ioption("download-aggregation", keyword
->download_aggregation
);
271 ioption("upload-aggregation", keyword
->upload_aggregation
);
272 option("leaf-discipline", keyword
->leaf_discipline
);
273 option("html-color", keyword
->html_color
);
274 ioption("allowed-avgmtu" ,keyword
->allowed_avgmtu
);
277 if(keyword
->data_limit
|| keyword
->fixed_limit
||
278 keyword
->data_prio
|| keyword
->fixed_prio
)
287 option("iptables",iptables
);
288 option("iptables-save",iptablessave
);
289 option("iptables-restore",iptablesrestore
);
290 option("ip6tables",ip6tables
);
291 option("ip6tables-save",ip6tablessave
);
292 option("ip6tables-restore",ip6tablesrestore
);
293 option("iptables-in-filename",iptablesfile
);
294 option("iptables-dump-filename",iptablesdump
);
295 option("ip6tables-in-filename",ip6tablesfile
);
296 option("hosts",hosts
);
297 option("downstream-interfaces-list-filename",downstreamfile
);
298 option("upstream-interfaces-list-filename",upstreamfile
);
299 option("qos-free-interfaces-list-filename",qosfreefile
);
300 option("macros-filename",macrosfile
);
301 option("ip6-prefix",ip6prefix
);
302 option("medium",medium
);
303 ioption("hall-of-fame-enable",hall_of_fame
);
304 ioption("digital-divide-weirdness-ratio",digital_divide
);
305 option("hall-of-fame-title",title
);
306 option("hall-of-fame-filename",html
);
307 option("json-filename",json_traffic
);
308 option("hall-of-fame-preview",preview
);
309 option("json-preview",json_preview
);
310 option("log-filename",cmdlog
);
311 option("credit-filename",credit
);
312 option("classmap-filename",classmap
);
313 ioption("credit-enable",enable_credit
);
314 option("log-traffic-directory",log_dir
);
315 option("log-traffic-html-directory",html_log_dir
);
316 option("log-traffic-url-path",log_url
);
317 option("jquery-url",jquery_url
);
318 option("lms-url",lms_url
);
319 ioption("use-jquery-popups",use_jquery_popups
);
320 option("qos-free-zone",qos_free_zone
);
321 option("qos-free-dst-ipset",qos_free_dst_ipset
);
322 option("qos-free-src-ipset",qos_free_src_ipset
);
323 ioption("qos-free-delay",qos_free_delay
);
324 /* ioption("qos-proxy-enable",qos_proxy); */
325 /* option("qos-proxy-ip",proxy_ip);*/
326 option("htb-leaf-discipline",qos_leaf
);
327 /* ioption("qos-proxy-port",proxy_port); */
328 ioption("free-rate",free_min
);
329 ioption("free-ceil",free_max
);
330 ioption("overlimit-rate",overlimit_min
);
331 ioption("overlimit-ceil",overlimit_max
);
332 ioption("htb-burst",burst
);
333 ioption("htb-burst-main",burst_main
);
334 ioption("htb-burst-group",burst_group
);
335 ioption("htb-nesting-limit",max_nesting
);
336 ioption("htb-r2q",htb_r2q
);
337 ioption("magic-include-upload",include_upload
);
338 ioption("magic-treshold",magic_treshold
);
339 option("filter-type", cnf
);
340 /* not yet implemented:
341 ioption("magic-fixed-packets",fixed_packets);
342 ioption("magic-relative-packets",packet_limit);
347 perror(config_filename
);
348 puts("Warning - using built-in defaults instead ...");
350 done
; /* ugly macro end */
353 /* leaf discipline for keywords */
354 for_each(keyword
,keywords
)
356 if(!strcmpi(keyword
->leaf_discipline
, ""))
358 keyword
->leaf_discipline
= qos_leaf
;
362 if(strcmpi(cnf
, "mark"))
366 mark_iptables
= "CLASSIFY --set-class 1:";
372 mark_iptables
= "MARK --set-mark ";
377 /* ========== This function executes, logs OR ALSO prints command ========== */
379 void safe_run(char *cmd
)
383 printf("\n=>%s\n",cmd
);
391 fprintf(log_file
,"%s\n",cmd
);
395 void iptables_save_line(char *line
, int ipv6
)
399 fprintf(ip6tables_file
,"%s\n",line
);
403 fprintf(iptables_file
,"%s\n",line
);
411 void run_iptables_restore(void)
414 string(restor
, STRLEN
);
416 /*-----------------------------------------------------------------*/
417 printf("Running %s <%s ...\n", iptablesrestore
, iptablesfile
);
418 /*-----------------------------------------------------------------*/
420 iptables_save_line("COMMIT", IPv4
);
421 fclose(iptables_file
);
428 done
; /* ugly macro end */
431 sprintf(restor
,"%s <%s",iptablesrestore
, iptablesfile
);
436 /*-----------------------------------------------------------------*/
437 printf("Running %s <%s ...\n", ip6tablesrestore
, ip6tablesfile
);
438 /*-----------------------------------------------------------------*/
439 iptables_save_line("COMMIT", IPv6
);
440 fclose(ip6tables_file
);
447 done
; /* ugly macro end */
449 sprintf(restor
,"%s <%s",ip6tablesrestore
, ip6tablesfile
);
457 char *parse_datafile_line(char *str
);
458 time_t get_mtime(const char *path
);
460 /*-----------------------------------------------------------------*/
461 /* Are you looking for int main(int argc, char **argv) ? :-)) */
462 /*-----------------------------------------------------------------*/
466 int i
=0; /* just plain old Fortran style integer :-) */
467 FILE *f
=NULL
; /* everything is just stream of bytes... */
468 char *str
, *ptr
, *d
; /* LET A$=B$ :-) */
469 char *substring
, *limit_pkts
;
472 int just_networks
= FALSE
;
473 int just_flush
= FALSE
; /* deactivates all previous actions */
475 int just_preview
= FALSE
; /* preview - generate just stats */
476 int start_shaping
= FALSE
; /* apply FUP - requires classmap file */
477 int stop_shaping
= FALSE
; /* lift FUP - requires classmap file */
478 int reduce_ceil
= 0; /* allow only rate+(ceil-rate)/2, /4, etc. */
479 int just_logs
= FALSE
; /* just parse logs */
486 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
487 Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\
488 iptables-restore & burst tunning & classify modification by Ludva\n\
489 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version
);
491 /*----- Boring... we have to check command line options first: ----*/
494 argument("-c") { nextargument(config
); }
495 argument("-h") { nextargument(althosts
);}
496 argument("-d") { run
=TRUE
; dry_run
=TRUE
; }
497 argument("-f") { run
=TRUE
; just_flush
=TRUE
; }
498 argument("-9") { run
=TRUE
; just_flush
=9; }
499 argument("-p") { run
=TRUE
; just_preview
=TRUE
; }
500 argument("-q") { run
=TRUE
; just_preview
=TRUE
; stop_shaping
=TRUE
; }
501 argument("-2") { run
=TRUE
; just_preview
=TRUE
; reduce_ceil
=2; }
502 argument("-4") { run
=TRUE
; just_preview
=TRUE
; reduce_ceil
=4; }
503 argument("-s") { run
=TRUE
; just_preview
=TRUE
; start_shaping
=TRUE
; }
504 argument("-r") { run
=TRUE
; }
505 argument("-n") { run
=TRUE
; nodelay
=TRUE
; }
506 argument("-a") { run
=TRUE
; just_networks
=TRUE
; }
507 argument("-l") { just_logs
=TRUE
; }
508 argument("-m") { just_logs
=TRUE
; }
509 argument("-y") { just_logs
=TRUE
; }
510 argument("-?") { help(); exit(0); }
511 argument("--help") { help(); exit(0); }
512 argument("-v") { exit(0); }
513 argument("--version") { exit(0); }
518 puts("*** THIS IS JUST DRY RUN ! ***\n");
521 date(d
); /* this is typical cll1.h macro - prints current date */
523 /*-----------------------------------------------------------------*/
524 printf("Parsing configuration file %s ...\n", config
);
525 /*-----------------------------------------------------------------*/
527 /*-----------------------------------------------------------------*/
528 printf("Parsing upstream interfaces list %s ...\n", upstreamfile
);
529 /*-----------------------------------------------------------------*/
532 ptr
= parse_datafile_line(_
);
535 create(interface
, Interface
);
537 interface
->speed
= (long long)atol(ptr
);
538 /* is supplied value meaningful ?*/
539 if(interface
->speed
<= 0)
541 printf("Illegal value of %s interface bandwidth.\n", interface
->name
);
542 reject_config_and_exit(upstreamfile
);
544 interface
->is_upstream
= TRUE
;
545 interface
->chain
= "FORWARD";
546 interface
->idxprefix
= "forw";
547 push(interface
, interfaces
);
548 printf("Upstream interface %s: medium %s capacity %ld kbps\n", interface
->name
, medium
, interface
->speed
);
551 done
; /* ugly macro end */
553 /*-----------------------------------------------------------------*/
554 printf("Parsing downstream interfaces list %s ...\n", downstreamfile
);
555 /*-----------------------------------------------------------------*/
556 parse(downstreamfile
)
558 ptr
= parse_datafile_line(_
);
561 create(interface
, Interface
);
563 interface
->speed
= (long long)atol(ptr
);
564 /* is supplied value meaningful ?*/
565 if(interface
->speed
<= 0)
567 printf("Illegal value of %s interface bandwidth.\n", interface
->name
);
568 reject_config_and_exit(downstreamfile
);
570 interface
->is_upstream
= FALSE
;
571 interface
->chain
= "POSTROUTING";
572 interface
->idxprefix
= "post";
573 push(interface
, interfaces
);
574 printf("Downstream interface %s: medium %s capacity %ld kbps\n", interface
->name
, medium
, interface
->speed
);
577 done
; /* ugly macro end */
581 parse_ip_log(argc
,argv
);
597 /*-----------------------------------------------------------------*/
598 puts("Parsing iptables verbose output ...");
599 /*-----------------------------------------------------------------*/
600 get_traffic_statistics(iptables
, FALSE
);
603 /*-----------------------------------------------------------------*/
604 puts("Parsing ip6tables verbose output ...");
605 /*-----------------------------------------------------------------*/
606 get_traffic_statistics(ip6tables
, TRUE
);
610 /*-----------------------------------------------------------------*/
611 /* cll1.h - let's allocate brand new character buffer... */
612 /*-----------------------------------------------------------------*/
614 string(limit_pkts
, STRLEN
);
616 /*-----------------------------------------------------------------*/
617 printf("Parsing qos free interfaces file %s ...\n", qosfreefile
);
618 /*-----------------------------------------------------------------*/
619 load(qosfreeinterface
, qosfreeinterfaces
,
620 qosfreefile
, QosFreeInterface
, name
);
622 /*-----------------------------------------------------------------*/
623 printf("Parsing macro definition file %s ...\n", macrosfile
);
624 /*-----------------------------------------------------------------*/
627 ptr
= parse_datafile_line(_
);
630 create(macro
, Macro
);
631 macro
->rewrite_from
= _
;
632 macro
->rewrite_to
= ptr
;
634 printf("%s -> %s\n", macro
->rewrite_from
, macro
->rewrite_to
);
637 done
; /* ugly macro end */
641 /*-----------------------------------------------------------------*/
642 printf("Parsing class defintion file %s ...\n", hosts
);
643 /*-----------------------------------------------------------------*/
646 #ifdef MONITORINGTRHU_CTU
647 //special hack only to generate certain required CSV statistics for www.ctu.cz (regulation body)
648 //not required for everyday use, requires special syntax sugar in hosts file, see parsehosts.c
649 for_each(technology
, technologies
)
653 string(filename
, strlen(log_dir
) + strlen(technology
->filename
) + 5);
654 strcpy(filename
, html_log_dir
);
655 strcat(filename
, technology
->filename
);
656 strcat(filename
, ".csv");
657 /*-----------------------------------------------------------------*/
658 printf("Writing report file %s ...\n", filename
);
659 /*-----------------------------------------------------------------*/
660 f
= fopen(filename
, "w");
663 for_each(ip
, ips
) if(eq(technology
->filename
, ip
->technology_str
))
665 fprintf(f
,"%d,%s,%d\n", ip
->lmsid
, ip
->ruian_id_str
, ip
->max
);
674 /*-----------------------------------------------------------------*/
675 puts("Resolving shared connections ...");
676 /*-----------------------------------------------------------------*/
677 for_each(ip
, ips
) if(ip
->sharing
)
679 for_each(sharedip
, ips
) if(eq(sharedip
->name
, ip
->sharing
))
681 sharedip
->traffic
+= ip
->traffic
;
682 sharedip
->traffic_down
+= ip
->direct
;
683 sharedip
->traffic_up
+= ip
->upload
;
685 ip
->mark
= sharedip
->mark
;
686 ip
->lmsid
= sharedip
->lmsid
;
687 ip
->pps_limit
= sharedip
->pps_limit
; /* no other way to do this */
689 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */
690 ptr
= strchr(ip
->addr
, '+');
691 if(ptr
&& ptr
-ip
->addr
> 1 && !sharedip
->v6
)
694 concatenate(ip
->addr
, sharedip
->addr
, ptr
);
695 ip
->name
= ip
->addr
= ptr
;
696 ptr
= strchr(ip
->addr
, '.');
700 ptr
= strchr(ptr
, '.');
709 printf("Unresolved shared connection: %s %s sharing-%s\n",
710 ip
->addr
, ip
->name
, ip
->sharing
);
714 if(enable_credit
&& just_flush
<9)
716 /*-----------------------------------------------------------------*/
717 printf("Parsing credit file %s ...\n", credit
);
718 /*-----------------------------------------------------------------*/
721 ptr
= parse_datafile_line(_
);
724 if_exists(ip
,ips
,eq(ip
->addr
,_
))
726 sscanf(ptr
,"%Lu",&(ip
->credit
));
730 done
; /* ugly macro end */
736 /*-----------------------------------------------------------------*/
737 puts("Initializing iptables and tc classes ...");
738 /*-----------------------------------------------------------------*/
740 iptables_file
= fopen(iptablesfile
, "w");
741 if(iptables_file
== NULL
)
743 perror(iptablesfile
);
746 iptables_save_line(iptablespreamble
, IPv4
);
750 ip6tables_file
= fopen(ip6tablesfile
, "w");
751 if(ip6tables_file
== NULL
)
753 perror(ip6tablesfile
);
756 iptables_save_line(iptablespreamble
, IPv6
);
757 iptables_save_line(ip6preamble
, IPv6
);
760 run_iptables_restore();
762 log_file
= fopen(cmdlog
, "w");
769 for_each(interface
, interfaces
)
771 sprintf(str
,"%s qdisc del dev %s root 2>/dev/null", tc
, interface
->name
);
775 iptables_file
=fopen(iptablesfile
,"w");
776 iptables_save_line(iptablespreamble
, IPv4
);
779 ip6tables_file
=fopen(ip6tablesfile
,"w");
780 iptables_save_line(iptablespreamble
, IPv6
);
781 iptables_save_line(ip6preamble
, IPv6
);
784 if(qos_free_zone
&& *qos_free_zone
!= '0') /* this is currently supported only for IPv4 */
786 for_each(interface
, interfaces
)
788 sprintf(str
,"-A %s -%c %s -o %s -j ACCEPT", interface
->chain
, (interface
->is_upstream
?'d':'s'), qos_free_zone
, interface
->name
);
789 iptables_save_line(str
, IPv4
);
793 if(qos_free_dst_ipset
&& *qos_free_dst_ipset
!= '0') /* this is currently supported only for IPv4 */
795 for_each(interface
, interfaces
)
797 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
);
798 iptables_save_line(str
, IPv4
);
802 if(qos_free_src_ipset
&& *qos_free_src_ipset
!= '0') /* this is currently supported only for IPv4 */
804 for_each(interface
, interfaces
)
806 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
);
807 iptables_save_line(str
, IPv4
);
811 for_each(qosfreeinterface
, qosfreeinterfaces
)
813 sprintf(str
,"-A FORWARD -i %s -j ACCEPT", qosfreeinterface
->name
);
814 iptables_save_line(str
, IPv4
);
815 iptables_save_line(str
, IPv6
);
816 sprintf(str
,"-A POSTROUTING -o %s -j ACCEPT", qosfreeinterface
->name
);
817 iptables_save_line(str
, IPv4
);
818 iptables_save_line(str
, IPv6
);
821 if(ip_count
> idxtable_treshold1
&& !just_flush
)
823 int idxcount
=0, bitmask
=32-idxtable_bitmask1
;
825 /*-----------------------------------------------------------------*/
826 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count
);
827 /*-----------------------------------------------------------------*/
829 iptables_save_line(":post_common - [0:0]", IPv4
);
830 iptables_save_line(":forw_common - [0:0]", IPv4
);
833 iptables_save_line(":post_common - [0:0]", IPv6
);
834 iptables_save_line(":forw_common - [0:0]", IPv6
);
837 for_each(ip
,ips
) if(ip
->addr
&& *(ip
->addr
) && !eq(ip
->addr
,"0.0.0.0/0"))
841 buf
=index6_id(ip
->addr
,bitmask
+32);
845 buf
=index_id(ip
->addr
, bitmask
);
848 if_exists(idx
,idxs
,eq(idx
->id
,buf
))
855 idx
->addr
= ip
->addr
;
857 idx
->bitmask
= bitmask
+32*ip
->v6
;
866 /* brutal perfomance optimalization */
867 while(idxcount
> idxtable_treshold2
&& bitmask
> 2*idxtable_bitmask2
)
869 bitmask
-= idxtable_bitmask2
;
872 for_each(idx
,idxs
) if(idx
->parent
== NULL
)
876 buf
= index6_id(idx
->addr
, bitmask
+32);
880 buf
= index_id(idx
->addr
, bitmask
);
882 if_exists(metaindex
,idxs
,eq(metaindex
->id
,buf
))
884 metaindex
->children
++;
888 create(metaindex
,Index
);
889 metaindex
->addr
= idx
->addr
;
891 metaindex
->bitmask
= bitmask
+32*idx
->ipv6
;
892 metaindex
->parent
= NULL
;
893 metaindex
->children
= 0;
894 metaindex
->ipv6
= idx
->ipv6
;
896 push(metaindex
,idxs
);
898 idx
->parent
=metaindex
;
902 /* this should slightly optimize throughput ... */
903 sort(idx
,idxs
,desc_order_by
,children
);
904 sort(idx
,idxs
,order_by
,bitmask
);
911 subnet
=subnet6_id(idx
->addr
, idx
->bitmask
);
915 subnet
=subnet_id(idx
->addr
, idx
->bitmask
);
917 printf("%d: %s/%d\n", ++i
, subnet
, idx
->bitmask
);
919 sprintf(str
,":post_%s - [0:0]", idx
->id
);
920 iptables_save_line(str
, idx
->ipv6
);
922 sprintf(str
,":forw_%s - [0:0]", idx
->id
);
923 iptables_save_line(str
, idx
->ipv6
);
925 for_each(interface
, interfaces
)
929 string(buf
, strlen(idx
->parent
->id
)+6);
930 sprintf(buf
, "%s_%s", interface
->idxprefix
, idx
->parent
->id
);
934 buf
= interface
->chain
;
937 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s_%s",
938 buf
, (interface
->is_upstream
?'s':'d'), subnet
, idx
->bitmask
, interface
->name
, interface
->idxprefix
, idx
->id
);
939 iptables_save_line(str
, idx
->ipv6
);
941 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s_common",
942 buf
, (interface
->is_upstream
?'s':'d'), subnet
, idx
->bitmask
, interface
->name
, interface
->idxprefix
);
943 iptables_save_line(str
, idx
->ipv6
);
946 printf("Total indexed iptables chains created: %d\n", i
);
948 for_each(interface
, interfaces
)
950 sprintf(str
,"-A %s -o %s -j %s_common", interface
->chain
, interface
->name
, interface
->idxprefix
);
951 iptables_save_line(str
, IPv4
);
954 sprintf(str
,"-A %s -o %s -j %s_common", interface
->chain
, interface
->name
, interface
->idxprefix
);
955 iptables_save_line(str
, IPv6
);
963 fclose(iptables_file
);
968 puts("Just flushed iptables and tc classes - now exiting ...");
974 if(!dry_run
&& !nodelay
&& qos_free_delay
)
976 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay
);
977 sleep(qos_free_delay
);
980 for_each(interface
, interfaces
)
982 sprintf(str
, "%s qdisc add dev %s root handle 1: htb r2q %d default 1",
983 tc
, interface
->name
, htb_r2q
);
986 sprintf(str
, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
987 tc
, interface
->name
, medium
, medium
, burst_main
, highest_priority
);
990 sprintf(str
, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
991 tc
, interface
->name
, interface
->speed
, interface
->speed
, burst_main
, highest_priority
);
996 /*-----------------------------------------------------------------*/
997 puts("Locating heavy downloaders and generating root classes ...");
998 /*-----------------------------------------------------------------*/
999 sort(ip
,ips
,desc_order_by
,traffic
);
1001 /*-----------------------------------------------------------------*/
1002 for_each(interface
, interfaces
)
1004 long long int rate
= interface
->speed
;
1005 long long int max
= interface
->speed
;
1006 int group_count
= 0;
1007 //obsolete: FILE *credit_file = NULL;
1009 //obsolete: if(!just_preview && !dry_run && enable_credit)
1011 //obsolete: credit_file = fopen(credit,"w");
1014 for_each(group
,groups
)
1018 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",
1019 tc
, interface
->name
, parent
, group
->id
, rate
, max
, burst_group
, highest_priority
+1, group
->desired
);
1023 if(group_count
++ < max_nesting
)
1028 rate
-= digital_divide
*group
->min
;
1029 if(rate
< group
->min
)
1034 /*shaping of aggresive downloaders, with credit file support */
1038 int group_rate = group->min, priority_sequence = lowest_priority;
1040 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
1042 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));
1043 if( ip->keyword->data_limit
1044 and not ip->fixedprio
1045 and ip->traffic > ip->realquota )
1047 if(group_rate < ip->max)
1049 ip->max = group_rate;
1051 group_rate+=magic_treshold;
1052 ip->prio=lowest_priority;
1053 if(ip->prio<highest_priority+2)
1055 ip->prio=highest_priority+2;
1060 if( ip->keyword->data_prio
1062 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1064 ip->prio=priority_sequence--;
1065 if(ip->prio<highest_priority+1)
1067 ip->prio=highest_priority+1;
1073 unsigned long long lcredit=0;
1075 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1077 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1079 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1088 fclose(credit_file);
1094 if(start_shaping
|| stop_shaping
|| reduce_ceil
)
1096 time_t how_much_seconds
= time(NULL
) - get_mtime(classmap
); /* sice start of daily aggregation session */
1097 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap
, how_much_seconds
);
1106 if_exists(ip
,ips
,eq(ip
->addr
,_
))
1108 int unshape_this_ip
= 0;
1109 long avg_mbps_down
= ip
->traffic_down
* 8 / how_much_seconds
;
1110 long avg_mbps_up
= ip
->traffic_up
* 8 / how_much_seconds
;
1111 int agreg
= 1, print_stats
= 1;
1113 if(ip
->keyword
->download_aggregation
)
1115 int min_mbps
= (ip
->min
/ip
->keyword
->download_aggregation
)>>10;
1121 if(min_mbps
<= avg_mbps_down
)
1123 unshape_this_ip
= 0;
1124 agreg
= (int)((float)(avg_mbps_down
+1)/min_mbps
+.5);
1126 ip
->pps_limit
/= agreg
;
1127 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg
, ip
->name
, min_mbps
, avg_mbps_down
);
1131 unshape_this_ip
= 1;
1134 else if(ip
->keyword
->upload_aggregation
)
1136 int min_mbps
= (ip
->min
/ip
->keyword
->upload_aggregation
)>>10;
1142 if(min_mbps
<= avg_mbps_up
)
1144 unshape_this_ip
= 0;
1145 agreg
= (int)((float)(avg_mbps_up
+1)/min_mbps
+.5);
1147 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg
, ip
->name
, min_mbps
, avg_mbps_up
);
1151 unshape_this_ip
= 1;
1156 unshape_this_ip
= 1;
1158 ip
->aggregated
= agreg
;
1159 ip
->mark
= atoi(ptr
);
1160 if(ip
->max
< ip
->desired
|| unshape_this_ip
|| reduce_ceil
) /* apply or disable FUP limit immediately.... */
1164 ip
->max
= ip
->desired
;
1165 if(stop_shaping
) /* all limits removed, but not printed with -s (start_shaping) switch */
1167 printf("Removing limit for %s (%s) ", ip
->name
, ip
->addr
);
1176 printf("Updating %s (%s) ", ip
->name
, ip
->addr
);
1179 ip
->max
= ip
->min
+ (ip
->desired
-ip
->min
)/reduce_ceil
;
1181 else if(ip
->max
< ip
->min
)
1186 for_each(interface
, interfaces
)
1188 if(!interface
->is_upstream
)
1192 printf("[down %s: %dk-%dk wants %d]", interface
->name
, ip
->min
, ip
->max
, ip
->desired
);
1194 sprintf(str
, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1195 tc
, interface
->name
, ip
->group
, ip
->mark
, ip
->min
, ip
->max
, burst
, ip
->prio
);
1202 printf("[up %s: %dk-%dk wants %dk]", interface
->name
, (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1203 (int)((ip
->desired
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1204 (int)((ip
->desired
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
));
1206 sprintf(str
,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1207 tc
, interface
->name
, ip
->group
, ip
->mark
,
1208 (int)((ip
->min
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
),
1209 (int)((ip
->max
/ip
->keyword
->asymetry_ratio
)-ip
->keyword
->asymetry_fixed
), burst
, ip
->prio
);
1224 puts("Warning - classmap file not fund, just generating preview ...");
1225 start_shaping
=FALSE
;
1228 done
; /* ugly macro end */
1231 json_traffic
=json_preview
;
1234 if(!dry_run
&& !just_flush
)
1236 /*-----------------------------------------------------------------*/
1237 printf("Writing json traffic overview %s ... ", json_traffic
);
1238 /*-----------------------------------------------------------------*/
1239 write_json_traffic(json_traffic
);
1241 /*-----------------------------------------------------------------*/
1242 printf("Writing statistics into HTML page %s ...\n", html
);
1243 /*-----------------------------------------------------------------*/
1244 write_htmlandlogs(html
, d
, total
, just_preview
);
1255 else if(reduce_ceil
)
1257 swchar
='0'+reduce_ceil
; /* -2, -4 */
1259 else if(stop_shaping
)
1264 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar
);
1270 printf("%-22s %-15s mark\n","name","ip");
1273 printf("Writing %s", classmap
);
1274 f
= fopen(classmap
, "w");
1280 /*-----------------------------------------------------------------*/
1281 printf(" + generating iptables and tc classes ... ");
1282 /*-----------------------------------------------------------------*/
1284 for_each(ip
, ips
) if(ip
->mark
> 0)
1286 for_each(interface
, interfaces
)
1292 duplicate(ip
->addr
,buf
);
1295 buf
=index6_id(ip
->addr
,64-idxtable_bitmask1
);
1299 buf
=index_id(ip
->addr
,32-idxtable_bitmask1
);
1302 string(chain
, 6+strlen(buf
));
1303 sprintf(chain
, "%s_", interface
->idxprefix
);
1310 chain
= interface
->chain
;
1313 /* packet limits - this will be optional in future */
1316 sprintf(limit_pkts
, "-m limit --limit %d/s --limit-burst %d ",
1317 ip
->pps_limit
, ip
->pps_limit
);
1325 printf("%-22s %-16s %04d %d/s\n", ip
->name
, ip
->addr
, ip
->mark
, ip
->pps_limit
);
1328 /* ------------------------------------------------ iptables classify */
1329 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s%d",
1330 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1331 interface
->name
, mark_iptables
, ip
->mark
);
1332 iptables_save_line(str
, ip
->v6
);
1334 sprintf(str
, "-A %s -%c %s/%d -o %s %s-j ACCEPT",
1335 chain
, (interface
->is_upstream
?'s':'d'),ip
->addr
, ip
->mask
,
1336 interface
->name
, limit_pkts
);
1337 iptables_save_line(str
, ip
->v6
);
1339 if(*limit_pkts
) /* non-empty string?*/
1341 /* classify overlimit packets to separate overlimit class */
1342 sprintf(str
, "-A %s -%c %s/%d -o %s -j %s%d",
1343 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1344 interface
->name
, mark_iptables
, OVERLIMIT_CLASS
);
1345 iptables_save_line(str
, ip
->v6
);
1347 sprintf(str
, "-A %s -%c %s/%d -o %s -j ACCEPT",
1348 chain
, (interface
->is_upstream
?'s':'d'), ip
->addr
, ip
->mask
,
1350 iptables_save_line(str
, ip
->v6
);
1355 //TODO - min and max should not exceed interface->speed
1357 /* -------------------------------------------------------- tc class */
1359 printf("[down: %dk-%dk]", ip
->min
, ip
->max
);
1362 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1363 tc
, interface
->name
, ip
->group
, ip
->mark
, ip
->min
, ip
->max
, burst
, ip
->prio
);
1366 if(strcmpi(ip
->keyword
->leaf_discipline
, "none"))
1368 sprintf(str
, "%s qdisc add dev %s parent 1:%d handle %d %s",
1369 tc
, interface
->name
, ip
->mark
, ip
->mark
, ip
->keyword
->leaf_discipline
); /*qos_leaf*/
1373 if(filter_type
== 1)
1375 sprintf(str
, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1376 tc
, interface
->name
, ip
->mark
, ip
->mark
);
1383 printf("(sharing %s)\n", ip
->sharing
);
1388 if(ip
->min
&& f
> 0)
1390 fprintf(f
, "%s %d\n", ip
->addr
, ip
->mark
);
1399 for_each(interface
, interfaces
)
1404 string(chain
, STRLEN
);
1405 sprintf(chain
, "%s_common", interface
->idxprefix
);
1409 chain
= interface
->chain
;
1414 final_chain
= "ACCEPT";
1416 sprintf(str
, "-A %s -o %s -j %s%d",
1417 chain
, interface
->name
, mark_iptables
, FREE_CLASS
);
1418 iptables_save_line(str
, IPv4
); /* only for IPv4 */
1421 sprintf(str
,"-A %s -o %s -j %s", chain
, interface
->name
, final_chain
);
1422 iptables_save_line(str
, IPv4
);
1425 sprintf(str
,"-A %s -o %s -j %s", chain
, interface
->name
, final_chain
);
1426 iptables_save_line(str
, IPv6
);
1429 if(free_min
) /* allocate free bandwith if it is not zero... */
1431 /*-----------------------------------------------------------------*/
1432 puts("Generating free bandwith class ...");
1433 /*-----------------------------------------------------------------*/
1434 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1435 tc
, interface
->name
, parent
, FREE_CLASS
, free_min
, free_max
,burst
, lowest_priority
);
1438 if(strcmpi(qos_leaf
, "none"))
1440 sprintf(str
,"%s qdisc add dev %s parent 1:%d handle %d %s", tc
, interface
->name
, FREE_CLASS
, FREE_CLASS
, qos_leaf
);
1443 /* tc handle 1 fw flowid */
1444 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
);
1447 /*-----------------------------------------------------------------*/
1448 puts("Generating bandwith class for overlimit packets...");
1449 /*-----------------------------------------------------------------*/
1450 sprintf(str
, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1451 tc
, interface
->name
, parent
, OVERLIMIT_CLASS
, overlimit_min
, overlimit_max
, burst
, lowest_priority
);
1454 printf("Total IP count: %d\n", i
);
1455 run_iptables_restore();
1461 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1462 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
This page took 1.237683 seconds and 4 git commands to generate.