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