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