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