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