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