...
[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
398void run_iptables_restore(void)\r
399{\r
400 char *restor;\r
401 string(restor, STRLEN);\r
402\r
403 /*-----------------------------------------------------------------*/\r
404 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
405 /*-----------------------------------------------------------------*/\r
406\r
407 iptables_save_line("COMMIT", FALSE);\r
408 fclose(iptables_file);\r
409 if(dry_run) \r
410 {\r
411 parse(iptablesfile)\r
412 {\r
413 printf("%s\n",_);\r
414 }\r
415 done; /* ugly macro end */\r
416 }\r
417\r
418 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
419 safe_run(restor);\r
420\r
421 if(ip6prefix)\r
422 {\r
423 /*-----------------------------------------------------------------*/\r
424 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
425 /*-----------------------------------------------------------------*/\r
426 iptables_save_line("COMMIT", TRUE);\r
427 fclose(ip6tables_file);\r
428 if(dry_run) \r
429 {\r
430 parse(ip6tablesfile)\r
431 {\r
432 printf("%s\n",_);\r
433 }\r
434 done; /* ugly macro end */\r
435 }\r
436 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
437 safe_run(restor);\r
438 }\r
439 free(restor);\r
440}\r
441\r
442/**/\r
443\r
444char *parse_datafile_line(char *str);\r
445time_t get_mtime(const char *path);\r
446\r
447/*-----------------------------------------------------------------*/\r
448/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
449/*-----------------------------------------------------------------*/\r
450\r
451program\r
452{\r
453 int i=0; /* just plain old Fortran style integer :-) */\r
454 FILE *f=NULL; /* everything is just stream of bytes... */\r
455 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
456 char *substring, *limit_pkts;\r
457\r
458 int parent = 1;\r
459 int just_networks = FALSE; \r
460 int just_flush = FALSE; /* deactivates all previous actions */\r
461 int nodelay = FALSE;\r
462 int just_preview = FALSE; /* preview - generate just stats */\r
463 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
464 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
465 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
466 int just_logs = FALSE; /* just parse logs */\r
467 int run = FALSE;\r
468 int total = 0;\r
469 \r
470 char *althosts=NULL;\r
471 \r
472 printf("\n\\r
473Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
474Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\\r
475iptables-restore & burst tunning & classify modification by Ludva\n\\r
476Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
477\r
478 /*----- Boring... we have to check command line options first: ----*/ \r
479 arguments\r
480 {\r
481 argument("-c") { nextargument(config); }\r
482 argument("-h") { nextargument(althosts);}\r
483 argument("-d") { run=TRUE; dry_run=TRUE; }\r
484 argument("-f") { run=TRUE; just_flush=TRUE; }\r
485 argument("-9") { run=TRUE; just_flush=9; }\r
486 argument("-p") { run=TRUE; just_preview=TRUE; }\r
487 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
488 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
489 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
490 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
491 argument("-r") { run=TRUE; }\r
492 argument("-n") { run=TRUE; nodelay=TRUE; }\r
493 argument("-a") { run=TRUE; just_networks=TRUE; }\r
494 argument("-l") { just_logs=TRUE; }\r
495 argument("-m") { just_logs=TRUE; }\r
496 argument("-y") { just_logs=TRUE; }\r
497 argument("-?") { help(); exit(0); }\r
498 argument("--help") { help(); exit(0); }\r
499 argument("-v") { exit(0); } \r
500 argument("--version") { exit(0); } \r
501 }\r
502 \r
503 if(dry_run)\r
504 {\r
505 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
506 }\r
507\r
508 date(d); /* this is typical cll1.h macro - prints current date */\r
509\r
510 /*-----------------------------------------------------------------*/\r
511 printf("Parsing configuration file %s ...\n", config);\r
512 /*-----------------------------------------------------------------*/\r
513 get_config(config);\r
514 /*-----------------------------------------------------------------*/\r
515 printf("Parsing upstream interfaces list %s ...\n", upstreamfile);\r
516 /*-----------------------------------------------------------------*/\r
517 parse(upstreamfile)\r
518 {\r
519 ptr = parse_datafile_line(_);\r
520 if(ptr)\r
521 {\r
522 create(interface, Interface);\r
523 interface->name = _;\r
524 interface->speed = (long long)atol(ptr);\r
525 /* is supplied value meaningful ?*/\r
526 if(interface->speed <= 0)\r
527 {\r
528 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
529 reject_config_and_exit(upstreamfile);\r
530 }\r
531 interface->is_upstream = TRUE;\r
532 interface->chain = "FORWARD";\r
533 interface->idxprefix = "forw";\r
534 push(interface, interfaces);\r
535 printf("Upstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
536 }\r
537 }\r
538 done; /* ugly macro end */\r
539\r
540 /*-----------------------------------------------------------------*/\r
541 printf("Parsing downstream interfaces list %s ...\n", downstreamfile);\r
542 /*-----------------------------------------------------------------*/\r
543 parse(downstreamfile)\r
544 {\r
545 ptr = parse_datafile_line(_);\r
546 if(ptr)\r
547 {\r
548 create(interface, Interface);\r
549 interface->name = _;\r
550 interface->speed = (long long)atol(ptr);\r
551 /* is supplied value meaningful ?*/\r
552 if(interface->speed <= 0)\r
553 {\r
554 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
555 reject_config_and_exit(downstreamfile);\r
556 }\r
557 interface->is_upstream = FALSE;\r
558 interface->chain = "POSTROUTING";\r
559 interface->idxprefix = "post";\r
560 push(interface, interfaces);\r
561 printf("Downstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
562 }\r
563 }\r
564 done; /* ugly macro end */\r
565\r
566 \r
567 if(just_logs)\r
568 {\r
569 parse_ip_log(argc,argv);\r
570 exit(0);\r
571 }\r
572 else if(not run)\r
573 {\r
574 help();\r
575 exit(0);\r
576 }\r
577\r
578 if(althosts)\r
579 {\r
580 hosts = althosts;\r
581 }\r
582\r
583 if(just_flush<9)\r
584 {\r
585 /*-----------------------------------------------------------------*/\r
586 puts("Parsing iptables verbose output ...");\r
587 /*-----------------------------------------------------------------*/\r
588 get_traffic_statistics(iptables, FALSE);\r
589 if(ip6prefix)\r
590 {\r
591 /*-----------------------------------------------------------------*/\r
592 puts("Parsing ip6tables verbose output ...");\r
593 /*-----------------------------------------------------------------*/ \r
594 get_traffic_statistics(ip6tables, TRUE);\r
595 }\r
596 }\r
597\r
598 /*-----------------------------------------------------------------*/\r
599 /* cll1.h - let's allocate brand new character buffer... */\r
600 /*-----------------------------------------------------------------*/\r
601 string(str, STRLEN); \r
602 string(limit_pkts, STRLEN);\r
603\r
604 /*-----------------------------------------------------------------*/\r
605 printf("Parsing macro definition file %s ...\n", macrosfile);\r
606 /*-----------------------------------------------------------------*/\r
607 parse(macrosfile)\r
608 {\r
609 ptr = parse_datafile_line(_);\r
610 if(ptr)\r
611 {\r
612 create(macro, Macro);\r
613 macro->rewrite_from = _;\r
614 macro->rewrite_to = ptr;\r
615 push(macro, macros);\r
616 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
617 }\r
618 }\r
619 done; /* ugly macro end */\r
620\r
621\r
622\r
623 /*-----------------------------------------------------------------*/\r
624 printf("Parsing class defintion file %s ...\n", hosts);\r
625 /*-----------------------------------------------------------------*/\r
626 parse_hosts(hosts);\r
627/*\r
628 //this was pretty dumb idea anyway...\r
629 if(just_networks)\r
630 {\r
631 analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d");\r
632 exit(-1); \r
633 }\r
634*/\r
635\r
636 /*-----------------------------------------------------------------*/\r
637 puts("Resolving shared connections ...");\r
638 /*-----------------------------------------------------------------*/\r
639 for_each(ip, ips) if(ip->sharing)\r
640 {\r
641 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
642 {\r
643 sharedip->traffic += ip->traffic;\r
644 sharedip->traffic_down += ip->direct;\r
645 sharedip->traffic_up += ip->upload;\r
646 ip->traffic = 0;\r
647 ip->mark = sharedip->mark; \r
648 ip->lmsid = sharedip->lmsid;\r
649 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
650\r
651 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
652 ptr = strchr(ip->addr, '+');\r
653 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
654 {\r
655 *(--ptr) = 0;\r
656 concatenate(ip->addr, sharedip->addr, ptr);\r
657 ip->name = ip->addr = ptr;\r
658 ptr = strchr(ip->addr, '.');\r
659 while(ptr && *ptr)\r
660 {\r
661 *ptr = ':';\r
662 ptr = strchr(ptr, '.');\r
663 }\r
664 ip->mask += 64;\r
665 }\r
666\r
667 break;\r
668 }\r
669 if(not sharedip)\r
670 {\r
671 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
672 ip->addr, ip->name, ip->sharing);\r
673 }\r
674 }\r
675\r
676 if(enable_credit && just_flush<9)\r
677 {\r
678 /*-----------------------------------------------------------------*/\r
679 printf("Parsing credit file %s ...\n", credit);\r
680 /*-----------------------------------------------------------------*/\r
681 parse(credit)\r
682 {\r
683 ptr = parse_datafile_line(_);\r
684 if(ptr)\r
685 {\r
686 if_exists(ip,ips,eq(ip->addr,_))\r
687 {\r
688 sscanf(ptr,"%Lu",&(ip->credit));\r
689 }\r
690 }\r
691 }\r
692 done; /* ugly macro end */\r
693 }\r
694\r
695\r
696 if(!just_preview)\r
697 {\r
698 /*-----------------------------------------------------------------*/\r
699 puts("Initializing iptables and tc classes ...");\r
700 /*-----------------------------------------------------------------*/\r
701 \r
702 iptables_file = fopen(iptablesfile, "w");\r
703 if(iptables_file == NULL)\r
704 {\r
705 perror(iptablesfile);\r
706 exit(-1);\r
707 }\r
708 iptables_save_line(iptablespreamble, FALSE);\r
709\r
710 if(ip6prefix)\r
711 {\r
712 ip6tables_file = fopen(ip6tablesfile, "w");\r
713 if(ip6tables_file == NULL)\r
714 {\r
715 perror(ip6tablesfile);\r
716 exit(-1);\r
717 }\r
718 iptables_save_line(iptablespreamble, TRUE);\r
719 iptables_save_line(ip6preamble, TRUE);\r
720 }\r
721\r
722 run_iptables_restore();\r
723 \r
724 log_file = fopen(cmdlog, "w");\r
725 if(log_file == NULL) \r
726 {\r
727 perror(cmdlog);\r
728 exit(-1);\r
729 } \r
730 \r
731 for_each(interface, interfaces)\r
732 {\r
733 sprintf(str,"%s qdisc del dev %s root 2>/dev/null", tc, interface->name);\r
734 safe_run(str);\r
735 }\r
736 \r
737 iptables_file=fopen(iptablesfile,"w");\r
738 iptables_save_line(iptablespreamble, FALSE);\r
739 if(ip6prefix)\r
740 {\r
741 ip6tables_file=fopen(ip6tablesfile,"w");\r
742 iptables_save_line(iptablespreamble, TRUE);\r
743 iptables_save_line(ip6preamble, TRUE);\r
744 }\r
745\r
746 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */\r
747 {\r
748 for_each(interface, interfaces)\r
749 {\r
750 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", interface->chain, qos_free_zone, interface->name);\r
751 iptables_save_line(str, FALSE);\r
752 }\r
753 }\r
754 \r
755 if(ip_count > idxtable_treshold1 && !just_flush)\r
756 {\r
757 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
758 char *subnet, *buf;\r
759 /*-----------------------------------------------------------------*/\r
760 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
761 /*-----------------------------------------------------------------*/\r
762\r
763 iptables_save_line(":post_common - [0:0]", FALSE);\r
764 iptables_save_line(":forw_common - [0:0]", FALSE);\r
765 if(ip6prefix)\r
766 {\r
767 iptables_save_line(":post_common - [0:0]", TRUE);\r
768 iptables_save_line(":forw_common - [0:0]", TRUE);\r
769 }\r
770\r
771 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
772 {\r
773 if(ip->v6)\r
774 {\r
775 buf=index6_id(ip->addr,bitmask+32);\r
776 }\r
777 else\r
778 {\r
779 buf=index_id(ip->addr, bitmask);\r
780 }\r
781 \r
782 if_exists(idx,idxs,eq(idx->id,buf))\r
783 {\r
784 idx->children++;\r
785 }\r
786 else\r
787 {\r
788 create(idx,Index);\r
789 idx->addr = ip->addr;\r
790 idx->id = buf;\r
791 idx->bitmask = bitmask+32*ip->v6;\r
792 idx->parent = NULL;\r
793 idx->children = 0;\r
794 idx->ipv6 = ip->v6;\r
795 idxcount++;\r
796 push(idx,idxs);\r
797 }\r
798 }\r
799\r
800 /* brutal perfomance optimalization */\r
801 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
802 {\r
803 bitmask -= idxtable_bitmask2;\r
804 idxcount = 0;\r
805\r
806 for_each(idx,idxs) if(idx->parent == NULL)\r
807 {\r
808 if(idx->ipv6)\r
809 {\r
810 buf = index6_id(idx->addr, bitmask+32);\r
811 }\r
812 else\r
813 {\r
814 buf = index_id(idx->addr, bitmask);\r
815 }\r
816 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
817 {\r
818 metaindex->children++;\r
819 }\r
820 else\r
821 {\r
822 create(metaindex,Index);\r
823 metaindex->addr = idx->addr;\r
824 metaindex->id = buf;\r
825 metaindex->bitmask = bitmask+32*idx->ipv6;\r
826 metaindex->parent = NULL;\r
827 metaindex->children = 0;\r
828 metaindex->ipv6 = idx->ipv6;\r
829 idxcount++;\r
830 push(metaindex,idxs);\r
831 }\r
832 idx->parent=metaindex;\r
833 }\r
834 }\r
835\r
836 /* this should slightly optimize throughput ... */\r
837 sort(idx,idxs,desc_order_by,children);\r
838 sort(idx,idxs,order_by,bitmask);\r
839\r
840 i=0;\r
841 for_each(idx, idxs)\r
842 {\r
843 if(idx->ipv6)\r
844 {\r
845 subnet=subnet6_id(idx->addr, idx->bitmask);\r
846 }\r
847 else\r
848 {\r
849 subnet=subnet_id(idx->addr, idx->bitmask);\r
850 }\r
851 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
852 \r
853 sprintf(str,":post_%s - [0:0]", idx->id);\r
854 iptables_save_line(str, idx->ipv6);\r
855\r
856 sprintf(str,":forw_%s - [0:0]", idx->id);\r
857 iptables_save_line(str, idx->ipv6);\r
858\r
859 for_each(interface, interfaces)\r
860 {\r
861 if(idx->parent)\r
862 {\r
863 string(buf, strlen(idx->parent->id)+6);\r
864 sprintf(buf, "%s_%s", interface->idxprefix, idx->parent->id);\r
865 }\r
866 else\r
867 {\r
868 buf = interface->chain;\r
869 }\r
870\r
871 sprintf(str,"-A %s -d %s/%d -o %s -j %s_%s", buf, subnet, idx->bitmask, interface->name, interface->idxprefix, idx->id);\r
872 iptables_save_line(str, idx->ipv6);\r
873\r
874 sprintf(str,"-A %s -d %s/%d -o %s -j %s_common", buf, subnet, idx->bitmask, interface->name, interface->idxprefix);\r
875 iptables_save_line(str, idx->ipv6);\r
876 }\r
877 }\r
878 printf("Total indexed iptables chains created: %d\n", i);\r
879\r
880 for_each(interface, interfaces)\r
881 {\r
882 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
883 iptables_save_line(str, FALSE);\r
884 if(ip6prefix)\r
885 {\r
886 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
887 iptables_save_line(str, TRUE);\r
888 }\r
889 }\r
890 }\r
891 }\r
892\r
893 if(just_flush)\r
894 {\r
895 fclose(iptables_file);\r
896 if(log_file)\r
897 { \r
898 fclose(log_file);\r
899 }\r
900 puts("Just flushed iptables and tc classes - now exiting ...");\r
901 exit(0);\r
902 }\r
903\r
904 if(!just_preview)\r
905 {\r
906 if(!dry_run && !nodelay && qos_free_delay)\r
907 {\r
908 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay);\r
909 sleep(qos_free_delay);\r
910 }\r
911\r
912 for_each(interface, interfaces)\r
913 {\r
914 sprintf(str, "%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
915 tc, interface->name, htb_r2q);\r
916 safe_run(str);\r
917\r
918 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
919 tc, interface->name, medium, medium, burst_main, highest_priority);\r
920 safe_run(str);\r
921\r
922 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
923 tc, interface->name, interface->speed, interface->speed, burst_main, highest_priority);\r
924 safe_run(str);\r
925 }\r
926 }\r
927\r
928 /*-----------------------------------------------------------------*/\r
929 puts("Locating heavy downloaders and generating root classes ...");\r
930 /*-----------------------------------------------------------------*/\r
931 sort(ip,ips,desc_order_by,traffic); \r
932\r
933 /*-----------------------------------------------------------------*/\r
934 for_each(interface, interfaces)\r
935 {\r
936 long long int rate = interface->speed;\r
937 long long int max = interface->speed;\r
938 int group_count = 0;\r
939 //obsolete: FILE *credit_file = NULL;\r
940 \r
941 //obsolete: if(!just_preview && !dry_run && enable_credit)\r
942 //obsolete: {\r
943 //obsolete: credit_file = fopen(credit,"w");\r
944 //obsolete: }\r
945\r
946 for_each(group,groups)\r
947 {\r
948 if(!just_preview)\r
949 {\r
950 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
951 tc, interface->name, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
952 safe_run(str);\r
953 }\r
954\r
955 if(group_count++ < max_nesting)\r
956 {\r
957 parent = group->id;\r
958 }\r
959\r
960 rate -= digital_divide*group->min;\r
961 if(rate < group->min)\r
962 {\r
963 rate = group->min;\r
964 }\r
965 \r
966 /*shaping of aggresive downloaders, with credit file support */\r
967 /* obsolete\r
968 if(use_credit)\r
969 {\r
970 int group_rate = group->min, priority_sequence = lowest_priority;\r
971 \r
972 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
973 {\r
974 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
975 if( ip->keyword->data_limit \r
976 and not ip->fixedprio \r
977 and ip->traffic > ip->realquota )\r
978 {\r
979 if(group_rate < ip->max)\r
980 {\r
981 ip->max = group_rate;\r
982 }\r
983 group_rate+=magic_treshold;\r
984 ip->prio=lowest_priority;\r
985 if(ip->prio<highest_priority+2)\r
986 {\r
987 ip->prio=highest_priority+2;\r
988 }\r
989 }\r
990 else\r
991 {\r
992 if( ip->keyword->data_prio \r
993 && !ip->fixedprio \r
994 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
995 {\r
996 ip->prio=priority_sequence--;\r
997 if(ip->prio<highest_priority+1)\r
998 {\r
999 ip->prio=highest_priority+1;\r
1000 }\r
1001 }\r
1002 \r
1003 if(credit_file)\r
1004 {\r
1005 unsigned long long lcredit=0;\r
1006 \r
1007 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1008 {\r
1009 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1010 }\r
1011 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1012 }\r
1013 }\r
1014 } \r
1015 } obsolete */\r
1016 }\r
1017 /* obsolete \r
1018 if(credit_file)\r
1019 {\r
1020 fclose(credit_file);\r
1021 } obsolete */\r
1022 }\r
1023\r
1024 if(just_preview)\r
1025 {\r
1026 if(start_shaping || stop_shaping || reduce_ceil)\r
1027 {\r
1028 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1029 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1030 \r
1031 parse(classmap)\r
1032 {\r
1033 ptr=strchr(_,' ');\r
1034 if(ptr)\r
1035 {\r
1036 *ptr=0;\r
1037 ptr++;\r
1038 if_exists(ip,ips,eq(ip->addr,_))\r
1039 {\r
1040 int unshape_this_ip = 0;\r
1041 long avg_mbps_down = ip->traffic_down * 8 / how_much_seconds; \r
1042 long avg_mbps_up = ip->traffic_up * 8 / how_much_seconds;\r
1043 int agreg = 1, print_stats = 1;\r
1044 \r
1045 if(ip->keyword->download_aggregation)\r
1046 {\r
1047 int min_mbps = (ip->min/ip->keyword->download_aggregation)>>10;\r
1048 if(min_mbps < 1)\r
1049 {\r
1050 min_mbps = 1;\r
1051 }\r
1052 \r
1053 if(min_mbps <= avg_mbps_down)\r
1054 {\r
1055 unshape_this_ip = 0;\r
1056 agreg = (int)((float)(avg_mbps_down+1)/min_mbps+.5);\r
1057 ip->max /= agreg;\r
1058 ip->pps_limit /= agreg;\r
1059 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
1060 }\r
1061 else\r
1062 {\r
1063 unshape_this_ip = 1;\r
1064 }\r
1065 }\r
1066 else if(ip->keyword->upload_aggregation)\r
1067 {\r
1068 int min_mbps = (ip->min/ip->keyword->upload_aggregation)>>10;\r
1069 if(min_mbps < 1)\r
1070 {\r
1071 min_mbps = 1;\r
1072 }\r
1073\r
1074 if(min_mbps <= avg_mbps_up)\r
1075 {\r
1076 unshape_this_ip = 0;\r
1077 agreg = (int)((float)(avg_mbps_up+1)/min_mbps+.5);\r
1078 ip->max /= agreg;\r
1079 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
1080 }\r
1081 else\r
1082 {\r
1083 unshape_this_ip = 1;\r
1084 }\r
1085 }\r
1086 if(stop_shaping)\r
1087 {\r
1088 unshape_this_ip = 1;\r
1089 }\r
1090 ip->aggregated = agreg; \r
1091 ip->mark = atoi(ptr);\r
1092 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
1093 {\r
1094 if(unshape_this_ip)\r
1095 {\r
1096 ip->max = ip->desired;\r
1097 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1098 {\r
1099 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1100 }\r
1101 else\r
1102 {\r
1103 print_stats = 0;\r
1104 }\r
1105 }\r
1106 else\r
1107 {\r
1108 printf("Updating %s (%s) ", ip->name, ip->addr);\r
1109 if(reduce_ceil)\r
1110 {\r
1111 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1112 }\r
1113 else if(ip->max < ip->min)\r
1114 {\r
1115 ip->max = ip->min;\r
1116 } \r
1117 }\r
1118 for_each(interface, interfaces)\r
1119 {\r
1120 if(!interface->is_upstream)\r
1121 {\r
1122 if(print_stats)\r
1123 {\r
1124 printf("[down %s: %dk-%dk wants %d]", interface->name, ip->min, ip->max, ip->desired);\r
1125 }\r
1126 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1127 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
1128 safe_run(str);\r
1129 }\r
1130 else\r
1131 {\r
1132 if(print_stats)\r
1133 {\r
1134 printf("[up %s: %dk-%dk wants %dk]", interface->name, (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1135 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1136 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1137 }\r
1138 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1139 tc, interface->name, ip->group, ip->mark,\r
1140 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1141 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1142 safe_run(str);\r
1143 }\r
1144 }\r
1145 if(print_stats)\r
1146 {\r
1147 printf("\n");\r
1148 }\r
1149 }\r
1150 }\r
1151 }\r
1152 }\r
1153 fail\r
1154 { \r
1155 perror(classmap);\r
1156 puts("Warning - classmap file not fund, just generating preview ...");\r
1157 start_shaping=FALSE;\r
1158 stop_shaping=FALSE;\r
1159 }\r
1160 done; /* ugly macro end */\r
1161 }\r
1162 html=preview;\r
1163 json_traffic=json_preview;\r
1164 }\r
1165\r
1166 if(!dry_run && !just_flush)\r
1167 {\r
1168 /*-----------------------------------------------------------------*/\r
1169 printf("Writing json traffic overview %s ... ", json_traffic);\r
1170 /*-----------------------------------------------------------------*/\r
1171 write_json_traffic(json_traffic);\r
1172\r
1173 /*-----------------------------------------------------------------*/\r
1174 printf("Writing statistics into HTML page %s ...\n", html);\r
1175 /*-----------------------------------------------------------------*/\r
1176 write_htmlandlogs(html, d, total, just_preview);\r
1177 }\r
1178\r
1179 if(just_preview)\r
1180 {\r
1181 char swchar='p';\r
1182 if(start_shaping)\r
1183 {\r
1184 swchar='s';\r
1185 }\r
1186 else if(reduce_ceil)\r
1187 {\r
1188 swchar='0'+reduce_ceil; /* -2, -4 */\r
1189 }\r
1190 else if(stop_shaping)\r
1191 {\r
1192 swchar='q';\r
1193 }\r
1194\r
1195 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
1196 exit(0);\r
1197 } \r
1198\r
1199 i=0;\r
1200#ifdef DEBUG\r
1201 printf("%-22s %-15s mark\n","name","ip");\r
1202#endif\r
1203\r
1204 printf("Writing %s", classmap); \r
1205 f = fopen(classmap, "w"); \r
1206 if(f < 0)\r
1207 {\r
1208 perror(classmap);\r
1209 }\r
1210\r
1211 /*-----------------------------------------------------------------*/\r
1212 printf(" + generating iptables and tc classes ... ");\r
1213 /*-----------------------------------------------------------------*/\r
1214\r
1215 for_each(ip, ips) if(ip->mark > 0)\r
1216 {\r
1217 for_each(interface, interfaces)\r
1218 {\r
1219 char *chain;\r
1220 if(idxs)\r
1221 {\r
1222 char *buf;\r
1223 duplicate(ip->addr,buf);\r
1224 if(ip->v6)\r
1225 {\r
1226 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1227 }\r
1228 else\r
1229 {\r
1230 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1231 }\r
1232 \r
1233 string(chain, 6+strlen(buf));\r
1234 sprintf(chain, "%s_", interface->idxprefix);\r
1235 strcat(chain, buf);\r
1236\r
1237 free(buf);\r
1238 }\r
1239 else\r
1240 {\r
1241 chain = interface->chain;\r
1242 }\r
1243\r
1244 /* packet limits - this will be optional in future */\r
1245 if(ip->pps_limit)\r
1246 {\r
1247 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1248 ip->pps_limit, ip->pps_limit);\r
1249 }\r
1250 else\r
1251 {\r
1252 *limit_pkts = 0;\r
1253 } \r
1254\r
1255 #ifdef DEBUG\r
1256 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1257 #endif\r
1258\r
1259 /* ------------------------------------------------ iptables classify */\r
1260 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1261 chain, ip->addr, ip->mask,\r
1262 interface->name, mark_iptables, ip->mark);\r
1263 iptables_save_line(str, ip->v6);\r
1264\r
1265 sprintf(str, "-A %s -d %s/%d -o %s %s-j ACCEPT",\r
1266 chain, ip->addr, ip->mask, interface->name, limit_pkts);\r
1267 iptables_save_line(str, ip->v6);\r
1268\r
1269 /* classify overlimit packets to separate overlimit class */\r
1270 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1271 chain, ip->addr, ip->mask,\r
1272 interface->name, mark_iptables, OVERLIMIT_CLASS);\r
1273 iptables_save_line(str, ip->v6);\r
1274\r
1275 sprintf(str, "-A %s -d %s/%d -o %s -j ACCEPT",\r
1276 chain, ip->addr, ip->mask, interface->name);\r
1277 iptables_save_line(str, ip->v6);\r
1278\r
1279 if(ip->min)\r
1280 {\r
1281 //TODO - min and max should not exceed interface->speed\r
1282 \r
1283 /* -------------------------------------------------------- tc class */\r
1284 #ifdef DEBUG\r
1285 printf("[down: %dk-%dk]", ip->min, ip->max);\r
1286 #endif\r
1287\r
1288 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1289 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
1290 safe_run(str);\r
1291\r
1292 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1293 {\r
1294 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1295 tc, interface->name, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1296 safe_run(str);\r
1297 }\r
1298\r
1299 if(filter_type == 1)\r
1300 {\r
1301 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1302 tc, interface->name, ip->mark, ip->mark);\r
1303 safe_run(str);\r
1304 }\r
1305 }\r
1306 else\r
1307 {\r
1308 #ifdef DEBUG\r
1309 printf("(sharing %s)\n", ip->sharing);\r
1310 #endif\r
1311 }\r
1312 i++;\r
1313 }\r
1314 if(ip->min && f > 0)\r
1315 {\r
1316 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
1317 }\r
1318 }\r
1319 if(f > 0)\r
1320 {\r
1321 puts("done.");\r
1322 fclose(f);\r
1323 }\r
1324\r
1325 for_each(interface, interfaces)\r
1326 {\r
1327 char *chain;\r
1328 if(idxs)\r
1329 {\r
1330 string(chain, STRLEN);\r
1331 sprintf(chain, "%s_common", interface->idxprefix);\r
1332 }\r
1333 else\r
1334 {\r
1335 chain = interface->chain;\r
1336 }\r
1337\r
1338 if(free_min)\r
1339 {\r
1340 final_chain = "ACCEPT";\r
1341\r
1342 sprintf(str, "-A %s -o %s -j %s%d",\r
1343 chain, interface->name, mark_iptables, FREE_CLASS);\r
1344 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1345 }\r
1346\r
1347 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1348 iptables_save_line(str, FALSE);\r
1349 if(ip6prefix)\r
1350 {\r
1351 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1352 iptables_save_line(str, TRUE);\r
1353 }\r
1354\r
1355 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1356 {\r
1357 /*-----------------------------------------------------------------*/\r
1358 puts("Generating free bandwith class ...");\r
1359 /*-----------------------------------------------------------------*/\r
1360 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1361 tc, interface->name, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority);\r
1362 safe_run(str);\r
1363 /* tc SFQ */\r
1364 if(strcmpi(qos_leaf, "none"))\r
1365 {\r
1366 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, interface->name, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1367 safe_run(str);\r
1368 } \r
1369 /* tc handle 1 fw flowid */\r
1370 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
1371 safe_run(str);\r
1372 }\r
1373 /*-----------------------------------------------------------------*/\r
1374 puts("Generating bandwith class for overlimit packets...");\r
1375 /*-----------------------------------------------------------------*/\r
1376 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1377 tc, interface->name, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1378 safe_run(str);\r
1379 } \r
1380 printf("Total IP count: %d\n", i);\r
1381 run_iptables_restore();\r
1382 if(log_file)\r
1383 {\r
1384 fclose(log_file);\r
1385 }\r
1386 return 0;\r
1387 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1388 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1389}\r
This page took 0.323096 seconds and 4 git commands to generate.