Major rewrite of leading comments
[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 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
49
50
51 /* ======= All path names are defined here (for RPM patch) ======= */
52
53 const char *tc = "/sbin/tc"; /* requires tc with HTB support */
54 const char *iptables = "/sbin/iptables"; /* requires iptables utility */
55 const char *iptablessave = "/sbin/iptables-save"; /* not yet required */
56 const char *iptablesrestore = "/sbin/iptables-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
62 char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-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 *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
95 char *qos_leaf = "sfq perturb 5"; /* leaf discipline */
96 char *qos_free_zone = NULL; /* QoS free zone */
97 int qos_proxy = TRUE; /* include proxy port to QoS */
98 int found_lmsid = FALSE; /* show links to users in LMS information system */
99 int include_upload = TRUE; /* upload+download=total traffic */
100 char *proxy_ip = "192.168.1.1/32"; /* our IP with proxy port */
101 int proxy_port = 3128; /* proxy port number */
102 long long int line = 1024; /* WAN/ISP download in kbps */
103 long long int up = 1024; /* WAN/ISP upload in kbps */
104 int free_min = 32; /* minimum guaranted bandwidth for all undefined hosts */
105 int free_max = 64; /* maximum allowed bandwidth for all undefined hosts */
106 int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */
107 int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */
108 int max_nesting = 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
109 int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */
110 int burst = 8; /* HTB burst (in kbits) */
111 int burst_main = 64;
112 int burst_group = 32;
113 int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
114 int keywordcount = 0;
115 int class_count = 0;
116 int ip_count = 0;
117 /* not yet implemented:
118 int fixed_packets = 0; maximum number of pps per IP address (not class!)
119 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
120 */
121 FILE *log_file = NULL;
122 char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
123
124 const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */
125 const int lowest_priority = 7; /* lowest HTB priority (HTB built-in value is 7) */
126 const int idxtable_treshold1 = 24; /* this is no longer configurable */
127 const int idxtable_treshold2 = 12; /* this is no longer configurable */
128 const int idxtable_bitmask1 = 3; /* this is no longer configurable */
129 const int idxtable_bitmask2 = 3; /* this is no longer configurable */
130
131 struct IP *ips = NULL, *ip, *sharedip;
132 struct Group *groups = NULL, *group;
133 struct Keyword *keyword, *defaultkeyword=NULL, *keywords=NULL;
134
135 void help(void);
136 /* implemented in help.c */
137
138 void parse_ip_log(int argc, char **argv);
139 /* implemented in parselog.c */
140
141 void parse_hosts(char *hosts);
142 /* implemented in parsehosts.c */
143
144 void write_json_traffic(char *json);
145 /* implemented in json.c */
146
147 void write_htmlandlogs(char *html, char *d, int total, int just_preview);
148 /* implemented in htmlandlogs.c */
149
150 const char *tr_odd_even(void)
151 {
152 row_odd_even = 1 - row_odd_even;
153 if(row_odd_even)
154 {
155 return "<tr class=\"even\">\n";
156 }
157 else
158 {
159 return "<tr class=\"odd\">\n";
160 }
161 }
162
163 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
164 /* (except that this code uses obsolete, archaic version of this header file...) */
165
166 struct Index
167 {
168 char *addr;
169 char *id;
170 struct Index *parent;
171 int bitmask;
172 int children;
173 list(Index);
174 } *idxs=NULL, *idx, *metaindex;
175
176 void TheIP(void);
177 /* function implemented in parsehosts.c */
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("iptables-in-filename",iptablesfile); /* new */
268 option("hosts",hosts);
269 option("lan-interface",lan);
270 option("wan-interface",wan);
271 option("lan-medium",lan_medium);
272 option("wan-medium",wan_medium);
273 lloption("wan-download",line);
274 lloption("wan-upload",up);
275 ioption("hall-of-fame-enable",hall_of_fame);
276 option("hall-of-fame-title",title);
277 option("hall-of-fame-filename",html);
278 option("json-filename",json_traffic);
279 option("hall-of-fame-preview",preview);
280 option("json-preview",json_preview);
281 option("log-filename",cmdlog);
282 option("credit-filename",credit);
283 option("classmap-filename",classmap);
284 ioption("credit-enable",enable_credit);
285 option("log-traffic-directory",log_dir);
286 option("log-traffic-html-directory",html_log_dir);
287 option("log-traffic-url-path",log_url);
288 option("jquery-url",jquery_url);
289 option("lms-url",lms_url);
290 ioption("use-jquery-popups",use_jquery_popups);
291 option("qos-free-zone",qos_free_zone);
292 ioption("qos-free-delay",qos_free_delay);
293 ioption("qos-proxy-enable",qos_proxy);
294 option("qos-proxy-ip",proxy_ip);
295 option("htb-leaf-discipline",qos_leaf);
296 ioption("qos-proxy-port",proxy_port);
297 ioption("free-rate",free_min);
298 ioption("free-ceil",free_max);
299 ioption("htb-burst",burst);
300 ioption("htb-burst-main",burst_main);
301 ioption("htb-burst-group",burst_group);
302 ioption("htb-nesting-limit",max_nesting);
303 ioption("htb-r2q",htb_r2q);
304 ioption("magic-include-upload",include_upload);
305 ioption("magic-treshold",magic_treshold);
306 option("filter-type", cnf);
307 /* not yet implemented:
308 ioption("magic-fixed-packets",fixed_packets);
309 ioption("magic-relative-packets",packet_limit);
310 */
311 }
312 fail
313 {
314 perror(config_filename);
315 puts("Warning - using built-in defaults instead ...");
316 }
317 done; /* ugly macro end */
318 printf("\n");
319
320 /* leaf discipline for keywords */
321 for_each(keyword,keywords)
322 {
323 if(!strcmpi(keyword->leaf_discipline, ""))
324 {
325 keyword->leaf_discipline = qos_leaf;
326 }
327 }
328
329 if(strcmpi(cnf, "mark"))
330 {
331 filter_type = 2;
332 mark = "CLASSIFY";
333 mark_iptables = "CLASSIFY --set-class 1:";
334 }
335 else
336 {
337 filter_type = 1;
338 mark = "MARK";
339 mark_iptables = "MARK --set-mark ";
340 }
341
342 /* are supplied values meaningful ?*/
343 if(line<=0 || up<=0)
344 {
345 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
346 reject_config_and_exit(config_filename);
347 }
348 }
349
350 /* ===================== traffic analyser - uses iptables ================ */
351
352 void get_traffic_statistics(void)
353 {
354 char *str,*cmd;
355 int downloadflag=0;
356
357 textfile(Pipe,str) *line,*lines=NULL;
358 string(str,STRLEN);
359 string(cmd,STRLEN);
360
361 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
362 shell(cmd);
363 input(str,STRLEN)
364 {
365 create(line,Pipe);
366 line->str=str;
367 string(str,STRLEN);
368 append(line,lines);
369 }
370
371 for_each(line,lines)
372 {
373 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
374 unsigned long long traffic=0;
375 unsigned long pkts=0;
376 char *ipaddr=NULL,*ptr;
377
378 /* debug puts(line->str); */
379 valid_columns(ptr,line->str,' ',col)
380 if(valid) switch(col)
381 {
382 case 1: if(eq(ptr,"Chain"))
383 {
384 setchainname=1;
385 }
386 else if(eq(ptr,"pkts"))
387 {
388 valid=0;
389 }
390 else
391 {
392 sscanf(ptr,"%lu",&pkts);
393 }
394 break;
395 case 2: if(setchainname)
396 {
397 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
398 {
399 downloadflag = 1;
400 }
401 else
402 {
403 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
404 {
405 downloadflag = 0;
406 }
407 }
408 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
409 {
410 commonflag = 1;
411 }
412 }
413 else
414 {
415 sscanf(ptr,"%Lu",&traffic);
416 traffic += (1<<19);
417 traffic >>= 20;
418 }
419 break;
420 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)
421 {
422 accept=eq(ptr,mark);
423 }
424 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
425 break;
426 case 8: if(downloadflag)
427 {
428 if(strstr(proxy_ip,ptr))
429 {
430 proxyflag=1;
431 }
432 }
433 else
434 {
435 ipaddr=ptr;
436 }
437 break;
438 case 9: if(downloadflag)ipaddr=ptr;break;
439 }
440
441 if(accept && traffic>0 && ipaddr)
442 {
443 if(proxyflag)
444 {
445 printf("(proxy) ");
446 }
447 else if(!downloadflag)
448 {
449 printf("(upload) ");
450 }
451 printf("IP %s: %Lu MB (%ld pkts)\n", ipaddr, traffic, pkts);
452
453 if_exists(ip,ips,eq(ip->addr,ipaddr));
454 else
455 {
456 TheIP();
457 ip->addr = ipaddr;
458 if(eq(ip->addr,"0.0.0.0/0"))
459 {
460 ip->name = "(unregistered)";
461 ip->min = free_min;
462 ip->max = ip->desired=free_max;
463 }
464 else
465 {
466 ip->name = ipaddr;
467 }
468 }
469
470 if(downloadflag)
471 {
472 if(proxyflag)
473 {
474 ip->proxy=traffic;
475 }
476 else
477 {
478 ip->traffic+=traffic;
479 }
480 ip->direct=ip->traffic-ip->upload-ip->proxy;
481 ip->pktsdown=pkts;
482 }
483 else
484 {
485 ip->upload=traffic;
486 ip->pktsup=pkts;
487 if(include_upload)
488 {
489 ip->traffic+=traffic;
490 }
491 else
492 {
493 if(traffic>ip->traffic)
494 {
495 ip->traffic=traffic;
496 }
497 }
498 }
499 }
500 }
501 free(cmd);
502 }
503
504 /* ========== This function executes, logs OR ALSO prints command ========== */
505
506 void safe_run(char *cmd)
507 {
508 if(dry_run)
509 {
510 printf("\n=>%s\n",cmd);
511 }
512 else
513 {
514 system(cmd);
515 }
516 if(log_file)
517 {
518 fprintf(log_file,"%s\n",cmd);
519 }
520 }
521
522 void save_line(char *line)
523 {
524 fprintf(iptables_file,"%s\n",line);
525 }
526
527 void run_restore(void)
528 {
529 char *restor;
530 string(restor,STRLEN);
531
532 /*-----------------------------------------------------------------*/
533 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);
534 /*-----------------------------------------------------------------*/
535
536 save_line("COMMIT");
537 fclose(iptables_file);
538 if(dry_run)
539 {
540 parse(iptablesfile)
541 {
542 printf("%s\n",_);
543 }
544 done; /* ugly macro end */
545 }
546
547 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);
548 safe_run(restor);
549
550 free(restor);
551 }
552
553 char *parse_datafile_line(char *str)
554 {
555 char *ptr=strchr(str,' ');
556
557 if(ptr)
558 {
559 *ptr=0;
560 ptr++;
561 return ptr;
562 }
563 else
564 {
565 return NULL;
566 }
567 }
568
569
570 /*-----------------------------------------------------------------*/
571 /* Are you looking for int main(int argc, char **argv) ? :-)) */
572 /*-----------------------------------------------------------------*/
573
574 program
575 {
576 int i=0; /* just plain old Fortran style integer :-) */
577 FILE *f=NULL; /* everything is just stream of bytes... */
578 char *str, *ptr, *d; /* LET A$=B$ :-) */
579 char *substring;
580
581 int parent = 1;
582 int just_flush = FALSE; /* deactivates all previous actions */
583 int nodelay = FALSE;
584 int just_preview = FALSE; /* preview - generate just stats */
585 int start_shaping = FALSE; /* apply FUP - requires classmap file */
586 int just_logs = FALSE; /* just parse logs */
587 int run = FALSE;
588 int total = 0;
589
590 char *chain_forward, *chain_postrouting;
591 char *althosts=NULL;
592
593 printf("\n\
594 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
595 Version %s - Copyright (C)2005-2012 Michael Polak, Arachne Labs\n\
596 iptables-restore & burst tunning & classify modification by Ludva\n\
597 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
598
599 /*----- Boring... we have to check command line options first: ----*/
600 arguments
601 {
602 argument("-c") { nextargument(config); }
603 argument("-h") { nextargument(althosts);}
604 argument("-d") { run=TRUE; dry_run=TRUE; }
605 argument("-f") { run=TRUE; just_flush=TRUE; }
606 argument("-9") { run=TRUE; just_flush=9; }
607 argument("-p") { run=TRUE; just_preview=TRUE; }
608 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }
609 argument("-r") { run=TRUE; }
610 argument("-n") { run=TRUE; nodelay=TRUE; }
611 argument("-l") { just_logs=TRUE; }
612 argument("-m") { just_logs=TRUE; }
613 argument("-y") { just_logs=TRUE; }
614 argument("-?") { help(); exit(0); }
615 argument("--help") { help(); exit(0); }
616 argument("-v") { exit(0); }
617 argument("--version") { exit(0); }
618 }
619
620 if(dry_run)
621 {
622 puts("*** THIS IS JUST DRY RUN ! ***\n");
623 }
624
625 date(d); /* this is typical cll1.h macro - prints current date */
626
627 /*-----------------------------------------------------------------*/
628 printf("Parsing configuration file %s ...\n", config);
629 /*-----------------------------------------------------------------*/
630 get_config(config);
631
632 if(just_logs)
633 {
634 parse_ip_log(argc,argv);
635 exit(0);
636 }
637 else if(not run)
638 {
639 help();
640 exit(0);
641 }
642
643 if(althosts)
644 {
645 hosts=althosts;
646 }
647
648 if(just_flush<9)
649 {
650 /*-----------------------------------------------------------------*/
651 puts("Parsing iptables verbose output ...");
652 /*-----------------------------------------------------------------*/
653 get_traffic_statistics();
654 }
655
656 /*-----------------------------------------------------------------*/
657 printf("Parsing class defintion file %s ...\n", hosts);
658 /*-----------------------------------------------------------------*/
659 parse_hosts(hosts);
660
661 /*-----------------------------------------------------------------*/
662 /* cll1.h - let's allocate brand new character buffer... */
663 /*-----------------------------------------------------------------*/
664 string(str,STRLEN);
665
666 /*-----------------------------------------------------------------*/
667 puts("Resolving shared connections ...");
668 /*-----------------------------------------------------------------*/
669 for_each(ip,ips) if(ip->sharing)
670 {
671 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))
672 {
673 sharedip->traffic+=ip->traffic;
674 ip->traffic=0;
675 ip->mark=sharedip->mark;
676 ip->lmsid=sharedip->lmsid;
677 break;
678 }
679 if(not sharedip)
680 {
681 printf("Unresolved shared connection: %s %s sharing-%s\n",
682 ip->addr, ip->name, ip->sharing);
683 }
684 }
685
686 if(enable_credit && just_flush<9)
687 {
688 /*-----------------------------------------------------------------*/
689 printf("Parsing credit file %s ...\n", credit);
690 /*-----------------------------------------------------------------*/
691 parse(credit)
692 {
693 ptr=parse_datafile_line(_);
694 if(ptr)
695 {
696 if_exists(ip,ips,eq(ip->addr,_))
697 {
698 sscanf(ptr,"%Lu",&(ip->credit));
699 }
700 }
701 }
702 done; /* ugly macro end */
703 }
704
705 if(!just_preview)
706 {
707 /*-----------------------------------------------------------------*/
708 puts("Initializing iptables and tc classes ...");
709 /*-----------------------------------------------------------------*/
710
711 iptables_file=fopen(iptablesfile,"w");
712 if(iptables_file == NULL)
713 {
714 puts("Cannot open iptablesfile!");
715 exit(-1);
716 }
717
718 log_file=fopen(cmdlog,"w");
719 if(log_file == NULL)
720 {
721 puts("Cannot open logfile!");
722 exit(-1);
723 }
724
725 save_line(iptablespreamble);
726 run_restore();
727
728 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
729 safe_run(str);
730
731 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
732 safe_run(str);
733
734 iptables_file=fopen(iptablesfile,"w");
735 save_line(iptablespreamble);
736
737 if(qos_free_zone && *qos_free_zone!='0')
738 {
739 char *chain;
740
741 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
742 save_line(str);
743
744 if(qos_proxy)
745 {
746 save_line(":post_noproxy - [0:0]");
747 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);
748 save_line(str);
749 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);
750 save_line(str);
751 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
752 save_line(str);
753
754 chain="post_noproxy";
755 }
756 else
757 {
758 chain="POSTROUTING";
759 }
760
761 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
762 save_line(str);
763 }
764
765 if(ip_count>idxtable_treshold1 && !just_flush)
766 {
767 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
768 char *subnet, *buf;
769 /*-----------------------------------------------------------------*/
770 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
771 /*-----------------------------------------------------------------*/
772
773 save_line(":post_common - [0:0]");
774 save_line(":forw_common - [0:0]");
775
776 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
777 {
778 buf=index_id(ip->addr,bitmask);
779 if_exists(idx,idxs,eq(idx->id,buf))
780 {
781 idx->children++;
782 }
783 else
784 {
785 create(idx,Index);
786 idx->addr=ip->addr;
787 idx->id=buf;
788 idx->bitmask=bitmask;
789 idx->parent=NULL;
790 idx->children=0;
791 idxcount++;
792 push(idx,idxs);
793 }
794 }
795
796 /* brutal perfomance optimalization */
797 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
798 {
799 bitmask-=idxtable_bitmask2;
800 idxcount=0;
801
802 for_each(idx,idxs) if(idx->parent == NULL)
803 {
804 buf=index_id(idx->addr,bitmask);
805 if_exists(metaindex,idxs,eq(metaindex->id,buf))
806 {
807 metaindex->children++;
808 }
809 else
810 {
811 create(metaindex,Index);
812 metaindex->addr=idx->addr;
813 metaindex->id=buf;
814 metaindex->bitmask=bitmask;
815 metaindex->parent=NULL;
816 metaindex->children=0;
817 idxcount++;
818 push(metaindex,idxs);
819 }
820 idx->parent=metaindex;
821 }
822 }
823
824 /* this should slightly optimize throughout ... */
825 sort(idx,idxs,desc_order_by,children);
826 sort(idx,idxs,order_by,bitmask);
827
828 i=0;
829 for_each(idx,idxs)
830 {
831 subnet=subnet_id(idx->addr,idx->bitmask);
832 printf("%d: %s/%d\n",
833 ++i, subnet, idx->bitmask);
834
835 sprintf(str,":post_%s - [0:0]", idx->id);
836 save_line(str);
837
838 sprintf(str,":forw_%s - [0:0]", idx->id);
839 save_line(str);
840
841 if(idx->parent)
842 {
843 string(buf,strlen(idx->parent->id)+6);
844 sprintf(buf,"post_%s",idx->parent->id);
845 }
846 else
847 {
848 buf="POSTROUTING";
849 }
850
851 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
852 save_line(str);
853
854 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
855 save_line(str);
856
857 if(idx->parent)
858 {
859 string(buf,strlen(idx->parent->id)+6);
860 sprintf(buf,"forw_%s",idx->parent->id);
861 }
862 else
863 {
864 buf="FORWARD";
865 }
866
867 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
868 save_line(str);
869
870 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
871 save_line(str);
872 }
873 printf("Total indexed iptables chains created: %d\n", i);
874
875 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
876 save_line(str);
877
878 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
879 save_line(str);
880 }
881
882 }
883
884 if(just_flush)
885 {
886 fclose(iptables_file);
887 if(log_file)
888 {
889 fclose(log_file);
890 }
891 puts("Just flushed iptables and tc classes - now exiting ...");
892 exit(0);
893 }
894
895 if(!just_preview)
896 {
897 if(!dry_run && !nodelay && qos_free_delay)
898 {
899 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
900 sleep(qos_free_delay);
901 }
902
903 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
904 tc,lan,htb_r2q);
905 safe_run(str);
906
907 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
908 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
909 safe_run(str);
910
911 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
912 tc,lan,line,line,burst_main,highest_priority);
913 safe_run(str);
914
915 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
916 safe_run(str);
917
918 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
919 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
920 safe_run(str);
921
922 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
923 tc,wan,up,up,burst_main,highest_priority);
924 safe_run(str);
925 }
926
927 /*-----------------------------------------------------------------*/
928 puts("Locating heavy downloaders and generating root classes ...");
929 /*-----------------------------------------------------------------*/
930 sort(ip,ips,desc_order_by,traffic);
931
932 /*-----------------------------------------------------------------*/
933 /* sub-scope - local variables */
934 {
935 long long int rate = line;
936 long long int max = line;
937 int group_count = 0;
938 FILE *credit_file = NULL;
939
940 if(!just_preview && !dry_run && enable_credit)
941 {
942 credit_file = fopen(credit,"w");
943 }
944
945 for_each(group,groups)
946 {
947 if(!just_preview)
948 {
949 //download
950 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",
951 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
952 safe_run(str);
953
954 //upload
955 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",
956 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
957 safe_run(str);
958 }
959
960 if(group_count++ < max_nesting)
961 {
962 parent = group->id;
963 }
964
965 rate -= digital_divide*group->min;
966 if(rate < group->min)
967 {
968 rate = group->min;
969 }
970
971 /*shaping of aggresive downloaders, with credit file support */
972 if(use_credit)
973 {
974 int group_rate = group->min, priority_sequence = lowest_priority;
975
976 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
977 {
978 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));
979 if( ip->keyword->data_limit
980 and not ip->fixedprio
981 and ip->traffic > ip->realquota )
982 {
983 if(group_rate < ip->max)
984 {
985 ip->max = group_rate;
986 }
987 group_rate+=magic_treshold;
988 ip->prio=lowest_priority;
989 if(ip->prio<highest_priority+2)
990 {
991 ip->prio=highest_priority+2;
992 }
993 }
994 else
995 {
996 if( ip->keyword->data_prio
997 && !ip->fixedprio
998 && ( ip->traffic>ip->credit
999 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1000 {
1001 ip->prio=priority_sequence--;
1002 if(ip->prio<highest_priority+1)
1003 {
1004 ip->prio=highest_priority+1;
1005 }
1006 }
1007
1008 if(credit_file)
1009 {
1010 unsigned long long lcredit=0;
1011
1012 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1013 {
1014 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1015 }
1016 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1017 }
1018 }
1019 }
1020 }
1021 }
1022 if(credit_file)
1023 {
1024 fclose(credit_file);
1025 }
1026 }
1027
1028 if(just_preview)
1029 {
1030 if(start_shaping)
1031 {
1032 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap);
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 ip->mark=atoi(ptr);
1043 if(ip->max < ip->desired) /* apply FUP limit immediately.... */
1044 {
1045 printf("Applying limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1046 printf("(down: %dk-%dk ", ip->min, ip->max);
1047 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1048 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1049 safe_run(str);
1050 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1051 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1052 sprintf(str,"%s class change 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 }
1059 }
1060 }
1061 fail
1062 {
1063 perror(classmap);
1064 puts("Warning - classmap file not fund, just generating preview ...");
1065 start_shaping=FALSE;
1066 }
1067 done; /* ugly macro end */
1068 }
1069 html=preview;
1070 json_traffic=json_preview;
1071 }
1072
1073 if(!dry_run && !just_flush)
1074 {
1075 /*-----------------------------------------------------------------*/
1076 printf("Writing json traffic overview %s ... ", json_traffic);
1077 /*-----------------------------------------------------------------*/
1078 write_json_traffic(json_traffic);
1079 }
1080
1081 /*-----------------------------------------------------------------*/
1082 printf("Writing statistics into HTML page %s ...\n", html);
1083 /*-----------------------------------------------------------------*/
1084 write_htmlandlogs(html, d,total, just_preview);
1085
1086 if(just_preview)
1087 {
1088 char swchar='p';
1089 if(start_shaping)
1090 {
1091 swchar='s';
1092 }
1093 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);
1094 exit(0);
1095 }
1096
1097 i=0;
1098 #ifdef DEBUG
1099 printf("%-22s %-15s mark\n","name","ip");
1100 #endif
1101
1102 printf("Writing %s ... ", classmap);
1103 f = fopen(classmap, "w");
1104 if(f < 0)
1105 {
1106 perror(classmap);
1107 }
1108
1109 /*-----------------------------------------------------------------*/
1110 puts("Generating iptables and tc classes ... ");
1111 /*-----------------------------------------------------------------*/
1112
1113 for_each(ip, ips) if(ip->mark > 0)
1114 {
1115 if(idxs)
1116 {
1117 char *buf;
1118 duplicate(ip->addr,buf);
1119 buf=index_id(ip->addr,32-idxtable_bitmask1);
1120
1121 string(chain_forward,6+strlen(buf));
1122 strcpy(chain_forward,"forw_");
1123 strcat(chain_forward,buf);
1124
1125 string(chain_postrouting,6+strlen(buf));
1126 strcpy(chain_postrouting,"post_");
1127 strcat(chain_postrouting,buf);
1128
1129 free(buf);
1130 }
1131 else
1132 {
1133 chain_forward="FORWARD";
1134 chain_postrouting="POSTROUTING";
1135 }
1136
1137 #ifdef DEBUG
1138 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1139 #endif
1140
1141 /* -------------------------------------------------------- mark download */
1142
1143 sprintf(str, "-A %s -d %s/32 -o %s -j %s%d",
1144 chain_postrouting, ip->addr, lan, mark_iptables, ip->mark);
1145 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1146 /* -m limit --limit 1/s */
1147 save_line(str);
1148
1149 if(qos_proxy)
1150 {
1151 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
1152 chain_postrouting, proxy_ip, proxy_port, ip->addr, lan, mark_iptables, ip->mark);
1153 /*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);*/
1154 save_line(str);
1155 }
1156
1157 sprintf(str, "-A %s -d %s/32 -o %s -j ACCEPT",
1158 chain_postrouting, ip->addr, lan);
1159 save_line(str);
1160
1161 /* -------------------------------------------------------- mark upload */
1162 sprintf(str, "-A %s -s %s/32 -o %s -j %s%d",
1163 chain_forward, ip->addr, wan, mark_iptables, ip->mark);
1164 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1165 save_line(str);
1166
1167 sprintf(str, "-A %s -s %s/32 -o %s -j ACCEPT",
1168 chain_forward, ip->addr, wan);
1169 save_line(str);
1170
1171 if(ip->min)
1172 {
1173 /* -------------------------------------------------------- download class */
1174 #ifdef DEBUG
1175 printf("(down: %dk-%dk ", ip->min, ip->max);
1176 #endif
1177
1178 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1179 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1180 safe_run(str);
1181
1182 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1183 {
1184 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1185 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1186 safe_run(str);
1187 }
1188
1189 if(filter_type == 1)
1190 {
1191 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1192 tc, lan, ip->mark, ip->mark);
1193 safe_run(str);
1194 }
1195
1196 /* -------------------------------------------------------- upload class */
1197 #ifdef DEBUG
1198 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1199 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1200 #endif
1201
1202 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1203 tc, wan, ip->group, ip->mark,
1204 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1205 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1206 safe_run(str);
1207
1208 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1209 {
1210 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1211 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1212 safe_run(str);
1213 }
1214
1215 if(filter_type == 1)
1216 {
1217 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1218 tc, wan, ip->mark, ip->mark);
1219 safe_run(str);
1220 }
1221
1222 if(f > 0)
1223 {
1224 fprintf(f, "%s %d\n", ip->addr, ip->mark);
1225 }
1226 }
1227 else
1228 {
1229 #ifdef DEBUG
1230 printf("(sharing %s)\n", ip->sharing);
1231 #endif
1232 }
1233 i++;
1234 }
1235 if(f > 0)
1236 {
1237 puts("done.");
1238 fclose(f);
1239 }
1240
1241 if(idxs)
1242 {
1243 chain_forward = "forw_common";
1244 chain_postrouting = "post_common";
1245 }
1246 else
1247 {
1248 chain_forward = "FORWARD";
1249 chain_postrouting = "POSTROUTING";
1250 }
1251 /* -------------------------------- classify or reject free download */
1252 {
1253 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
1254 if(free_min)
1255 {
1256 final_chain = "ACCEPT";
1257 }
1258 if(qos_proxy)
1259 {
1260 if(free_min)
1261 {
1262 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
1263 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
1264 save_line(str);
1265 }
1266 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
1267 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
1268 save_line(str);
1269 }
1270 if(free_min)
1271 {
1272 sprintf(str,"-A %s -o %s -j %s%d", chain_postrouting, lan, mark_iptables, 3);
1273 save_line(str);
1274 }
1275 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
1276 save_line(str);
1277 /* ------------------------------- classify or reject free upload */
1278 if(free_min)
1279 {
1280 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);
1281 save_line(str);
1282 }
1283 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);
1284 save_line(str);
1285 }
1286
1287 if(free_min) /* allocate free bandwith if it is not zero... */
1288 {
1289 /*-----------------------------------------------------------------*/
1290 puts("Generating free bandwith classes ...");
1291 /*-----------------------------------------------------------------*/
1292 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1293 tc, lan, parent, free_min, free_max,burst, lowest_priority);
1294 safe_run(str);
1295 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
1296 tc, wan, parent, free_min, free_max, burst, lowest_priority);
1297 safe_run(str);
1298 /* tc SFQ */
1299 if(strcmpi(qos_leaf, "none"))
1300 {
1301 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);
1302 safe_run(str);
1303
1304 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);
1305 safe_run(str);
1306 }
1307 /* tc handle 1 fw flowid */
1308 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);
1309 safe_run(str);
1310
1311 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);
1312 safe_run(str);
1313 }
1314 printf("Total IP count: %d\n", i);
1315 run_restore();
1316 if(log_file)
1317 {
1318 fclose(log_file);
1319 }
1320 return 0;
1321 /* that's all folks, thank you for reading it all the way up to this point ;-) */
1322 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
1323 }
This page took 1.108163 seconds and 5 git commands to generate.