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