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