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