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