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