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