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