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