-b Boot mode
[svn/Prometheus-QoS/.git] / prometheus.c
CommitLineData
068f0e75 1/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
b1a5c883 2/* Prometheus QoS - you can "steal fire" from your ISP */\r
3/* "fair-per-IP" quality of service (QoS) utility */\r
068f0e75 4/* requires Linux 2.4.x or 2.6.x with HTB support */\r
47b5fd64 5/* Copyright(C) 2005-2020 Michael Polak, Arachne Aerospace */\r
068f0e75 6/* iptables-restore support Copyright(C) 2007-2008 ludva */\r
7/* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */\r
8/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
9\r
5aca3d03 10/* Modified by: xChaos, 20231028\r
a031788f 11 ludva, 20080415\r
208112af 12 \r
007c44c5 13 Prometheus QoS is free software; you can redistribute it and/or\r
14 modify it under the terms of the GNU General Public License as \r
15 published by the Free Software Foundation; either version 2.1 of \r
16 the License, or (at your option) any later version.\r
17\r
18 Prometheus QoS is distributed in the hope that it will be useful,\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
21 General Public License for more details.\r
22\r
c9012978 23 You should have received a copy of the GNU General Public License\r
24 along with Prometheus Qos; if not, write to the Free Software\r
d1ae4fa7 25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \r
26 \r
c9012978 27 GNU General Public License is located in file COPYING */\r
007c44c5 28\r
208112af 29#include "cll1-0.6.2.h"\r
1c9cae56 30#include "ipstruct.h"\r
007c44c5 31\r
5aca3d03 32const char *version = "1.0.1";\r
007c44c5 33\r
068f0e75 34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
9f552e96 35/* Versions: 0.9.0 is development release, 1.0 will be "stable" */\r
068f0e75 36/* Official Trac URL: https://dev.arachne.cz/svn/prometheus */\r
37/* Official SVN URL: https://dev.arachne.cz/repos/prometheus */\r
38/* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */\r
39/* CZK donations account: 2900242944/2010 (transparent account) */\r
40/* Warning: unofficial Github mirror is not supported by author! */\r
41/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
77e71d6b 42\r
47b5fd64 43const 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";\r
2d114137 44\r
068f0e75 45#define STRLEN 512\r
46#undef DEBUG\r
47\r
82c702a1 48/* ======= All path names are defined here (for RPM patch) ======= */\r
ae776b10 49\r
f19d3cd0 50const char *tc = "/sbin/tc"; /* requires tc with HTB support */\r
51const char *iptables = "/sbin/iptables"; /* requires iptables utility */\r
52const char *ip6tables = "/sbin/ip6tables"; /* requires iptables utility */\r
53const char *iptablessave = "/sbin/iptables-save"; /* not yet required */\r
54const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */\r
55const char *ip6tablessave = "/sbin/ip6tables-save"; /* not yet required */\r
56const char *ip6tablesrestore = "/sbin/ip6tables-restore"; /* requires iptables-restore */\r
57const char *ls = "/bin/ls"; /* this is not user configurable :-) */\r
ae776b10 58\r
2d114137 59char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */\r
60char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */\r
bb5e7385 61char *macrosfile = "/etc/prometheus/prometheus.macros"; /* rewrite rules for most common tariffs */\r
9f552e96 62char *upstreamfile = "/etc/prometheus/upstream.interfaces"; /* list of interfaces to manage */\r
63char *downstreamfile = "/etc/prometheus/downstream.interfaces"; /* list of interfaces to manage */\r
20ae739c 64char *qosfreefile = "/etc/prometheus/qosfree.interfaces"; /* list of interfaces to manage */\r
2d114137 65char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/\r
47b5fd64 66char *iptablesdump = "/var/spool/prometheus.iptables-dump"; /* temporary file for iptables -L -v -x -n -t mangle */\r
f64d5431 67char *ip6tablesfile = "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/\r
2d114137 68char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */\r
be96b71b 69char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */\r
70char *html = "/var/www/traffic.html"; /* hall of fame - html version */\r
6fb3c58a 71char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */\r
1ab008b9 72char *json_traffic = "/var/www/logs/traffic.json"; /* hall of fame - json version */\r
6fb3c58a 73char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */\r
2d114137 74char *cmdlog = "/var/log/prometheuslog"; /* command log filename */\r
75char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */\r
8bcc3268 76char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */\r
2d114137 77char *html_log_dir = "/var/www/logs/html/";\r
ae776b10 78\r
6cc38f96 79char *jquery_url = "http://code.jquery.com/jquery-latest.js";\r
80char *lms_url = "/lms/?m=customerinfo&amp;id=";\r
9a56ab25 81int use_jquery_popups = TRUE;\r
9aa195f6 82int row_odd_even = 0; /*<tr class="odd/even"> */\r
b6fb849a 83 \r
007c44c5 84/* === Configuraration file values defaults - stored in global variables ==== */\r
85\r
43cde5c3 86int filter_type = 1; /*1 mark, 2 classify*/\r
0b9c3c19 87char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */\r
43cde5c3 88char *mark = "MARK";\r
89char *mark_iptables = "MARK --set-mark ";\r
5aca3d03 90int dry_run = FALSE; /* preview commands - use puts() instead of system() */\r
91int skip_stats = FALSE; /* skip generating statistics */\r
43cde5c3 92char *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]";\r
0995c4ad 93char *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";\r
43cde5c3 94FILE *iptables_file = NULL;\r
0b9c3c19 95FILE *ip6tables_file = NULL;\r
9a56ab25 96int enable_credit = TRUE; /* enable credit file */\r
97int use_credit = FALSE; /* use credit file (if enabled)*/\r
43cde5c3 98char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */\r
9a56ab25 99int hall_of_fame = TRUE; /* enable hall of fame */\r
9f552e96 100char *medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */\r
101//obsolete: char *lan = "eth0"; /* LAN interface */\r
102//obsolete: char *lan_medium = "1000Mbit"; /* 10Mbit/100Mbit ethernet */\r
f64d5431 103char *ip6prefix = NULL; /* Prefix for global /48 IPv6 subnet */\r
43cde5c3 104char *qos_leaf = "sfq perturb 5"; /* leaf discipline */\r
105char *qos_free_zone = NULL; /* QoS free zone */\r
421c0c00 106char *qos_free_dst_ipset = NULL; /* QoS free zone - dst match ipset name, must be prepared outside prometheus */\r
107char *qos_free_src_ipset = NULL; /* QoS free zone - src match ipset name, must be prepared outside prometheus */\r
7d05bfc0 108/* int qos_proxy = TRUE; include proxy port to QoS */\r
296d0585 109int found_code = FALSE; /* show links to users in LMS information system */\r
9a56ab25 110int include_upload = TRUE; /* upload+download=total traffic */\r
7ae5a593 111/* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */\r
112/* int proxy_port = 3128; proxy port number */\r
9f552e96 113//obsolete: long long int line = 1024; /* WAN/ISP download in kbps */\r
114//obsolete: long long int up = 1024; /* WAN/ISP upload in kbps */\r
0b9c3c19 115int free_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
116int free_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
73cf6e9d 117int overlimit_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
118int overlimit_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
43cde5c3 119int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */\r
120int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */ \r
fa54950d 121int max_nesting = 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */\r
5450cb41 122//obsolete: int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */\r
123int htb_quantum = 1514; /* MTU + ethernet header */\r
43cde5c3 124int burst = 8; /* HTB burst (in kbits) */\r
125int burst_main = 64;\r
126int burst_group = 32;\r
43cde5c3 127int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */\r
128int keywordcount = 0;\r
9a56ab25 129int class_count = 0;\r
130int ip_count = 0;\r
43cde5c3 131FILE *log_file = NULL;\r
132char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */\r
007c44c5 133\r
4deb2d6f 134const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */\r
135const int lowest_priority = 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */\r
136const int idxtable_treshold1 = 24; /* this is no longer configurable */\r
137const int idxtable_treshold2 = 12; /* this is no longer configurable */\r
138const int idxtable_bitmask1 = 3; /* this is no longer configurable */\r
139const int idxtable_bitmask2 = 3; /* this is no longer configurable */\r
007c44c5 140\r
af37be1d 141struct IP *ips = NULL, *networks = NULL, *ip, *sharedip;\r
1c9cae56 142struct Group *groups = NULL, *group;\r
bb5e7385 143struct Keyword *keyword, *defaultkeyword=NULL, *keywords = NULL;\r
144struct Macro *macro, *macros = NULL;\r
9f552e96 145struct Index *idxs = NULL, *idx, *metaindex;\r
146struct Interface *interfaces = NULL, *interface;\r
20ae739c 147struct QosFreeInterface *qosfreeinterfaces = NULL, *qosfreeinterface;\r
007c44c5 148\r
a25842fa 149#define FREE_CLASS 3\r
150#define OVERLIMIT_CLASS 4\r
151\r
068f0e75 152void help(void);\r
153/* implemented in help.c */
154\r
d7357b63 155void get_traffic_statistics(const char *whichiptables, int ipv6);\r
f19d3cd0 156/* implemented in parseiptables.c */\r
157\r
b6fb849a 158void parse_ip_log(int argc, char **argv);\r
1ab008b9 159/* implemented in parselog.c */\r
b6fb849a 160\r
161void parse_hosts(char *hosts);\r
1ab008b9 162/* implemented in parsehosts.c */\r
163\r
164void write_json_traffic(char *json);\r
165/* implemented in json.c */\r
b6fb849a 166\r
9a56ab25 167void write_htmlandlogs(char *html, char *d, int total, int just_preview);\r
168/* implemented in htmlandlogs.c */\r
169\r
af37be1d 170void analyse_topology(char *traceroute);\r
171/* implemented in networks.c */\r
172\r
dccb3227 173char *parse_datafile_line(char *str);\r
174/* implemented in utils.c */\r
175\r
176time_t get_mtime(const char *path);\r
177/* implemented in utils.c */\r
af37be1d 178\r
b6fb849a 179const char *tr_odd_even(void)\r
180{\r
181 row_odd_even = 1 - row_odd_even;\r
182 if(row_odd_even)\r
183 {\r
184 return "<tr class=\"even\">\n";\r
185 }\r
186 else\r
187 {\r
188 return "<tr class=\"odd\">\n";\r
189 }\r
190}\r
191\r
5b902402 192/* ====== iptables indexes are used to reduce complexity to log8(N) ===== */\r
007c44c5 193\r
59c3032e 194char *index_id(char *ip, int bitmask);\r
195/* function implemented in ipv4subnets.c */\r
007c44c5 196\r
59c3032e 197char *subnet_id(char *ip, int bitmask);\r
198/* function implemented in ipv4subnets.c */\r
007c44c5 199\r
0b9c3c19 200char *index6_id(char *ip, int bitmask);\r
201/* function implemented in ipv6subnets.c */\r
202\r
203char *subnet6_id(char *ip, int bitmask);\r
204/* function implemented in ipv6subnets.c */\r
205\r
59c3032e 206/* ================= Let's parse configuration file here ================ */\r
007c44c5 207\r
208void reject_config_and_exit(char *filename)\r
209{\r
210 printf("Configuration file %s rejected - abnormal exit.",filename);\r
211 exit(-1);\r
212}\r
213\r
214void get_config(char *config_filename)\r
215{\r
216 char *cnf="mark";\r
217 \r
218 printf("Configured keywords: ");\r
219 parse(config_filename)\r
220 {\r
221 option("keyword",kwd);\r
222 if(kwd)\r
223 {\r
224 printf("%s ",kwd);\r
225\r
226 create(keyword,Keyword);\r
73cf6e9d 227 keyword->key = kwd;\r
228 keyword->asymetry_ratio = 1; /* ratio for ADSL-like upload */\r
229 keyword->asymetry_fixed = 0; /* fixed treshold for ADSL-like upload */\r
230 keyword->data_limit = 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
231 keyword->data_prio = 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
232 keyword->fixed_limit = 0; /* fixed data limit for setting lower HTB ceil */\r
233 keyword->fixed_prio = 0; /* fixed data limit for setting lower HTB prio */\r
234 keyword->reserve_min = 8; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
235 keyword->reserve_max = 0; /* malus for nominal HTB ceil (in kbps) */\r
236 keyword->default_prio = highest_priority+1;\r
dccb3227 237 keyword->download_aggregation = keyword->upload_aggregation = 0; /* disable by default */\r
73cf6e9d 238 keyword->html_color = "000000";\r
239 keyword->ip_count = 0;\r
240 keyword->leaf_discipline = "";\r
241 keyword->allowed_avgmtu = 0;\r
007c44c5 242\r
bb5e7385 243 push(keyword, keywords);\r
4d41c1e4 244 if(!defaultkeyword)\r
245 {\r
73cf6e9d 246 defaultkeyword = keyword;\r
4d41c1e4 247 }\r
007c44c5 248 keywordcount++;\r
249 \r
250 kwd=NULL;\r
251 }\r
208112af 252 else\r
007c44c5 253 {\r
208112af 254 for_each(keyword,keywords)\r
255 {\r
256 int l=strlen(keyword->key);\r
007c44c5 257\r
208112af 258 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)\r
259 {\r
260 char *tmptr=_; /* <---- l+1 ----> */\r
261 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */\r
64b2d125 262 foption("asymetry-ratio", keyword->asymetry_ratio);\r
73cf6e9d 263 ioption("asymetry-treshold", keyword->asymetry_fixed);\r
264 ioption("magic-relative-limit", keyword->data_limit);\r
265 ioption("magic-relative-prio", keyword->data_prio);\r
266 loption("magic-fixed-limit", keyword->fixed_limit);\r
267 loption("magic-fixed-prio", keyword->fixed_prio);\r
268 ioption("htb-default-prio", keyword->default_prio);\r
269 ioption("htb-rate-bonus", keyword->reserve_min);\r
270 ioption("htb-ceil-malus", keyword->reserve_max);\r
dccb3227 271 ioption("download-aggregation", keyword->download_aggregation);\r
272 ioption("upload-aggregation", keyword->upload_aggregation);\r
73cf6e9d 273 option("leaf-discipline", keyword->leaf_discipline);\r
274 option("html-color", keyword->html_color);\r
275 ioption("allowed-avgmtu" ,keyword->allowed_avgmtu);\r
208112af 276 _=tmptr;\r
277 \r
278 if(keyword->data_limit || keyword->fixed_limit || \r
279 keyword->data_prio || keyword->fixed_prio)\r
bb9e11ee 280 {\r
281 use_credit=1; \r
282 }\r
208112af 283 }\r
284 }\r
007c44c5 285 }\r
286\r
287 option("tc",tc);\r
288 option("iptables",iptables);\r
f64d5431 289 option("iptables-save",iptablessave);\r
290 option("iptables-restore",iptablesrestore);\r
f19d3cd0 291 option("ip6tables",ip6tables);\r
f64d5431 292 option("ip6tables-save",ip6tablessave);\r
293 option("ip6tables-restore",ip6tablesrestore);\r
294 option("iptables-in-filename",iptablesfile);\r
47b5fd64 295 option("iptables-dump-filename",iptablesdump);\r
f64d5431 296 option("ip6tables-in-filename",ip6tablesfile);\r
007c44c5 297 option("hosts",hosts);\r
9f552e96 298 option("downstream-interfaces-list-filename",downstreamfile);\r
299 option("upstream-interfaces-list-filename",upstreamfile);\r
20ae739c 300 option("qos-free-interfaces-list-filename",qosfreefile);\r
00e9928c 301 option("macros-filename",macrosfile);\r
f64d5431 302 option("ip6-prefix",ip6prefix);\r
9f552e96 303 option("medium",medium);\r
007c44c5 304 ioption("hall-of-fame-enable",hall_of_fame);\r
d1dd0f04 305 ioption("digital-divide-weirdness-ratio",digital_divide);\r
007c44c5 306 option("hall-of-fame-title",title);\r
307 option("hall-of-fame-filename",html);\r
1ab008b9 308 option("json-filename",json_traffic);\r
007c44c5 309 option("hall-of-fame-preview",preview);\r
6fb3c58a 310 option("json-preview",json_preview);\r
007c44c5 311 option("log-filename",cmdlog);\r
312 option("credit-filename",credit);\r
be96b71b 313 option("classmap-filename",classmap);\r
007c44c5 314 ioption("credit-enable",enable_credit);\r
315 option("log-traffic-directory",log_dir);\r
5b902402 316 option("log-traffic-html-directory",html_log_dir);\r
007c44c5 317 option("log-traffic-url-path",log_url);\r
6cc38f96 318 option("jquery-url",jquery_url);\r
319 option("lms-url",lms_url);\r
320 ioption("use-jquery-popups",use_jquery_popups);\r
007c44c5 321 option("qos-free-zone",qos_free_zone);\r
421c0c00 322 option("qos-free-dst-ipset",qos_free_dst_ipset);\r
323 option("qos-free-src-ipset",qos_free_src_ipset);\r
007c44c5 324 ioption("qos-free-delay",qos_free_delay);\r
7d05bfc0 325/* ioption("qos-proxy-enable",qos_proxy); */\r
7ae5a593 326/* option("qos-proxy-ip",proxy_ip);*/\r
007c44c5 327 option("htb-leaf-discipline",qos_leaf);\r
7ae5a593 328/* ioption("qos-proxy-port",proxy_port); */\r
007c44c5 329 ioption("free-rate",free_min);\r
330 ioption("free-ceil",free_max);\r
73cf6e9d 331 ioption("overlimit-rate",overlimit_min);\r
332 ioption("overlimit-ceil",overlimit_max);\r
007c44c5 333 ioption("htb-burst",burst);\r
334 ioption("htb-burst-main",burst_main);\r
335 ioption("htb-burst-group",burst_group);\r
336 ioption("htb-nesting-limit",max_nesting);\r
5450cb41 337 ioption("htb-quantum",htb_quantum);\r
007c44c5 338 ioption("magic-include-upload",include_upload);\r
5b902402 339 ioption("magic-treshold",magic_treshold); \r
260c2719 340 option("filter-type", cnf); \r
007c44c5 341/* not yet implemented:\r
342 ioption("magic-fixed-packets",fixed_packets);\r
343 ioption("magic-relative-packets",packet_limit);\r
344*/\r
345 }\r
346 fail\r
347 { \r
348 perror(config_filename);\r
349 puts("Warning - using built-in defaults instead ...");\r
350 }\r
8e29188a 351 done; /* ugly macro end */\r
007c44c5 352 printf("\n");\r
353 \r
be96b71b 354 /* leaf discipline for keywords */\r
208112af 355 for_each(keyword,keywords)\r
007c44c5 356 {\r
af37be1d 357 if(!strcmpi(keyword->leaf_discipline, ""))\r
358 {\r
359 keyword->leaf_discipline = qos_leaf;\r
360 }\r
007c44c5 361 }\r
362\r
260c2719 363 if(strcmpi(cnf, "mark"))\r
bb9e11ee 364 {\r
365 filter_type = 2;\r
366 mark = "CLASSIFY";\r
367 mark_iptables = "CLASSIFY --set-class 1:";\r
368 }\r
369 else\r
370 {\r
371 filter_type = 1;\r
372 mark = "MARK";\r
373 mark_iptables = "MARK --set-mark ";\r
007c44c5 374 }\r
007c44c5 375}\r
376\r
007c44c5 377 \r
5450cb41 378/* ========== This function executes, logs or also prints command ========== */\r
007c44c5 379\r
380void safe_run(char *cmd)\r
381{\r
a1d21464 382 if(dry_run)\r
383 {\r
384 printf("\n=>%s\n",cmd);\r
385 }\r
386 else\r
387 {\r
4deb2d6f 388 system(cmd);\r
a1d21464 389 }\r
4deb2d6f 390 if(log_file)\r
a1d21464 391 {\r
392 fprintf(log_file,"%s\n",cmd);\r
393 }\r
007c44c5 394}\r
395\r
0b9c3c19 396void iptables_save_line(char *line, int ipv6)\r
dba7666b 397{\r
0b9c3c19 398 if(ipv6)\r
399 {\r
4deb2d6f 400 fprintf(ip6tables_file,"%s\n",line);\r
0b9c3c19 401 }\r
402 else\r
403 {\r
4deb2d6f 404 fprintf(iptables_file,"%s\n",line);\r
0b9c3c19 405 }\r
007c44c5 406}\r
407\r
1a2ab32b 408#define IPv4 FALSE\r
409#define IPv6 TRUE\r
410\r
411\r
0b9c3c19 412void run_iptables_restore(void)\r
007c44c5 413{\r
5da44508 414 char *restor;\r
9f552e96 415 string(restor, STRLEN);\r
abe9b855 416\r
417 /*-----------------------------------------------------------------*/\r
1c004f15 418 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
abe9b855 419 /*-----------------------------------------------------------------*/\r
0b9c3c19 420\r
1a2ab32b 421 iptables_save_line("COMMIT", IPv4);\r
007c44c5 422 fclose(iptables_file);\r
ae776b10 423 if(dry_run) \r
424 {\r
a1d21464 425 parse(iptablesfile)\r
426 {\r
427 printf("%s\n",_);\r
428 }\r
8e29188a 429 done; /* ugly macro end */\r
ae776b10 430 }\r
431\r
432 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
433 safe_run(restor);\r
0b9c3c19 434\r
435 if(ip6prefix)\r
436 {\r
437 /*-----------------------------------------------------------------*/\r
438 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
439 /*-----------------------------------------------------------------*/\r
1a2ab32b 440 iptables_save_line("COMMIT", IPv6);\r
0b9c3c19 441 fclose(ip6tables_file);\r
442 if(dry_run) \r
443 {\r
444 parse(ip6tablesfile)\r
445 {\r
446 printf("%s\n",_);\r
447 }\r
448 done; /* ugly macro end */\r
449 }\r
450 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
451 safe_run(restor);\r
452 }\r
007c44c5 453 free(restor);\r
454}\r
455\r
dccb3227 456/**/\r
007c44c5 457\r
dccb3227 458char *parse_datafile_line(char *str);\r
459time_t get_mtime(const char *path);\r
5b902402 460\r
007c44c5 461/*-----------------------------------------------------------------*/\r
493e1ccd 462/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
007c44c5 463/*-----------------------------------------------------------------*/\r
464\r
465program\r
466{\r
8e29188a 467 int i=0; /* just plain old Fortran style integer :-) */\r
468 FILE *f=NULL; /* everything is just stream of bytes... */\r
469 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
c38473c1 470 char *substring, *limit_pkts;\r
1c9cae56 471\r
9a56ab25 472 int parent = 1;\r
af37be1d 473 int just_networks = FALSE; \r
9a56ab25 474 int just_flush = FALSE; /* deactivates all previous actions */\r
475 int nodelay = FALSE;\r
476 int just_preview = FALSE; /* preview - generate just stats */\r
477 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
62b118c2 478 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
4deb2d6f 479 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
9a56ab25 480 int just_logs = FALSE; /* just parse logs */\r
481 int run = FALSE;\r
482 int total = 0;\r
33ec95ab 483 \r
007c44c5 484 char *althosts=NULL;\r
485 \r
486 printf("\n\\r
487Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
4deb2d6f 488Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\\r
43cde5c3 489iptables-restore & burst tunning & classify modification by Ludva\n\\r
0d5026c6 490Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
007c44c5 491\r
8e29188a 492 /*----- Boring... we have to check command line options first: ----*/ \r
007c44c5 493 arguments\r
494 {\r
495 argument("-c") { nextargument(config); }\r
496 argument("-h") { nextargument(althosts);}\r
4deb2d6f 497 argument("-d") { run=TRUE; dry_run=TRUE; }\r
498 argument("-f") { run=TRUE; just_flush=TRUE; }\r
499 argument("-9") { run=TRUE; just_flush=9; }\r
500 argument("-p") { run=TRUE; just_preview=TRUE; }\r
501 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
502 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
503 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
504 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
505 argument("-r") { run=TRUE; }\r
506 argument("-n") { run=TRUE; nodelay=TRUE; }\r
5aca3d03 507 argument("-b") { run=TRUE; nodelay=TRUE; skip_stats=TRUE; }\r
4deb2d6f 508 argument("-a") { run=TRUE; just_networks=TRUE; }\r
509 argument("-l") { just_logs=TRUE; }\r
510 argument("-m") { just_logs=TRUE; }\r
511 argument("-y") { just_logs=TRUE; }\r
007c44c5 512 argument("-?") { help(); exit(0); }\r
513 argument("--help") { help(); exit(0); }\r
514 argument("-v") { exit(0); } \r
515 argument("--version") { exit(0); } \r
516 }\r
208112af 517 \r
007c44c5 518 if(dry_run)\r
208112af 519 {\r
007c44c5 520 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
208112af 521 }\r
007c44c5 522\r
208112af 523 date(d); /* this is typical cll1.h macro - prints current date */\r
007c44c5 524\r
525 /*-----------------------------------------------------------------*/\r
526 printf("Parsing configuration file %s ...\n", config);\r
527 /*-----------------------------------------------------------------*/\r
528 get_config(config);\r
9f552e96 529 /*-----------------------------------------------------------------*/\r
530 printf("Parsing upstream interfaces list %s ...\n", upstreamfile);\r
531 /*-----------------------------------------------------------------*/\r
532 parse(upstreamfile)\r
533 {\r
534 ptr = parse_datafile_line(_);\r
535 if(ptr)\r
536 {\r
537 create(interface, Interface);\r
538 interface->name = _;\r
539 interface->speed = (long long)atol(ptr);\r
540 /* is supplied value meaningful ?*/\r
541 if(interface->speed <= 0)\r
542 {\r
543 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
544 reject_config_and_exit(upstreamfile);\r
545 }\r
546 interface->is_upstream = TRUE;\r
547 interface->chain = "FORWARD";\r
548 interface->idxprefix = "forw";\r
549 push(interface, interfaces);\r
5aca3d03 550 printf("Upstream interface %s: medium %s capacity %Ld kbps\n", interface->name, medium, interface->speed);\r
9f552e96 551 }\r
552 }\r
553 done; /* ugly macro end */\r
554\r
555 /*-----------------------------------------------------------------*/\r
556 printf("Parsing downstream interfaces list %s ...\n", downstreamfile);\r
557 /*-----------------------------------------------------------------*/\r
00e9928c 558 parse(downstreamfile)\r
9f552e96 559 {\r
560 ptr = parse_datafile_line(_);\r
561 if(ptr)\r
562 {\r
563 create(interface, Interface);\r
564 interface->name = _;\r
565 interface->speed = (long long)atol(ptr);\r
566 /* is supplied value meaningful ?*/\r
567 if(interface->speed <= 0)\r
568 {\r
569 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
570 reject_config_and_exit(downstreamfile);\r
571 }\r
572 interface->is_upstream = FALSE;\r
573 interface->chain = "POSTROUTING";\r
574 interface->idxprefix = "post";\r
575 push(interface, interfaces);\r
5aca3d03 576 printf("Downstream interface %s: medium %s capacity %Ld kbps\n", interface->name, medium, interface->speed);\r
9f552e96 577 }\r
578 }\r
579 done; /* ugly macro end */\r
c9012978 580 \r
33ec95ab 581 if(just_logs)\r
c9012978 582 {\r
208112af 583 parse_ip_log(argc,argv);\r
584 exit(0);\r
585 }\r
586 else if(not run)\r
587 {\r
588 help();\r
589 exit(0);\r
c9012978 590 }\r
007c44c5 591\r
208112af 592 if(althosts)\r
593 {\r
af37be1d 594 hosts = althosts;\r
208112af 595 }\r
007c44c5 596\r
5aca3d03 597 if(just_flush<9 && !skip_stats)\r
007c44c5 598 {\r
599 /*-----------------------------------------------------------------*/\r
600 puts("Parsing iptables verbose output ...");\r
601 /*-----------------------------------------------------------------*/\r
d7357b63 602 get_traffic_statistics(iptables, FALSE);\r
0b9c3c19 603 if(ip6prefix)\r
604 {\r
605 /*-----------------------------------------------------------------*/\r
606 puts("Parsing ip6tables verbose output ...");\r
607 /*-----------------------------------------------------------------*/ \r
d7357b63 608 get_traffic_statistics(ip6tables, TRUE);\r
0b9c3c19 609 }\r
007c44c5 610 }\r
611\r
612 /*-----------------------------------------------------------------*/\r
af37be1d 613 /* cll1.h - let's allocate brand new character buffer... */\r
007c44c5 614 /*-----------------------------------------------------------------*/\r
c38473c1 615 string(str, STRLEN); \r
616 string(limit_pkts, STRLEN);\r
007c44c5 617\r
20ae739c 618 /*-----------------------------------------------------------------*/\r
619 printf("Parsing qos free interfaces file %s ...\n", qosfreefile);\r
620 /*-----------------------------------------------------------------*/\r
621 load(qosfreeinterface, qosfreeinterfaces,\r
622 qosfreefile, QosFreeInterface, name);\r
623\r
8dcd2b4c 624 /*-----------------------------------------------------------------*/\r
625 printf("Parsing macro definition file %s ...\n", macrosfile);\r
626 /*-----------------------------------------------------------------*/\r
627 parse(macrosfile)\r
628 {\r
629 ptr = parse_datafile_line(_);\r
630 if(ptr)\r
631 {\r
632 create(macro, Macro);\r
633 macro->rewrite_from = _;\r
634 macro->rewrite_to = ptr;\r
635 push(macro, macros);\r
636 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
637 }\r
638 }\r
639 done; /* ugly macro end */\r
640\r
4deb2d6f 641\r
642\r
007c44c5 643 /*-----------------------------------------------------------------*/\r
af37be1d 644 printf("Parsing class defintion file %s ...\n", hosts);\r
007c44c5 645 /*-----------------------------------------------------------------*/\r
af37be1d 646 parse_hosts(hosts);\r
47b5fd64 647\r
648#ifdef MONITORINGTRHU_CTU\r
649//special hack only to generate certain required CSV statistics for www.ctu.cz (regulation body)\r
650//not required for everyday use, requires special syntax sugar in hosts file, see parsehosts.c\r
651 for_each(technology, technologies)\r
af37be1d 652 {\r
47b5fd64 653 char *filename;\r
654 FILE *f;\r
655 string(filename, strlen(log_dir) + strlen(technology->filename) + 5);\r
364980f0 656 strcpy(filename, log_dir);\r
47b5fd64 657 strcat(filename, technology->filename); \r
658 strcat(filename, ".csv");\r
659 /*-----------------------------------------------------------------*/\r
660 printf("Writing report file %s ...\n", filename);\r
661 /*-----------------------------------------------------------------*/\r
662 f = fopen(filename, "w");\r
663 if(f)\r
664 {\r
665 for_each(ip, ips) if(eq(technology->filename, ip->technology_str))\r
666 {\r
296d0585 667 fprintf(f,"%s,%s,%d\n", ip->code, ip->ruian_id_str, ip->max);\r
47b5fd64 668 }\r
669 fclose(f);\r
670 }\r
671 else\r
672 perror(filename); \r
673 } \r
674#endif\r
007c44c5 675\r
676 /*-----------------------------------------------------------------*/\r
677 puts("Resolving shared connections ...");\r
678 /*-----------------------------------------------------------------*/\r
af37be1d 679 for_each(ip, ips) if(ip->sharing)\r
007c44c5 680 {\r
af37be1d 681 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
007c44c5 682 {\r
b1a5c883 683 sharedip->traffic += ip->traffic;\r
bf59a20b 684 sharedip->traffic_down += ip->direct;\r
685 sharedip->traffic_up += ip->upload;\r
b1a5c883 686 ip->traffic = 0;\r
687 ip->mark = sharedip->mark; \r
296d0585 688 ip->code = sharedip->code;\r
c38473c1 689 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
64b2d125 690\r
691 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
692 ptr = strchr(ip->addr, '+');\r
693 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
694 {\r
695 *(--ptr) = 0;\r
696 concatenate(ip->addr, sharedip->addr, ptr);\r
697 ip->name = ip->addr = ptr;\r
698 ptr = strchr(ip->addr, '.');\r
699 while(ptr && *ptr)\r
700 {\r
701 *ptr = ':';\r
702 ptr = strchr(ptr, '.');\r
703 }\r
704 ip->mask += 64;\r
705 }\r
706\r
007c44c5 707 break;\r
708 }\r
1c9cae56 709 if(not sharedip)\r
bb9e11ee 710 {\r
260c2719 711 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
712 ip->addr, ip->name, ip->sharing);\r
bb9e11ee 713 }\r
007c44c5 714 }\r
715\r
4deb2d6f 716 if(enable_credit && just_flush<9)\r
007c44c5 717 {\r
718 /*-----------------------------------------------------------------*/\r
719 printf("Parsing credit file %s ...\n", credit);\r
720 /*-----------------------------------------------------------------*/\r
721 parse(credit)\r
722 {\r
bb5e7385 723 ptr = parse_datafile_line(_);\r
007c44c5 724 if(ptr)\r
725 {\r
208112af 726 if_exists(ip,ips,eq(ip->addr,_))\r
727 {\r
007c44c5 728 sscanf(ptr,"%Lu",&(ip->credit));\r
208112af 729 }\r
007c44c5 730 }\r
731 }\r
8e29188a 732 done; /* ugly macro end */\r
007c44c5 733 }\r
734\r
bb5e7385 735\r
dba7666b 736 if(!just_preview)\r
007c44c5 737 {\r
4deb2d6f 738 /*-----------------------------------------------------------------*/\r
739 puts("Initializing iptables and tc classes ...");\r
740 /*-----------------------------------------------------------------*/\r
dba7666b 741 \r
4deb2d6f 742 iptables_file = fopen(iptablesfile, "w");\r
743 if(iptables_file == NULL)\r
744 {\r
f64d5431 745 perror(iptablesfile);\r
007c44c5 746 exit(-1);\r
4deb2d6f 747 }\r
748 iptables_save_line(iptablespreamble, IPv4);\r
0b9c3c19 749\r
4deb2d6f 750 if(ip6prefix)\r
751 {\r
752 ip6tables_file = fopen(ip6tablesfile, "w");\r
753 if(ip6tables_file == NULL)\r
0b9c3c19 754 {\r
4deb2d6f 755 perror(ip6tablesfile);\r
756 exit(-1);\r
0b9c3c19 757 }\r
4deb2d6f 758 iptables_save_line(iptablespreamble, IPv6);\r
759 iptables_save_line(ip6preamble, IPv6);\r
dba7666b 760 }\r
4deb2d6f 761\r
762 run_iptables_restore();\r
007c44c5 763 \r
4deb2d6f 764 log_file = fopen(cmdlog, "w");\r
260c2719 765 if(log_file == NULL) \r
bb9e11ee 766 {\r
f64d5431 767 perror(cmdlog);\r
007c44c5 768 exit(-1);\r
ca6f7e80 769 } \r
007c44c5 770 \r
9f552e96 771 for_each(interface, interfaces)\r
772 {\r
773 sprintf(str,"%s qdisc del dev %s root 2>/dev/null", tc, interface->name);\r
774 safe_run(str);\r
775 }\r
4deb2d6f 776 \r
777 iptables_file=fopen(iptablesfile,"w");\r
778 iptables_save_line(iptablespreamble, IPv4);\r
779 if(ip6prefix)\r
780 {\r
781 ip6tables_file=fopen(ip6tablesfile,"w");\r
782 iptables_save_line(iptablespreamble, IPv6);\r
783 iptables_save_line(ip6preamble, IPv6);\r
0b9c3c19 784 }\r
007c44c5 785\r
296d0585 786 /* this doesn't seem to be way to go... about 2/3 of all packets have ACK flag set\r
787 maybe with --length 40:100 it would make some sense, but not enought \r
788 for_each(interface, interfaces)\r
789 {\r
790 sprintf(str,"-A %s -m tcp -p tcp --tcp-flags ACK ACK -o %s -j ACCEPT", interface->chain, interface->name);\r
791 iptables_save_line(str, IPv4);\r
792 }\r
793 */\r
794\r
421c0c00 795 if(qos_free_zone && *qos_free_zone != '0') /* this is currently supported only for IPv4 */\r
007c44c5 796 {\r
9f552e96 797 for_each(interface, interfaces)\r
007c44c5 798 {\r
c5a58cd4 799 sprintf(str,"-A %s -%c %s -o %s -j ACCEPT", interface->chain, (interface->is_upstream?'d':'s'), qos_free_zone, interface->name);\r
1a2ab32b 800 iptables_save_line(str, IPv4);\r
007c44c5 801 }\r
007c44c5 802 }\r
421c0c00 803\r
804 if(qos_free_dst_ipset && *qos_free_dst_ipset != '0') /* this is currently supported only for IPv4 */\r
805 {\r
806 for_each(interface, interfaces)\r
807 {\r
84245208 808 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);\r
421c0c00 809 iptables_save_line(str, IPv4);\r
810 }\r
811 }\r
812\r
813 if(qos_free_src_ipset && *qos_free_src_ipset != '0') /* this is currently supported only for IPv4 */\r
814 {\r
815 for_each(interface, interfaces)\r
816 {\r
84245208 817 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);\r
421c0c00 818 iptables_save_line(str, IPv4);\r
819 }\r
820 }\r
007c44c5 821 \r
20ae739c 822 for_each(qosfreeinterface, qosfreeinterfaces)\r
823 {\r
824 sprintf(str,"-A FORWARD -i %s -j ACCEPT", qosfreeinterface->name);\r
825 iptables_save_line(str, IPv4); \r
826 iptables_save_line(str, IPv6);\r
827 sprintf(str,"-A POSTROUTING -o %s -j ACCEPT", qosfreeinterface->name);\r
828 iptables_save_line(str, IPv4);\r
829 iptables_save_line(str, IPv6);\r
830 }\r
831 \r
f64d5431 832 if(ip_count > idxtable_treshold1 && !just_flush)\r
007c44c5 833 {\r
0b9c3c19 834 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
e0161edb 835 char *subnet, *buf;\r
007c44c5 836 /*-----------------------------------------------------------------*/\r
837 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
838 /*-----------------------------------------------------------------*/\r
839\r
1a2ab32b 840 iptables_save_line(":post_common - [0:0]", IPv4);\r
841 iptables_save_line(":forw_common - [0:0]", IPv4);\r
0b9c3c19 842 if(ip6prefix)\r
843 {\r
1a2ab32b 844 iptables_save_line(":post_common - [0:0]", IPv6);\r
845 iptables_save_line(":forw_common - [0:0]", IPv6);\r
0b9c3c19 846 }\r
007c44c5 847\r
0b9c3c19 848 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
007c44c5 849 {\r
0b9c3c19 850 if(ip->v6)\r
851 {\r
852 buf=index6_id(ip->addr,bitmask+32);\r
853 }\r
854 else\r
855 {\r
856 buf=index_id(ip->addr, bitmask);\r
857 }\r
858 \r
208112af 859 if_exists(idx,idxs,eq(idx->id,buf))\r
860 {\r
007c44c5 861 idx->children++;\r
208112af 862 }\r
007c44c5 863 else\r
864 {\r
865 create(idx,Index);\r
0b9c3c19 866 idx->addr = ip->addr;\r
867 idx->id = buf;\r
868 idx->bitmask = bitmask+32*ip->v6;\r
869 idx->parent = NULL;\r
870 idx->children = 0;\r
871 idx->ipv6 = ip->v6;\r
007c44c5 872 idxcount++;\r
873 push(idx,idxs);\r
874 }\r
875 }\r
876\r
877 /* brutal perfomance optimalization */\r
f64d5431 878 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
007c44c5 879 {\r
f64d5431 880 bitmask -= idxtable_bitmask2;\r
881 idxcount = 0;\r
208112af 882\r
6cc38f96 883 for_each(idx,idxs) if(idx->parent == NULL)\r
007c44c5 884 {\r
0b9c3c19 885 if(idx->ipv6)\r
886 {\r
887 buf = index6_id(idx->addr, bitmask+32);\r
888 }\r
889 else\r
890 {\r
891 buf = index_id(idx->addr, bitmask);\r
892 }\r
208112af 893 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
894 {\r
895 metaindex->children++;\r
896 }\r
007c44c5 897 else\r
898 {\r
899 create(metaindex,Index);\r
0b9c3c19 900 metaindex->addr = idx->addr;\r
901 metaindex->id = buf;\r
902 metaindex->bitmask = bitmask+32*idx->ipv6;\r
903 metaindex->parent = NULL;\r
904 metaindex->children = 0;\r
905 metaindex->ipv6 = idx->ipv6;\r
007c44c5 906 idxcount++;\r
907 push(metaindex,idxs);\r
908 }\r
909 idx->parent=metaindex;\r
910 }\r
911 }\r
912\r
f64d5431 913 /* this should slightly optimize throughput ... */\r
007c44c5 914 sort(idx,idxs,desc_order_by,children);\r
915 sort(idx,idxs,order_by,bitmask);\r
916\r
917 i=0;\r
9f552e96 918 for_each(idx, idxs)\r
007c44c5 919 {\r
0b9c3c19 920 if(idx->ipv6)\r
921 {\r
922 subnet=subnet6_id(idx->addr, idx->bitmask);\r
923 }\r
924 else\r
925 {\r
926 subnet=subnet_id(idx->addr, idx->bitmask);\r
927 }\r
928 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
007c44c5 929 \r
930 sprintf(str,":post_%s - [0:0]", idx->id);\r
0b9c3c19 931 iptables_save_line(str, idx->ipv6);\r
007c44c5 932\r
933 sprintf(str,":forw_%s - [0:0]", idx->id);\r
0b9c3c19 934 iptables_save_line(str, idx->ipv6);\r
007c44c5 935\r
9f552e96 936 for_each(interface, interfaces)\r
bb9e11ee 937 {\r
9f552e96 938 if(idx->parent)\r
939 {\r
940 string(buf, strlen(idx->parent->id)+6);\r
941 sprintf(buf, "%s_%s", interface->idxprefix, idx->parent->id);\r
942 }\r
943 else\r
944 {\r
945 buf = interface->chain;\r
946 }\r
007c44c5 947\r
c5a58cd4 948 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_%s", \r
949 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix, idx->id);\r
9f552e96 950 iptables_save_line(str, idx->ipv6);\r
007c44c5 951\r
c5a58cd4 952 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_common",\r
953 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix);\r
9f552e96 954 iptables_save_line(str, idx->ipv6);\r
bb9e11ee 955 }\r
007c44c5 956 }\r
957 printf("Total indexed iptables chains created: %d\n", i);\r
958\r
9f552e96 959 for_each(interface, interfaces)\r
0b9c3c19 960 {\r
9f552e96 961 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
1a2ab32b 962 iptables_save_line(str, IPv4);\r
9f552e96 963 if(ip6prefix)\r
964 {\r
965 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
1a2ab32b 966 iptables_save_line(str, IPv6);\r
9f552e96 967 }\r
0b9c3c19 968 }\r
007c44c5 969 }\r
007c44c5 970 }\r
971\r
972 if(just_flush)\r
973 {\r
974 fclose(iptables_file);\r
add90548 975 if(log_file)\r
976 { \r
977 fclose(log_file);\r
978 }\r
007c44c5 979 puts("Just flushed iptables and tc classes - now exiting ...");\r
980 exit(0);\r
981 }\r
982\r
4deb2d6f 983 if(!just_preview)\r
007c44c5 984 {\r
985 if(!dry_run && !nodelay && qos_free_delay)\r
986 {\r
9f552e96 987 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay);\r
007c44c5 988 sleep(qos_free_delay);\r
989 }\r
990\r
9f552e96 991 for_each(interface, interfaces)\r
992 {\r
5450cb41 993 sprintf(str, "%s qdisc add dev %s root handle 1: htb default 1",\r
994 tc, interface->name);\r
9f552e96 995 safe_run(str);\r
007c44c5 996\r
5450cb41 997 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d quantum %d",\r
998 tc, interface->name, medium, medium, burst_main, highest_priority, htb_quantum);\r
9f552e96 999 safe_run(str);\r
007c44c5 1000\r
5450cb41 1001 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d quantum %d",\r
1002 tc, interface->name, interface->speed, interface->speed, burst_main, highest_priority, htb_quantum);\r
9f552e96 1003 safe_run(str);\r
1004 }\r
007c44c5 1005 }\r
1006\r
4deb2d6f 1007 /*-----------------------------------------------------------------*/\r
1008 puts("Locating heavy downloaders and generating root classes ...");\r
1009 /*-----------------------------------------------------------------*/\r
1010 sort(ip,ips,desc_order_by,traffic); \r
007c44c5 1011\r
1012 /*-----------------------------------------------------------------*/\r
9f552e96 1013 for_each(interface, interfaces)\r
007c44c5 1014 {\r
9f552e96 1015 long long int rate = interface->speed;\r
1016 long long int max = interface->speed;\r
6cc38f96 1017 int group_count = 0;\r
9f552e96 1018 //obsolete: FILE *credit_file = NULL;\r
007c44c5 1019 \r
9f552e96 1020 //obsolete: if(!just_preview && !dry_run && enable_credit)\r
1021 //obsolete: {\r
1022 //obsolete: credit_file = fopen(credit,"w");\r
1023 //obsolete: }\r
1024\r
208112af 1025 for_each(group,groups)\r
007c44c5 1026 {\r
1027 if(!just_preview)\r
1028 {\r
5450cb41 1029 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d quantum %d #down desired %d", \r
1030 tc, interface->name, parent, group->id, rate, max, burst_group, highest_priority+1, htb_quantum, group->desired);\r
007c44c5 1031 safe_run(str);\r
1032 }\r
9f552e96 1033\r
6cc38f96 1034 if(group_count++ < max_nesting)\r
bb9e11ee 1035 {\r
6cc38f96 1036 parent = group->id;\r
bb9e11ee 1037 }\r
9f552e96 1038\r
6cc38f96 1039 rate -= digital_divide*group->min;\r
1040 if(rate < group->min)\r
4358455e 1041 {\r
6cc38f96 1042 rate = group->min;\r
4358455e 1043 }\r
007c44c5 1044 \r
1045 /*shaping of aggresive downloaders, with credit file support */\r
9f552e96 1046 /* obsolete\r
007c44c5 1047 if(use_credit)\r
1048 {\r
6cc38f96 1049 int group_rate = group->min, priority_sequence = lowest_priority;\r
007c44c5 1050 \r
6cc38f96 1051 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
007c44c5 1052 {\r
e48d46c9 1053 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
1054 if( ip->keyword->data_limit \r
1055 and not ip->fixedprio \r
1056 and ip->traffic > ip->realquota )\r
007c44c5 1057 {\r
e48d46c9 1058 if(group_rate < ip->max)\r
4358455e 1059 {\r
e48d46c9 1060 ip->max = group_rate;\r
4358455e 1061 }\r
007c44c5 1062 group_rate+=magic_treshold;\r
208112af 1063 ip->prio=lowest_priority;\r
4358455e 1064 if(ip->prio<highest_priority+2)\r
1065 {\r
1066 ip->prio=highest_priority+2;\r
1067 }\r
007c44c5 1068 }\r
1069 else\r
1070 {\r
6cc38f96 1071 if( ip->keyword->data_prio \r
1072 && !ip->fixedprio \r
f71cfa3b 1073 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
007c44c5 1074 {\r
1075 ip->prio=priority_sequence--;\r
4358455e 1076 if(ip->prio<highest_priority+1)\r
1077 {\r
1078 ip->prio=highest_priority+1;\r
1079 }\r
007c44c5 1080 }\r
1081 \r
1082 if(credit_file)\r
1083 {\r
1084 unsigned long long lcredit=0;\r
99127c70 1085 \r
4358455e 1086 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1087 {\r
007c44c5 1088 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
4358455e 1089 }\r
007c44c5 1090 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1091 }\r
1092 }\r
6cc38f96 1093 } \r
9f552e96 1094 } obsolete */\r
007c44c5 1095 }\r
9f552e96 1096 /* obsolete \r
4358455e 1097 if(credit_file)\r
1098 {\r
1099 fclose(credit_file);\r
9f552e96 1100 } obsolete */\r
007c44c5 1101 }\r
1102\r
1103 if(just_preview)\r
1104 {\r
62b118c2 1105 if(start_shaping || stop_shaping || reduce_ceil)\r
8e29188a 1106 {\r
dccb3227 1107 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1108 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1109 \r
8e29188a 1110 parse(classmap)\r
1111 {\r
1112 ptr=strchr(_,' ');\r
1113 if(ptr)\r
1114 {\r
1115 *ptr=0;\r
1116 ptr++;\r
1117 if_exists(ip,ips,eq(ip->addr,_))\r
1118 {\r
68184e0d 1119 int unshape_this_ip = 0;\r
bf59a20b 1120 long avg_mbps_down = ip->traffic_down * 8 / how_much_seconds; \r
1121 long avg_mbps_up = ip->traffic_up * 8 / how_much_seconds;\r
dccb3227 1122 int agreg = 1, print_stats = 1;\r
1123 \r
dccb3227 1124 if(ip->keyword->download_aggregation)\r
1125 {\r
3335365b 1126 int min_mbps = (ip->min/ip->keyword->download_aggregation)>>10;\r
1127 if(min_mbps < 1)\r
1128 {\r
1129 min_mbps = 1;\r
1130 }\r
1131 \r
1132 if(min_mbps <= avg_mbps_down)\r
dccb3227 1133 {\r
1134 unshape_this_ip = 0;\r
bf59a20b 1135 agreg = (int)((float)(avg_mbps_down+1)/min_mbps+.5);\r
dccb3227 1136 ip->max /= agreg;\r
9de0d723 1137 ip->pps_limit /= agreg;\r
5aca3d03 1138 printf("Download aggregation 1:%d for %s (min: %d Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
dccb3227 1139 }\r
1140 else\r
1141 {\r
1142 unshape_this_ip = 1;\r
1143 }\r
1144 }\r
1145 else if(ip->keyword->upload_aggregation)\r
1146 {\r
3335365b 1147 int min_mbps = (ip->min/ip->keyword->upload_aggregation)>>10;\r
1148 if(min_mbps < 1)\r
1149 {\r
1150 min_mbps = 1;\r
1151 }\r
1152\r
1153 if(min_mbps <= avg_mbps_up)\r
dccb3227 1154 {\r
1155 unshape_this_ip = 0;\r
bf59a20b 1156 agreg = (int)((float)(avg_mbps_up+1)/min_mbps+.5);\r
dccb3227 1157 ip->max /= agreg;\r
5aca3d03 1158 printf("Upload aggregation 1:%d for %s: (min: %d Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
dccb3227 1159 }\r
1160 else\r
1161 {\r
1162 unshape_this_ip = 1;\r
1163 }\r
1164 }\r
3335365b 1165 if(stop_shaping)\r
1166 {\r
1167 unshape_this_ip = 1;\r
1168 }\r
bf59a20b 1169 ip->aggregated = agreg; \r
1170 ip->mark = atoi(ptr);\r
dccb3227 1171 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
8e29188a 1172 {\r
dccb3227 1173 if(unshape_this_ip)\r
3f76726a 1174 {\r
1175 ip->max = ip->desired;\r
dccb3227 1176 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1177 {\r
1178 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1179 }\r
1180 else\r
1181 {\r
1182 print_stats = 0;\r
1183 }\r
3f76726a 1184 }\r
1185 else\r
1186 {\r
9f552e96 1187 printf("Updating %s (%s) ", ip->name, ip->addr);\r
62b118c2 1188 if(reduce_ceil)\r
1189 {\r
1190 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1191 }\r
dccb3227 1192 else if(ip->max < ip->min)\r
1193 {\r
1194 ip->max = ip->min;\r
1195 } \r
1196 }\r
9f552e96 1197 for_each(interface, interfaces)\r
dccb3227 1198 {\r
9f552e96 1199 if(!interface->is_upstream)\r
1200 {\r
1201 if(print_stats)\r
1202 {\r
1203 printf("[down %s: %dk-%dk wants %d]", interface->name, ip->min, ip->max, ip->desired);\r
1204 }\r
5450cb41 1205 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d", \r
1206 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio, htb_quantum);\r
9f552e96 1207 safe_run(str);\r
1208 }\r
1209 else\r
1210 {\r
1211 if(print_stats)\r
1212 {\r
1213 printf("[up %s: %dk-%dk wants %dk]", interface->name, (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1214 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1215 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1216 }\r
5450cb41 1217 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d",\r
9f552e96 1218 tc, interface->name, ip->group, ip->mark,\r
1219 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
5450cb41 1220 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio, htb_quantum);\r
9f552e96 1221 safe_run(str);\r
1222 }\r
3f76726a 1223 }\r
dccb3227 1224 if(print_stats)\r
1225 {\r
9f552e96 1226 printf("\n");\r
dccb3227 1227 }\r
8e29188a 1228 }\r
1229 }\r
1230 }\r
1231 }\r
1232 fail\r
1233 { \r
1234 perror(classmap);\r
1235 puts("Warning - classmap file not fund, just generating preview ...");\r
1236 start_shaping=FALSE;\r
3f76726a 1237 stop_shaping=FALSE;\r
8e29188a 1238 }\r
1239 done; /* ugly macro end */\r
1240 }\r
6fb3c58a 1241 html=preview;\r
1ab008b9 1242 json_traffic=json_preview;\r
007c44c5 1243 }\r
6fb3c58a 1244\r
5aca3d03 1245 if(!dry_run && !just_flush && !skip_stats)\r
007c44c5 1246 {\r
1247 /*-----------------------------------------------------------------*/\r
1ab008b9 1248 printf("Writing json traffic overview %s ... ", json_traffic);\r
007c44c5 1249 /*-----------------------------------------------------------------*/\r
1ab008b9 1250 write_json_traffic(json_traffic);\r
007c44c5 1251\r
0b9c3c19 1252 /*-----------------------------------------------------------------*/\r
1253 printf("Writing statistics into HTML page %s ...\n", html);\r
1254 /*-----------------------------------------------------------------*/\r
1255 write_htmlandlogs(html, d, total, just_preview);\r
47b5fd64 1256 printf("\n");\r
0b9c3c19 1257 }\r
007c44c5 1258\r
1259 if(just_preview)\r
1260 {\r
8e29188a 1261 char swchar='p';\r
1262 if(start_shaping)\r
1263 {\r
1264 swchar='s';\r
1265 }\r
62b118c2 1266 else if(reduce_ceil)\r
1267 {\r
1268 swchar='0'+reduce_ceil; /* -2, -4 */\r
1269 }\r
3f76726a 1270 else if(stop_shaping)\r
1271 {\r
1272 swchar='q';\r
1273 }\r
1274\r
8e29188a 1275 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
007c44c5 1276 exit(0);\r
4deb2d6f 1277 } \r
1278\r
007c44c5 1279 i=0;\r
260c2719 1280#ifdef DEBUG\r
007c44c5 1281 printf("%-22s %-15s mark\n","name","ip");\r
260c2719 1282#endif\r
208112af 1283\r
14e28c6f 1284 printf("Writing %s", classmap); \r
be96b71b 1285 f = fopen(classmap, "w"); \r
1286 if(f < 0)\r
1287 {\r
1288 perror(classmap);\r
1289 }\r
1290\r
1291 /*-----------------------------------------------------------------*/\r
296d0585 1292 printf(" + generating iptables and tc classes ... \n");\r
be96b71b 1293 /*-----------------------------------------------------------------*/\r
1294\r
9f552e96 1295 for_each(ip, ips) if(ip->mark > 0)\r
be96b71b 1296 {\r
9f552e96 1297 for_each(interface, interfaces)\r
007c44c5 1298 {\r
9f552e96 1299 char *chain;\r
1300 if(idxs)\r
0b9c3c19 1301 {\r
9f552e96 1302 char *buf;\r
1303 duplicate(ip->addr,buf);\r
1304 if(ip->v6)\r
1305 {\r
1306 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1307 }\r
1308 else\r
1309 {\r
1310 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1311 }\r
1312 \r
1313 string(chain, 6+strlen(buf));\r
1314 sprintf(chain, "%s_", interface->idxprefix);\r
1315 strcat(chain, buf);\r
1316\r
1317 free(buf);\r
0b9c3c19 1318 }\r
1319 else\r
1320 {\r
9f552e96 1321 chain = interface->chain;\r
0b9c3c19 1322 }\r
007c44c5 1323\r
9f552e96 1324 /* packet limits - this will be optional in future */\r
1325 if(ip->pps_limit)\r
1326 {\r
1327 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1328 ip->pps_limit, ip->pps_limit);\r
1329 }\r
1330 else\r
1331 {\r
1332 *limit_pkts = 0;\r
1333 } \r
007c44c5 1334\r
9f552e96 1335 #ifdef DEBUG\r
1336 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1337 #endif\r
06733b88 1338\r
9f552e96 1339 /* ------------------------------------------------ iptables classify */\r
c5a58cd4 1340 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1341 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
9f552e96 1342 interface->name, mark_iptables, ip->mark);\r
1343 iptables_save_line(str, ip->v6);\r
007c44c5 1344\r
c5a58cd4 1345 sprintf(str, "-A %s -%c %s/%d -o %s %s-j ACCEPT",\r
1346 chain, (interface->is_upstream?'s':'d'),ip->addr, ip->mask,\r
1347 interface->name, limit_pkts);\r
9f552e96 1348 iptables_save_line(str, ip->v6);\r
007c44c5 1349\r
76b82eec 1350 if(*limit_pkts) /* non-empty string?*/\r
56f6397e 1351 {\r
1352 /* classify overlimit packets to separate overlimit class */\r
c5a58cd4 1353 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1354 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
56f6397e 1355 interface->name, mark_iptables, OVERLIMIT_CLASS);\r
1356 iptables_save_line(str, ip->v6);\r
1357\r
c5a58cd4 1358 sprintf(str, "-A %s -%c %s/%d -o %s -j ACCEPT",\r
1359 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
1360 interface->name);\r
56f6397e 1361 iptables_save_line(str, ip->v6);\r
1362 }\r
007c44c5 1363\r
9f552e96 1364 if(ip->min)\r
dee5592e 1365 {\r
9f552e96 1366 //TODO - min and max should not exceed interface->speed\r
1367 \r
1368 /* -------------------------------------------------------- tc class */\r
1369 #ifdef DEBUG\r
1370 printf("[down: %dk-%dk]", ip->min, ip->max);\r
1371 #endif\r
be96b71b 1372\r
5450cb41 1373 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d", \r
1374 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio, htb_quantum);\r
0b9c3c19 1375 safe_run(str);\r
007c44c5 1376\r
9f552e96 1377 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1378 {\r
1379 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1380 tc, interface->name, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1381 safe_run(str);\r
1382 }\r
be96b71b 1383\r
9f552e96 1384 if(filter_type == 1)\r
1385 {\r
1386 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1387 tc, interface->name, ip->mark, ip->mark);\r
1388 safe_run(str);\r
1389 }\r
007c44c5 1390 }\r
9f552e96 1391 else\r
be96b71b 1392 {\r
9f552e96 1393 #ifdef DEBUG\r
1394 printf("(sharing %s)\n", ip->sharing);\r
1395 #endif\r
be96b71b 1396 }\r
9f552e96 1397 i++;\r
007c44c5 1398 }\r
9f552e96 1399 if(ip->min && f > 0)\r
260c2719 1400 {\r
9f552e96 1401 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
260c2719 1402 }\r
296d0585 1403 printf(".");\r
007c44c5 1404 }\r
6fb3c58a 1405 if(f > 0)\r
be96b71b 1406 {\r
296d0585 1407 puts(" done.");\r
be96b71b 1408 fclose(f);\r
1409 }\r
0b9c3c19 1410\r
9f552e96 1411 for_each(interface, interfaces)\r
007c44c5 1412 {\r
9f552e96 1413 char *chain;\r
1414 if(idxs)\r
0b9c3c19 1415 {\r
9f552e96 1416 string(chain, STRLEN);\r
1417 sprintf(chain, "%s_common", interface->idxprefix);\r
1418 }\r
1419 else\r
1420 {\r
1421 chain = interface->chain;\r
0b9c3c19 1422 }\r
0b9c3c19 1423\r
9f552e96 1424 if(free_min)\r
1425 {\r
1426 final_chain = "ACCEPT";\r
0b9c3c19 1427\r
9f552e96 1428 sprintf(str, "-A %s -o %s -j %s%d",\r
1429 chain, interface->name, mark_iptables, FREE_CLASS);\r
1a2ab32b 1430 iptables_save_line(str, IPv4); /* only for IPv4 */\r
9f552e96 1431 }\r
0b9c3c19 1432\r
9f552e96 1433 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1a2ab32b 1434 iptables_save_line(str, IPv4);\r
9f552e96 1435 if(ip6prefix)\r
1436 {\r
1437 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1a2ab32b 1438 iptables_save_line(str, IPv6);\r
9f552e96 1439 }\r
abe9b855 1440\r
9f552e96 1441 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1442 {\r
dee5592e 1443 /*-----------------------------------------------------------------*/\r
a25842fa 1444 puts("Generating free bandwith class ...");\r
dee5592e 1445 /*-----------------------------------------------------------------*/\r
5450cb41 1446 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d",\r
1447 tc, interface->name, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority, htb_quantum);\r
dee5592e 1448 safe_run(str);\r
1449 /* tc SFQ */\r
260c2719 1450 if(strcmpi(qos_leaf, "none"))\r
dee5592e 1451 {\r
9f552e96 1452 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, interface->name, FREE_CLASS, FREE_CLASS, qos_leaf);\r
dee5592e 1453 safe_run(str);\r
1454 } \r
1455 /* tc handle 1 fw flowid */\r
9f552e96 1456 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);\r
dee5592e 1457 safe_run(str);\r
9f552e96 1458 }\r
296d0585 1459 if(*limit_pkts) /* non-empty string?*/\r
1460 {\r
1461 /*-----------------------------------------------------------------*/\r
1462 puts("Generating bandwith class for overlimit packets...");\r
1463 /*-----------------------------------------------------------------*/\r
1464 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d quantum %d", \r
1465 tc, interface->name, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority, htb_quantum);\r
1466 safe_run(str);\r
1467 }\r
9f552e96 1468 } \r
dee5592e 1469 printf("Total IP count: %d\n", i);\r
4deb2d6f 1470 run_iptables_restore();\r
260c2719 1471 if(log_file)\r
1472 {\r
1473 fclose(log_file);\r
1474 }\r
007c44c5 1475 return 0;\r
007c44c5 1476 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1477 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1478}\r
This page took 1.944199 seconds and 4 git commands to generate.