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