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