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