64012559235dc72987d087318984737e747a92bf
[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-2012 Michael Polak, Arachne Labs */
6 /* iptables-restore support Copyright(C) 2007-2008 ludva */
7 /* Credit: CZFree.Net,Martin Devera,Netdave,Aquarius,Gandalf */
8 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
9
10 /* Modified by: xChaos, 20120612
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 #define STRLEN 512
30 #define FIRSTGROUPID 1024
31 #define FIRSTIPCLASS 2048
32 #undef DEBUG
33
34 #include "cll1-0.6.2.h"
35
36 const char *version = "0.8.3-f";
37
38 /* Version numbers: 0.8.3 is development releases ("beta"), 0.8.4 will be "stable" */
39 /* Debian(RPM) package versions/patchlevels: 0.7.9-2, 0.8.0-1, 0.8.0-2, etc. */
40 /* C source code development versions ("beta"): 0.7.9-a, 0.8.1-b, etc. */
41 /* C source code release versions: 0.8.0, 0.8.2, 0.8.4, etc. */
42
43 const char *stats_html_signature = "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2012 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";
44
45 /* ======= All path names are defined here (for RPM patch) ======= */
46
47 const char *tc = "/sbin/tc"; /* requires tc with HTB support */
48 const char *iptables = "/sbin/iptables"; /* requires iptables utility */
49 const char *iptablessave = "/sbin/iptables-save"; /* not yet required */
50 const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */
51 const char *ls = "/bin/ls"; /* this is not user configurable :-) */
52
53 char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */
54 char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */
55
56 char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/
57 char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */
58 char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */
59 char *html = "/var/www/traffic.html"; /* hall of fame - html version */
60 char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */
61 char *json = "/var/www/logs/traffic.json"; /* hall of fame - json version */
62 char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */
63 char *cmdlog = "/var/log/prometheuslog"; /* command log filename */
64 char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */
65 char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */
66 char *html_log_dir = "/var/www/logs/html/";
67
68 char *jquery_url = "http://code.jquery.com/jquery-latest.js";
69 char *lms_url = "/lms/?m=customerinfo&amp;id=";
70 int use_jquery_popups = 1;
71 int row_odd_even = 0; /*<tr class="odd/even"> */
72
73
74 void parse_ip_log(int argc, char **argv);
75 /* implementid in parselog.c */
76
77 const char *tr_odd_even(void)
78 {
79 row_odd_even = 1 - row_odd_even;
80 if(row_odd_even)
81 {
82 return "<tr class=\"even\">\n";
83 }
84 else
85 {
86 return "<tr class=\"odd\">\n";
87 }
88 }
89
90 /* ======= Help screen is hopefuly self-documenting part of code :-) ======= */
91
92 void help(void)
93 {
94 puts("Command line switches:\n\
95 \n\
96 -d Dry run (preview tc and iptables commands on stdout)\n\
97 -r Run (reset all statistics and start shaping - daily usage)\n\
98 -p just generate Preview of data transfer statistics and exit (after -r)\n\
99 -s start Shaping FUP limits (keeps data transfer stat like -p) (after -r)\n\
100 -n run Now (like -r delay - overrides qos-free-delay keyword, after boot)\n\
101 -f just Flush iptables and tc classes and exit (stop shaping, no QiS)\n\
102 -9 emergency iptables flush (like -f, but dumps data transfer statistics)\n\
103 \n\
104 -c filename force alternative /etc/prometheus/prometheus.conf filename\n\
105 -h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\
106 -l Mmm YYYY generate HTML summary of Logged traffic (Mmm=Jan-Dec) (and exit)\n\
107 -m generate HTML summary of traffic for yesterday's Month (and exit)\n\
108 -y generate HTML summary of traffic for yesterday's Year (and exit)\n\
109 -? --help show this help scree (and exit)\n\
110 -v --version show Version number of this utility (and exit)\n");
111 }
112
113 /* === Configuraration file values defaults - stored in global variables ==== */
114
115 int filter_type = 1; /*1 mark, 2 classify*/
116 char *mark = "MARK";
117 char *mark_iptables = "MARK --set-mark ";
118 int dry_run = 0; /* preview - use puts() instead of system() */
119 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]";
120 FILE *iptables_file = NULL;
121 int enable_credit = 1; /* enable credit file */
122 int use_credit = 0; /* use credit file (if enabled)*/
123 char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */
124 int hall_of_fame = 1; /* enable hall of fame */
125 char *lan = "eth0"; /* LAN interface */
126 char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
127 char *wan = "eth1"; /* WAN/ISP interface */
128 char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */
129 char *qos_leaf = "sfq perturb 5"; /* leaf discipline */
130 char *qos_free_zone = NULL; /* QoS free zone */
131 int qos_proxy = 1; /* include proxy port to QoS */
132 int found_lmsid = 0; /* show links to users in LMS information system */
133 int include_upload = 1; /* upload+download=total traffic */
134 char *proxy_ip = "192.168.1.1/32"; /* our IP with proxy port */
135 int proxy_port = 3128; /* proxy port number */
136 long long int line = 1024; /* WAN/ISP download in kbps */
137 long long int up = 1024; /* WAN/ISP upload in kbps */
138 int free_min = 32; /* minimum guaranted bandwidth for all undefined hosts */
139 int free_max = 64; /* maximum allowed bandwidth for all undefined hosts */
140 int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */
141 int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */
142 int max_nesting = 3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */
143 int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */
144 int burst = 8; /* HTB burst (in kbits) */
145 int burst_main = 64;
146 int burst_group = 32;
147 int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */
148 int keywordcount = 0;
149 /* not yet implemented:
150 int fixed_packets = 0; maximum number of pps per IP address (not class!)
151 int packet_limit = 5; maximum number of pps to htn CEIL, not rate !!!
152 */
153 FILE *log_file = NULL;
154 char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */
155
156 const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */
157 const int lowest_priority = 7; /* lowest HTB priority (HTB built-in value is 7) */
158 const int idxtable_treshold1 = 24; /* this is no longer configurable */
159 const int idxtable_treshold2 = 12; /* this is no longer configurable */
160 const int idxtable_bitmask1 = 3; /* this is no longer configurable */
161 const int idxtable_bitmask2 = 3; /* this is no longer configurable */
162
163 /* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */
164
165 struct IP
166 {
167 char *addr;
168 char *name;
169 char *sharing;
170 int min;
171 int desired;
172 int max;
173 int mark;
174 int prio;
175 int fixedprio;
176 int group;
177 int lmsid;
178 unsigned long long direct;
179 unsigned long long proxy;
180 unsigned long long upload;
181 unsigned long long traffic;
182 unsigned long long credit;
183 unsigned long pktsup;
184 unsigned long pktsdown;
185 struct Keyword *keyword;
186 list(IP);
187 } *ips=NULL, *ip, *sharedip;
188
189 struct Group
190 {
191 int min;
192 int count;
193 int desired;
194 int id;
195 list(Group);
196 } *groups=NULL, *group;
197
198 struct Index
199 {
200 char *addr;
201 char *id;
202 struct Index *parent;
203 int bitmask;
204 int children;
205 list(Index);
206 } *idxs=NULL, *idx, *metaindex;
207
208 struct Keyword
209 {
210 char *key;
211
212 int asymetry_ratio; /* ratio for ADSL-like upload */
213 int asymetry_fixed; /* fixed treshold for ADSL-like upload */
214 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
215 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
216 long fixed_limit; /* fixed data limit for setting lower HTB ceil */
217 long fixed_prio; /* fixed data lmit for setting lower HTB prio */
218 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */
219 int reserve_max; /* malus for nominal HTB ceil (in kbps) */
220 // int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */
221 // int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */
222 int default_prio; /* default HTB priority for this keyword */
223 char *html_color;
224 int ip_count;
225 char *leaf_discipline;
226
227 list(Keyword);
228 } *keyword,*defaultkeyword=NULL,*keywords=NULL;
229
230 /* Damned, this must be object oriented! This looks almost like constructor ;-) */
231
232 void TheIP(void)
233 {
234 create(ip,IP);
235 ip->name = "";
236 ip->addr = "";
237 ip->sharing = NULL;
238 ip->prio = highest_priority+1;
239 ip->lmsid = -1;
240 ip->fixedprio = \
241 ip->mark = \
242 ip->min = \
243 ip->max = \
244 ip->desired = \
245 ip->credit = \
246 ip->upload = \
247 ip->proxy = \
248 ip->direct = \
249 ip->traffic = \
250 ip->pktsup = \
251 ip->pktsdown = 0;
252 ip->keyword = keywords;
253 push(ip,ips);
254 }
255
256 /* ====== iptables indexes are used to reduce complexity to log8(N) ===== */
257
258 char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)
259 {
260 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/
261 int dot=0, n;
262 char *ip,*outip,*outptr,*fmt;
263
264 duplicate(inip,ip);
265 /* debug printf("(%s,%d) -> ",ip,bitmask); */
266
267 if(ip && *ip && bitmask>=0 && bitmask<=32)
268 {
269 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */
270 }
271 else
272 {
273 /* should never exit here */
274 return "undefined";
275 }
276 outptr=outip;
277 while(ip && *ip)
278 {
279 if(*ip=='.')
280 {
281 if(dot<(bitmask/8-1))
282 {
283 if(format_as_chainname)
284 {
285 *outptr='_';
286 }
287 else
288 {
289 *outptr='.';
290 }
291 outptr++;
292 dot++;
293 }
294 else
295 {
296 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/
297 if(cutdot)
298 {
299 *cutdot = '\0';
300 }
301
302 if(format_as_chainname)
303 {
304 fmt = "_%d_%d";
305 }
306 else
307 {
308 fmt = ".%d";
309 }
310
311 if(bitmask%8)
312 {
313 n = atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));
314 }
315 else
316 {
317 n = 0;
318 }
319
320 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */
321 sprintf(outptr,fmt,n,bitmask);
322 if(!format_as_chainname)
323 {
324 while(bitmask<24)
325 {
326 strcat(outip,".0");
327 bitmask+=8;
328 }
329 }
330 /* debug printf("[%s]\n",outip); */
331 return outip;
332 }
333 }
334 else
335 {
336 *outptr=*ip;
337 outptr++;
338 }
339 ip++;
340 }
341 /*should never exit here*/
342 *outptr='\0';
343 return outip;
344 }
345
346 char *hash_id(char *ip,int bitmask)
347 {
348 return very_ugly_ipv4_code(ip,bitmask,1);
349 }
350
351 char *subnet_id(char *ip,int bitmask)
352 {
353 return very_ugly_ipv4_code(ip,bitmask,0);
354 }
355
356 /* ================= Let's parse configuration file here =================== */
357
358 void reject_config_and_exit(char *filename)
359 {
360 printf("Configuration file %s rejected - abnormal exit.",filename);
361 exit(-1);
362 }
363
364 void get_config(char *config_filename)
365 {
366 char *cnf="mark";
367
368 printf("Configured keywords: ");
369 parse(config_filename)
370 {
371 option("keyword",kwd);
372 if(kwd)
373 {
374 printf("%s ",kwd);
375
376 create(keyword,Keyword);
377 keyword->key=kwd;
378 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */
379 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */
380 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */
381 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */
382 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */
383 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */
384 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */
385 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */
386 keyword->default_prio=highest_priority+1;
387 keyword->html_color="000000";
388 keyword->ip_count=0;
389 keyword->leaf_discipline="";
390
391 push(keyword,keywords);
392 if(!defaultkeyword) defaultkeyword=keyword;
393 keywordcount++;
394
395 kwd=NULL;
396 }
397 else
398 {
399 for_each(keyword,keywords)
400 {
401 int l=strlen(keyword->key);
402
403 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)
404 {
405 char *tmptr=_; /* <---- l+1 ----> */
406 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */
407 ioption("asymetry-ratio",keyword->asymetry_ratio);
408 ioption("asymetry-treshold",keyword->asymetry_fixed);
409 ioption("magic-relative-limit",keyword->data_limit);
410 ioption("magic-relative-prio",keyword->data_prio);
411 loption("magic-fixed-limit",keyword->fixed_limit);
412 loption("magic-fixed-prio",keyword->fixed_prio);
413 ioption("htb-default-prio",keyword->default_prio);
414 ioption("htb-rate-bonus",keyword->reserve_min);
415 ioption("htb-ceil-malus",keyword->reserve_max);
416 option("leaf-discipline",keyword->leaf_discipline);
417 option("html-color",keyword->html_color);
418 _=tmptr;
419
420 if(keyword->data_limit || keyword->fixed_limit ||
421 keyword->data_prio || keyword->fixed_prio)
422 {
423 use_credit=1;
424 }
425 }
426 }
427 }
428
429 option("tc",tc);
430 option("iptables",iptables);
431 option("iptables-save",iptablessave); /* new */
432 option("iptables-restore",iptablesrestore); /* new */
433 option("iptables-in-filename",iptablesfile); /* new */
434 option("hosts",hosts);
435 option("lan-interface",lan);
436 option("wan-interface",wan);
437 option("lan-medium",lan_medium);
438 option("wan-medium",wan_medium);
439 lloption("wan-download",line);
440 lloption("wan-upload",up);
441 ioption("hall-of-fame-enable",hall_of_fame);
442 option("hall-of-fame-title",title);
443 option("hall-of-fame-filename",html);
444 option("json-filename",json);
445 option("hall-of-fame-preview",preview);
446 option("json-preview",json_preview);
447 option("log-filename",cmdlog);
448 option("credit-filename",credit);
449 option("classmap-filename",classmap);
450 ioption("credit-enable",enable_credit);
451 option("log-traffic-directory",log_dir);
452 option("log-traffic-html-directory",html_log_dir);
453 option("log-traffic-url-path",log_url);
454 option("jquery-url",jquery_url);
455 option("lms-url",lms_url);
456 ioption("use-jquery-popups",use_jquery_popups);
457 option("qos-free-zone",qos_free_zone);
458 ioption("qos-free-delay",qos_free_delay);
459 ioption("qos-proxy-enable",qos_proxy);
460 option("qos-proxy-ip",proxy_ip);
461 option("htb-leaf-discipline",qos_leaf);
462 ioption("qos-proxy-port",proxy_port);
463 ioption("free-rate",free_min);
464 ioption("free-ceil",free_max);
465 ioption("htb-burst",burst);
466 ioption("htb-burst-main",burst_main);
467 ioption("htb-burst-group",burst_group);
468 ioption("htb-nesting-limit",max_nesting);
469 ioption("htb-r2q",htb_r2q);
470 ioption("magic-include-upload",include_upload);
471 ioption("magic-treshold",magic_treshold);
472 option("filter-type", cnf);
473 /* not yet implemented:
474 ioption("magic-fixed-packets",fixed_packets);
475 ioption("magic-relative-packets",packet_limit);
476 */
477 }
478 fail
479 {
480 perror(config_filename);
481 puts("Warning - using built-in defaults instead ...");
482 }
483 done; /* ugly macro end */
484 printf("\n");
485
486 /* leaf discipline for keywords */
487 for_each(keyword,keywords)
488 {
489 if(!strcmpi(keyword->leaf_discipline, ""))
490 {
491 keyword->leaf_discipline = qos_leaf;
492 }
493 }
494
495 if(strcmpi(cnf, "mark"))
496 {
497 filter_type = 2;
498 mark = "CLASSIFY";
499 mark_iptables = "CLASSIFY --set-class 1:";
500 }
501 else
502 {
503 filter_type = 1;
504 mark = "MARK";
505 mark_iptables = "MARK --set-mark ";
506 }
507
508 /* are supplied values meaningful ?*/
509 if(line<=0 || up<=0)
510 {
511 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");
512 reject_config_and_exit(config_filename);
513 }
514 }
515
516 /* ===================== traffic analyser - uses iptables ================ */
517
518 void get_traffic_statistics(void)
519 {
520 char *str,*cmd;
521 int downloadflag=0;
522
523 textfile(Pipe,str) *line,*lines=NULL;
524 string(str,STRLEN);
525 string(cmd,STRLEN);
526
527 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);
528 shell(cmd);
529 input(str,STRLEN)
530 {
531 create(line,Pipe);
532 line->str=str;
533 string(str,STRLEN);
534 append(line,lines);
535 }
536
537 for_each(line,lines)
538 {
539 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0;
540 unsigned long long traffic=0;
541 unsigned long pkts=0;
542 char *ipaddr=NULL,*ptr;
543
544 /* debug puts(line->str); */
545 valid_columns(ptr,line->str,' ',col)
546 if(valid) switch(col)
547 {
548 case 1: if(eq(ptr,"Chain"))
549 {
550 setchainname=1;
551 }
552 else if(eq(ptr,"pkts"))
553 {
554 valid=0;
555 }
556 else
557 {
558 sscanf(ptr,"%lu",&pkts);
559 }
560 break;
561 case 2: if(setchainname)
562 {
563 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))
564 {
565 downloadflag = 1;
566 }
567 else
568 {
569 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))
570 {
571 downloadflag = 0;
572 }
573 }
574 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))
575 {
576 commonflag = 1;
577 }
578 }
579 else
580 {
581 sscanf(ptr,"%Lu",&traffic);
582 traffic += (1<<19);
583 traffic >>= 20;
584 }
585 break;
586 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)
587 {
588 accept=eq(ptr,mark);
589 }
590 /*if(filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/
591 break;
592 case 8: if(downloadflag)
593 {
594 if(strstr(proxy_ip,ptr))
595 {
596 proxyflag=1;
597 }
598 }
599 else
600 {
601 ipaddr=ptr;
602 }
603 break;
604 case 9: if(downloadflag)ipaddr=ptr;break;
605 }
606
607 if(accept && traffic>0 && ipaddr)
608 {
609 if(proxyflag)
610 {
611 printf("(proxy) ");
612 }
613 else if(!downloadflag)
614 {
615 printf("(upload) ");
616 }
617 printf("IP %s: %Lu MB (%ld pkts)\n", ipaddr, traffic, pkts);
618
619 if_exists(ip,ips,eq(ip->addr,ipaddr));
620 else
621 {
622 TheIP();
623 ip->addr=ipaddr;
624 if(eq(ip->addr,"0.0.0.0/0"))
625 {
626 ip->name="(unregistered)";
627 ip->min=free_min;
628 ip->max=ip->desired=free_max;
629 }
630 }
631
632 if(downloadflag)
633 {
634 if(proxyflag)
635 {
636 ip->proxy=traffic;
637 }
638 else
639 {
640 ip->traffic+=traffic;
641 }
642 ip->direct=ip->traffic-ip->upload-ip->proxy;
643 ip->pktsdown=pkts;
644 }
645 else
646 {
647 ip->upload=traffic;
648 ip->pktsup=pkts;
649 if(include_upload)
650 {
651 ip->traffic+=traffic;
652 }
653 else
654 {
655 if(traffic>ip->traffic)
656 {
657 ip->traffic=traffic;
658 }
659 }
660 }
661 }
662 }
663 free(cmd);
664 }
665
666 /* ========== This function executes, logs OR ALSO prints command ========== */
667
668 void safe_run(char *cmd)
669 {
670 if(dry_run)
671 {
672 printf("\n=>%s\n",cmd);
673 }
674 else
675 {
676 system(cmd);
677 }
678 if(log_file)
679 {
680 fprintf(log_file,"%s\n",cmd);
681 }
682 }
683
684 void save_line(char *line)
685 {
686 fprintf(iptables_file,"%s\n",line);
687 }
688
689 void run_restore(void)
690 {
691 char *restor;
692 string(restor,STRLEN);
693
694 /*-----------------------------------------------------------------*/
695 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);
696 /*-----------------------------------------------------------------*/
697
698 save_line("COMMIT");
699 fclose(iptables_file);
700 if(dry_run)
701 {
702 parse(iptablesfile)
703 {
704 printf("%s\n",_);
705 }
706 done; /* ugly macro end */
707 }
708
709 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);
710 safe_run(restor);
711
712 free(restor);
713 }
714
715 /* == This function strips extra characters after IP address and stores it = */
716
717 void parse_ip(char *str)
718 {
719 char *ptr,*ipaddr=NULL,*ipname=NULL,*lmsid=NULL;
720
721 ptr=strchr(str,'{');
722 if(ptr)
723 {
724 lmsid=++ptr;
725 while(*ptr && *ptr!='}')
726 {
727 ptr++;
728 }
729 *ptr=0;
730 }
731
732 ptr=str;
733 while(*ptr && *ptr!=' ' && *ptr!=9)
734 {
735 ptr++;
736 }
737
738 *ptr=0;
739 ipaddr=str;
740 ptr++;
741 while(*ptr && (*ptr==' ' || *ptr==9))
742 {
743 ptr++;
744 }
745 ipname=ptr;
746 while(*ptr && *ptr!=' ' && *ptr!=9)
747 {
748 ptr++;
749 }
750 *ptr=0;
751
752 if_exists(ip,ips,eq(ip->addr,ipaddr));
753 else
754 {
755 TheIP();
756 }
757 ip->addr=ipaddr;
758 ip->name=ipname;
759 if(lmsid)
760 {
761 ip->lmsid=atoi(lmsid);
762 found_lmsid=1;
763 }
764 }
765
766 char *parse_datafile_line(char *str)
767 {
768 char *ptr=strchr(str,' ');
769
770 if(ptr)
771 {
772 *ptr=0;
773 ptr++;
774 return ptr;
775 }
776 else
777 {
778 return NULL;
779 }
780 }
781
782
783
784
785 void append_log(struct IP *self) /*using global variables*/
786 {
787 char *d, *str;
788 FILE *f;
789
790 date(d); /* this is typical cll1.h macro - prints current date */
791 string(str,STRLEN);
792 sprintf(str,"%s/%s.log", log_dir, self->name);
793 f=fopen(str,"a");
794 if(f > 0)
795 {
796 fprintf(f,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",
797 time(NULL), self->name, self->traffic, self->direct, self->proxy,
798 self->upload, self->min, self->max, self->desired, self->lmsid, d); /* d = date*/
799 fclose(f);
800 }
801 else
802 {
803 perror(str);
804 }
805 }
806
807
808 /*-----------------------------------------------------------------*/
809 /* Are you looking for int main(int argc, char **argv) ? :-)) */
810 /*-----------------------------------------------------------------*/
811
812 program
813 {
814 int i=0; /* just plain old Fortran style integer :-) */
815 FILE *f=NULL; /* everything is just stream of bytes... */
816 char *str, *ptr, *d; /* LET A$=B$ :-) */
817 char *substring;
818 int class_count=0,ip_count=0;
819 int parent=1;
820 int just_flush=FALSE; /* deactivates all previous actions */
821 int nodelay=FALSE;
822 int just_preview=FALSE; /* preview - generate just stats */
823 int start_shaping=FALSE; /* apply FUP - requires classmap file */
824 int just_logs=FALSE; /* just parse logs */
825 int run=FALSE;
826 int total=0;
827
828 char *chain_forward, *chain_postrouting;
829 char *althosts=NULL;
830
831 printf("\n\
832 Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\
833 Version %s - Copyright (C)2005-2012 Michael Polak, Arachne Labs\n\
834 iptables-restore & burst tunning & classify modification by Ludva\n\
835 Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);
836
837 /*----- Boring... we have to check command line options first: ----*/
838 arguments
839 {
840 argument("-c") { nextargument(config); }
841 argument("-h") { nextargument(althosts);}
842 argument("-d") { run=TRUE; dry_run=TRUE; }
843 argument("-f") { run=TRUE; just_flush=TRUE; }
844 argument("-9") { run=TRUE; just_flush=9; }
845 argument("-p") { run=TRUE; just_preview=TRUE; }
846 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }
847 argument("-r") { run=TRUE; }
848 argument("-n") { run=TRUE; nodelay=TRUE; }
849 argument("-l") { just_logs=TRUE; }
850 argument("-m") { just_logs=TRUE; }
851 argument("-y") { just_logs=TRUE; }
852 argument("-?") { help(); exit(0); }
853 argument("--help") { help(); exit(0); }
854 argument("-v") { exit(0); }
855 argument("--version") { exit(0); }
856 }
857
858 if(dry_run)
859 {
860 puts("*** THIS IS JUST DRY RUN ! ***\n");
861 }
862
863 date(d); /* this is typical cll1.h macro - prints current date */
864
865 /*-----------------------------------------------------------------*/
866 printf("Parsing configuration file %s ...\n", config);
867 /*-----------------------------------------------------------------*/
868 get_config(config);
869
870 if(just_logs)
871 {
872 parse_ip_log(argc,argv);
873 exit(0);
874 }
875 else if(not run)
876 {
877 help();
878 exit(0);
879 }
880
881 if(althosts)
882 {
883 hosts=althosts;
884 }
885
886 if(just_flush<9)
887 {
888 /*-----------------------------------------------------------------*/
889 puts("Parsing iptables verbose output ...");
890 /*-----------------------------------------------------------------*/
891 get_traffic_statistics();
892 }
893
894 /*-----------------------------------------------------------------*/
895 printf("Parsing class defintion file %s ...\n", hosts);
896 /*-----------------------------------------------------------------*/
897 int groupidx = FIRSTGROUPID;
898 parse(hosts)
899 {
900 str=_;
901
902 if(*str<'0' || *str>'9')
903 {
904 /* any line starting with non-number is comment ...*/
905 continue;
906 }
907
908 //Does this IP share QoS class with some other ?
909 substring=strstr(str,"sharing-");
910 if(substring)
911 {
912 substring+=8; //"sharing-"
913 parse_ip(str);
914 ip_count++;
915 ip->sharing=substring;
916 ip->keyword=defaultkeyword; /* settings for default keyword */
917 while(*substring && *substring!='\n')
918 {
919 substring++;
920 }
921 *substring=0;
922 }
923 else
924 {
925 //Do we have to create new QoS class for this IP ?
926
927 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))
928 {
929 parse_ip(str);
930 ip_count++;
931 ip->keyword=keyword;
932 keyword->ip_count++;
933 ip->prio=keyword->default_prio;
934 substring+=strlen(keyword->key)+1;
935 ptr=substring;
936 while(*ptr && *ptr!='-')
937 {
938 ptr++;
939 }
940 if(*ptr=='-')
941 {
942 *ptr=0;
943 ip->max = ip->desired=atoi(ptr+1);
944 }
945 ip->min = atoi(substring);
946 if(ip->min <= 0)
947 {
948 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",
949 str, free_min);
950 ip->min = free_min;
951 }
952 if(ip->max <= ip->min)
953 {
954 ip->fixedprio = 1;
955 ip->max = ip->min+ip->keyword->reserve_min;
956 }
957 else
958 {
959 ip->max -= ip->keyword->reserve_max;
960 if(ip->max<ip->min)
961 {
962 ip->max=ip->min;
963 }
964 }
965 ip->mark=FIRSTIPCLASS+1+class_count++;
966
967 if_exists(group,groups,group->min==ip->min)
968 {
969 group->count++;
970 group->desired += ip->min;
971 ip->group = group->id;
972 }
973 else
974 {
975 create(group,Group);
976 group->min = ip->min;
977 group->id = groupidx++;
978 ip->group = group->id;
979
980 if(group->min<8) group->min=8;
981 /* Warning - this is maybe because of primitive tc namespace, can be fixed */
982 /* it is because class IDs are derived from min. bandwidth. - xCh */
983 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;
984
985 group->count=1;
986 group->desired=ip->min;
987 insert(group,groups,desc_order_by,min);
988 }
989 }//endif keyword-
990 }//endif sharing-
991 }
992 fail
993 {
994 perror(hosts);
995 exit(-1);
996 }
997 done; /* ugly macro end */
998
999 /*-----------------------------------------------------------------*/
1000 /* cll1.h - let's allocate brand new character buffer... */
1001 /*-----------------------------------------------------------------*/
1002 string(str,STRLEN);
1003
1004 /*-----------------------------------------------------------------*/
1005 puts("Resolving shared connections ...");
1006 /*-----------------------------------------------------------------*/
1007 for_each(ip,ips) if(ip->sharing)
1008 {
1009 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))
1010 {
1011 sharedip->traffic+=ip->traffic;
1012 ip->traffic=0;
1013 ip->mark=sharedip->mark;
1014 ip->lmsid=sharedip->lmsid;
1015 break;
1016 }
1017 if(!sharedip)
1018 {
1019 printf("Unresolved shared connection: %s %s sharing-%s\n",
1020 ip->addr, ip->name, ip->sharing);
1021 }
1022 }
1023
1024 if(enable_credit && just_flush<9)
1025 {
1026 /*-----------------------------------------------------------------*/
1027 printf("Parsing credit file %s ...\n", credit);
1028 /*-----------------------------------------------------------------*/
1029 parse(credit)
1030 {
1031 ptr=parse_datafile_line(_);
1032 if(ptr)
1033 {
1034 if_exists(ip,ips,eq(ip->addr,_))
1035 {
1036 sscanf(ptr,"%Lu",&(ip->credit));
1037 }
1038 }
1039 }
1040 done; /* ugly macro end */
1041 }
1042
1043 if(!just_preview)
1044 {
1045 /*-----------------------------------------------------------------*/
1046 puts("Initializing iptables and tc classes ...");
1047 /*-----------------------------------------------------------------*/
1048
1049 iptables_file=fopen(iptablesfile,"w");
1050 if(iptables_file == NULL)
1051 {
1052 puts("Cannot open iptablesfile!");
1053 exit(-1);
1054 }
1055
1056 log_file=fopen(cmdlog,"w");
1057 if(log_file == NULL)
1058 {
1059 puts("Cannot open logfile!");
1060 exit(-1);
1061 }
1062
1063 save_line(iptablespreamble);
1064 run_restore();
1065
1066 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);
1067 safe_run(str);
1068
1069 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);
1070 safe_run(str);
1071
1072 iptables_file=fopen(iptablesfile,"w");
1073 save_line(iptablespreamble);
1074
1075 if(qos_free_zone && *qos_free_zone!='0')
1076 {
1077 char *chain;
1078
1079 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);
1080 save_line(str);
1081
1082 if(qos_proxy)
1083 {
1084 save_line(":post_noproxy - [0:0]");
1085 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);
1086 save_line(str);
1087 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);
1088 save_line(str);
1089 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);
1090 save_line(str);
1091
1092 chain="post_noproxy";
1093 }
1094 else
1095 {
1096 chain="POSTROUTING";
1097 }
1098
1099 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);
1100 save_line(str);
1101 }
1102
1103 if(ip_count>idxtable_treshold1 && !just_flush)
1104 {
1105 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */
1106 char *subnet, *buf;
1107 /*-----------------------------------------------------------------*/
1108 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);
1109 /*-----------------------------------------------------------------*/
1110
1111 save_line(":post_common - [0:0]");
1112 save_line(":forw_common - [0:0]");
1113
1114 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))
1115 {
1116 buf=hash_id(ip->addr,bitmask);
1117 if_exists(idx,idxs,eq(idx->id,buf))
1118 {
1119 idx->children++;
1120 }
1121 else
1122 {
1123 create(idx,Index);
1124 idx->addr=ip->addr;
1125 idx->id=buf;
1126 idx->bitmask=bitmask;
1127 idx->parent=NULL;
1128 idx->children=0;
1129 idxcount++;
1130 push(idx,idxs);
1131 }
1132 }
1133
1134 /* brutal perfomance optimalization */
1135 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)
1136 {
1137 bitmask-=idxtable_bitmask2;
1138 idxcount=0;
1139
1140 for_each(idx,idxs) if(idx->parent == NULL)
1141 {
1142 buf=hash_id(idx->addr,bitmask);
1143 if_exists(metaindex,idxs,eq(metaindex->id,buf))
1144 {
1145 metaindex->children++;
1146 }
1147 else
1148 {
1149 create(metaindex,Index);
1150 metaindex->addr=idx->addr;
1151 metaindex->id=buf;
1152 metaindex->bitmask=bitmask;
1153 metaindex->parent=NULL;
1154 metaindex->children=0;
1155 idxcount++;
1156 push(metaindex,idxs);
1157 }
1158 idx->parent=metaindex;
1159 }
1160 }
1161
1162 /* this should slightly optimize throughout ... */
1163 sort(idx,idxs,desc_order_by,children);
1164 sort(idx,idxs,order_by,bitmask);
1165
1166 i=0;
1167 for_each(idx,idxs)
1168 {
1169 subnet=subnet_id(idx->addr,idx->bitmask);
1170 printf("%d: %s/%d\n",
1171 ++i, subnet, idx->bitmask);
1172
1173 sprintf(str,":post_%s - [0:0]", idx->id);
1174 save_line(str);
1175
1176 sprintf(str,":forw_%s - [0:0]", idx->id);
1177 save_line(str);
1178
1179 if(idx->parent)
1180 {
1181 string(buf,strlen(idx->parent->id)+6);
1182 sprintf(buf,"post_%s",idx->parent->id);
1183 }
1184 else
1185 {
1186 buf="POSTROUTING";
1187 }
1188
1189 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);
1190 save_line(str);
1191
1192 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);
1193 save_line(str);
1194
1195 if(idx->parent)
1196 {
1197 string(buf,strlen(idx->parent->id)+6);
1198 sprintf(buf,"forw_%s",idx->parent->id);
1199 }
1200 else
1201 {
1202 buf="FORWARD";
1203 }
1204
1205 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);
1206 save_line(str);
1207
1208 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);
1209 save_line(str);
1210 }
1211 printf("Total indexed iptables chains created: %d\n", i);
1212
1213 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);
1214 save_line(str);
1215
1216 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);
1217 save_line(str);
1218 }
1219
1220 }
1221
1222 if(just_flush)
1223 {
1224 fclose(iptables_file);
1225 if(log_file)
1226 {
1227 fclose(log_file);
1228 }
1229 puts("Just flushed iptables and tc classes - now exiting ...");
1230 exit(0);
1231 }
1232
1233 if(!just_preview)
1234 {
1235 if(!dry_run && !nodelay && qos_free_delay)
1236 {
1237 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);
1238 sleep(qos_free_delay);
1239 }
1240
1241 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",
1242 tc,lan,htb_r2q);
1243 safe_run(str);
1244
1245 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1246 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);
1247 safe_run(str);
1248
1249 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1250 tc,lan,line,line,burst_main,highest_priority);
1251 safe_run(str);
1252
1253 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);
1254 safe_run(str);
1255
1256 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",
1257 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);
1258 safe_run(str);
1259
1260 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",
1261 tc,wan,up,up,burst_main,highest_priority);
1262 safe_run(str);
1263 }
1264
1265 /*-----------------------------------------------------------------*/
1266 puts("Locating heavy downloaders and generating root classes ...");
1267 /*-----------------------------------------------------------------*/
1268 sort(ip,ips,desc_order_by,traffic);
1269
1270 /*-----------------------------------------------------------------*/
1271 /* sub-scope - local variables */
1272 {
1273 long long int rate = line;
1274 long long int max = line;
1275 int group_count = 0;
1276 FILE *credit_file = NULL;
1277
1278 if(!just_preview && !dry_run && enable_credit)
1279 {
1280 credit_file = fopen(credit,"w");
1281 }
1282
1283 for_each(group,groups)
1284 {
1285 if(!just_preview)
1286 {
1287 //download
1288 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",
1289 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);
1290 safe_run(str);
1291
1292 //upload
1293 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",
1294 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);
1295 safe_run(str);
1296 }
1297
1298 if(group_count++ < max_nesting)
1299 {
1300 parent = group->id;
1301 }
1302
1303 rate -= digital_divide*group->min;
1304 if(rate < group->min)
1305 {
1306 rate = group->min;
1307 }
1308
1309 /*shaping of aggresive downloaders, with credit file support */
1310 if(use_credit)
1311 {
1312 int group_rate = group->min, priority_sequence = lowest_priority;
1313
1314 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)
1315 {
1316 if( ip->keyword->data_limit && !ip->fixedprio
1317 && ( ip->traffic>ip->credit
1318 + (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))) )
1319 {
1320 if(group_rate<ip->max)
1321 {
1322 ip->max=group_rate;
1323 }
1324 group_rate+=magic_treshold;
1325 ip->prio=lowest_priority;
1326 if(ip->prio<highest_priority+2)
1327 {
1328 ip->prio=highest_priority+2;
1329 }
1330 }
1331 else
1332 {
1333 if( ip->keyword->data_prio
1334 && !ip->fixedprio
1335 && ( ip->traffic>ip->credit
1336 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )
1337 {
1338 ip->prio=priority_sequence--;
1339 if(ip->prio<highest_priority+1)
1340 {
1341 ip->prio=highest_priority+1;
1342 }
1343 }
1344
1345 if(credit_file)
1346 {
1347 unsigned long long lcredit=0;
1348
1349 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)
1350 {
1351 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;
1352 }
1353 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);
1354 }
1355 }
1356 }
1357 }
1358 }
1359 if(credit_file)
1360 {
1361 fclose(credit_file);
1362 }
1363 }
1364
1365 if(just_preview)
1366 {
1367 if(start_shaping)
1368 {
1369 printf("Reading %s and applying Fair Use Policy rules ... \n", classmap);
1370 parse(classmap)
1371 {
1372 ptr=strchr(_,' ');
1373 if(ptr)
1374 {
1375 *ptr=0;
1376 ptr++;
1377 if_exists(ip,ips,eq(ip->addr,_))
1378 {
1379 ip->mark=atoi(ptr);
1380 if(ip->max < ip->desired) /* apply FUP limit immediately.... */
1381 {
1382 printf("Applying limit for %-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1383 printf("(down: %dk-%dk ", ip->min, ip->max);
1384 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1385 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1386 safe_run(str);
1387 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1388 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1389 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1390 tc, wan, ip->group, ip->mark,
1391 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1392 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1393 safe_run(str);
1394 }
1395 }
1396 }
1397 }
1398 fail
1399 {
1400 perror(classmap);
1401 puts("Warning - classmap file not fund, just generating preview ...");
1402 start_shaping=FALSE;
1403 }
1404 done; /* ugly macro end */
1405 }
1406 html=preview;
1407 json=json_preview;
1408 }
1409
1410 if(!dry_run && !just_flush)
1411 {
1412 /*-----------------------------------------------------------------*/
1413 printf("Writing json overview %s ... ", json);
1414 /*-----------------------------------------------------------------*/
1415 f=fopen(json, "w");
1416 if(f > 0)
1417 {
1418 int jsoncount=0;
1419 fprintf(f, "{\n");
1420 for_each(ip, ips)
1421 {
1422 if( ip->lmsid > 0
1423 && (ip->traffic || ip->direct || ip->proxy || ip->upload))
1424 {
1425 if(jsoncount)
1426 {
1427 fprintf(f, ",\n");
1428 }
1429 fprintf(f, " \"%s\":{ \"lms\": %d, \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu, \"min\":%d, \"max\":%d, \"limit\":%d }",
1430 ip->name, ip->lmsid, ip->addr, ip->traffic, ip->direct, ip->proxy, ip->upload, ip->min, ip->desired, ip->max);
1431 jsoncount++;
1432 }
1433 }
1434 fprintf(f, "}\n");
1435 fclose(f);
1436 puts("done.");
1437 }
1438 else
1439 {
1440 perror(json);
1441 }
1442 }
1443
1444 f=fopen(html,"w");
1445 if(f > 0)
1446 {
1447 int count=1;
1448 i=0;
1449
1450 /*-----------------------------------------------------------------*/
1451 printf("Sorting data and generating statistics page %s ...\n", html);
1452 /*-----------------------------------------------------------------*/
1453
1454 if(use_jquery_popups)
1455 {
1456 fprintf(f,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url);
1457 }
1458 fputs("<table class=\"decorated last\">\n\
1459 <caption>Bandwidth classes</caption>\n\
1460 <thead><tr>\n\
1461 <th style=\"text-align: right\">#</th>\n\
1462 <th style=\"text-align: right\">group</th>\n\
1463 <th style=\"text-align: right\">IPs</th>\n\
1464 <th style=\"text-align: right\">requested</th>\n",f);
1465 fprintf(f,"<th colspan=\"%d\">data limits</th>\n", keywordcount);
1466 fputs("</tr></thead><tbody>\n",f);
1467
1468 row_odd_even = 0;
1469 for_each(group, groups)
1470 {
1471 #ifdef DEBUG
1472 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group->min,group->count,group->desired);
1473 #endif
1474 fprintf(f, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1475 tr_odd_even(), count, group->min);
1476 fprintf(f, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",
1477 group->count, group->desired);
1478
1479 for_each(keyword, keywords) if(keyword->ip_count)
1480 {
1481 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d&nbsp;MB</span></td>",
1482 keyword->html_color, group->min*keyword->data_limit);
1483 }
1484 i += group->desired;
1485 total += group->count;
1486 count++;
1487 }
1488 #ifdef DEBUG
1489 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",
1490 count, i, i/line);
1491 #endif
1492 fprintf(f,"</tr></tbody>\n\
1493 <thead><tr>\n\
1494 <th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line);
1495 fprintf(f,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total,i);
1496
1497 for_each(keyword, keywords) if(keyword->ip_count)
1498 {
1499 fprintf(f,"<th style=\"text-align: right\">%d IPs</th>",keyword->ip_count);
1500 }
1501 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i/line));
1502 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount, total);
1503
1504 fputs("</thead></table>\n",f);
1505 }
1506 else if(!dry_run && !just_flush)
1507 {
1508 perror(html);
1509 }
1510
1511 i=0;
1512 if(f > 0)
1513 {
1514 unsigned long long total_traffic=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;
1515 int active_classes=0;
1516 int colspan=12;
1517 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;
1518 int limit_count=0, prio_count=0;
1519 int popup_button=0;
1520
1521 if(qos_proxy)
1522 {
1523 colspan++;
1524 }
1525
1526 fprintf(f,"<p><table class=\"decorated last\">\n<caption>%s",title);
1527 fprintf(f," (%s)</caption>\n", d);
1528 fputs("<thead><tr>\n<th colspan=\"3\">&nbsp;</th>\n",f);
1529 fputs("<th style=\"text-align: right\">credit</th>\n\
1530 <th style=\"text-align: right\">FUP</th>\n\
1531 <th style=\"text-align: right\">total</th>\n\
1532 <th style=\"text-align: right\">down</th>\n",f);
1533 if(qos_proxy)
1534 {
1535 fputs("<th style=\"text-align: right\">proxy</th>\n",f);
1536 }
1537 fputs("<th style=\"text-align: right\">up</th>\n\
1538 <th style=\"text-align: right\">min</th>\n\
1539 <th style=\"text-align: right\">max</th>\n\
1540 <th style=\"text-align: right\">limit</th>\n\
1541 <th>&nbsp;</th>\n\
1542 </tr><tr>\n\
1543 <th style=\"text-align: right\">#</th>\n\
1544 <th>hostname [+sharing]</th>\n\
1545 <th style=\"text-align: right\">LMS</th>\n\
1546 <th style=\"text-align: right\">MB</th>\n\
1547 <th style=\"text-align: right\">MB</th>\n\
1548 <th style=\"text-align: right\">MB</th>\n\
1549 <th style=\"text-align: right\">MB</th>\n\
1550 <th style=\"text-align: right\">MB</th>\n\
1551 <th style=\"text-align: right\">kb/s</th>\n\
1552 <th style=\"text-align: right\">kb/s</th>\n\
1553 <th style=\"text-align: right\">kb/s</th>\n\
1554 <th>prio</th>\n\
1555 </tr></thead><tbody>\n",f);
1556
1557 row_odd_even = 0;
1558 for_each(ip,ips) if(!use_jquery_popups || !ip->sharing)
1559 {
1560 char *f1="", *f2="";
1561 i++;
1562
1563 if(ip->max < ip->desired)
1564 {
1565 f1="<span style=\"color:red\">";
1566 f2="</span>";
1567 limit_count++;
1568 }
1569 else if(ip->prio > highest_priority+1)
1570 {
1571 f1="<span style=\"color:brown\">";
1572 f2="</span>";
1573 prio_count++;
1574 }
1575
1576 #ifdef DEBUG
1577 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max);
1578 #endif
1579 /* hostnames -------------------------------------- */
1580 fprintf(f,"%s<td style=\"text-align: right\"><a name=\"%s\"></a>%d</td><td><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n",
1581 tr_odd_even(), ip->name, i, log_url, ip->name, ip->name);
1582
1583 if(use_jquery_popups)
1584 {
1585 fprintf(f,"<span id=\"sharing_%d\" style=\"display:none\">",i);
1586 popup_button=0;
1587 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1588 {
1589 fprintf(f,"<br /><a class=\"blue\" target=\"_blank\" href=\"%s%s.log\">%s</a>\n", log_url, sharedip->name, sharedip->name);
1590 popup_button++;
1591 }
1592 fputs("</span>\n",f);
1593 if(popup_button)
1594 {
1595 fprintf(f,"<span>[<a class=\"blue\" href=\"#\" onClick=\"$(this).parent().hide();$(\'#sharing_%d\').show();$(\'#download_%d\').show();$(\'#upload_%d\').show();return(false);\" style=\"cursor: pointer;\">+%d</a>]</span>",
1596 i, i, i, popup_button);
1597 }
1598 }
1599 fputs("</td>\n",f);
1600 /* ----------------------------------------------- */
1601
1602 if(found_lmsid)
1603 {
1604 fputs("<td style=\"text-align: right\">",f);
1605 if(ip->lmsid > 0)
1606 {
1607 fprintf(f,"<a class=\"blue\" target=\"_blank\" href=\"%s%d\">%04d</a>\n", lms_url, ip->lmsid, ip->lmsid);
1608 }
1609 else if(ip->lmsid == 0)
1610 {
1611 fputs("-------",f);
1612 }
1613 fputs("</td>\n",f);
1614 }
1615 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->credit);
1616 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",
1617 ip->keyword->html_color,
1618 ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));
1619 fprintf(f,"<td style=\"text-align: right\">%s%Lu%s", f1, ip->traffic, f2);
1620
1621 /* download --------------------------------------- */
1622 fprintf(f,"</td><td style=\"text-align: right\">%Lu", ip->direct);
1623 if(use_jquery_popups)
1624 {
1625 fprintf(f,"<span id=\"download_%d\" style=\"display:none\">",i);
1626 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))
1627 {
1628 fprintf(f,"<br />%Lu", sharedip->direct);
1629 }
1630 fputs("</span>\n",f);
1631 }
1632 fputs("</td>\n",f);
1633 /* ----------------------------------------------- */
1634
1635 if(qos_proxy)
1636 {
1637 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->proxy);
1638 }
1639 /* upload ---------------------------------------- */
1640 fprintf(f,"<td style=\"text-align: right\">%Lu", ip->upload);
1641 if(use_jquery_popups)
1642 {
1643 fprintf(f,"<span id=\"upload_%d\" style=\"display:none\">",i);
1644 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))
1645 {
1646 fprintf(f,"<br />%Lu", sharedip->upload);
1647 }
1648 fputs("</span>\n",f);
1649 }
1650 fputs("</td>\n",f);
1651 /* ----------------------------------------------- */
1652
1653 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1654 <td style=\"text-align: right\">%d</td>\n\
1655 <td style=\"text-align: right\">%s%d%s</td>\n\
1656 <td>%s%d%s</td></tr>\n",
1657 ip->min, ip->desired,
1658 f1, ip->max, f2,
1659 f1, ip->prio, f2);
1660
1661 total_traffic+=ip->traffic;
1662 total_direct+=ip->direct;
1663 total_proxy+=ip->proxy;
1664 total_upload+=ip->upload;
1665 if(ip->traffic>0)
1666 {
1667 active_classes++;
1668 tmp_sum+=ip->traffic;
1669 create(sum,Sum);
1670 sum->l=tmp_sum;
1671 sum->i=active_classes;
1672 insert(sum,sums,order_by,i);
1673 }
1674
1675 if(!just_preview)
1676 {
1677 append_log(ip);
1678 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))
1679 {
1680 append_log(sharedip);
1681 }
1682 }
1683 }
1684 fprintf(f,"</tbody><thead><tr>\n\
1685 <th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan-7, i);
1686 fprintf(f,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic, total_direct);
1687 if(qos_proxy)
1688 {
1689 fprintf(f,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy);
1690 }
1691 fprintf(f,"<th style=\"text-align: right\">%Lu</th>", total_upload);
1692 fprintf(f,"<th colspan=\"4\"><span style=\"color:red\">LIMIT %dx</span> <span style=\"color:brown\">LOW-PRIO %dx</span></th></tr>\n</thead></table>\n",limit_count,prio_count);
1693
1694 row_odd_even = 0;
1695 if(active_classes>10)
1696 {
1697 int top20_count=0,top20_perc1=0;
1698 long long top20_perc2=0;
1699 unsigned long long top20_sum=0l;
1700
1701 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f);
1702 fputs("<thead><tr>\n\
1703 <th>Analytic category</th>\n\
1704 <th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\
1705 <th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\
1706 </tr></thead><tbody>\n",f);
1707
1708 if_exists(sum,sums,sum->l>=total_traffic/4)
1709 {
1710 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());
1711 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1712 <td style=\"text-align: right\">%d %%</td>\n\
1713 <td style=\"text-align: right\">%Lu MB</td>\n\
1714 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1715 sum->i, (100*sum->i+50)/active_classes, sum->l, (100*sum->l+50)/total_traffic);
1716 }
1717
1718 if_exists(sum,sums,sum->i==10)
1719 {
1720 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());
1721 fprintf(f,"<td style=\"text-align: right\"><strong>10</strong></td>\n\
1722 <td style=\"text-align: right\">%d %%</td>\n\
1723 <td style=\"text-align: right\">%Lu MB</td>\n\
1724 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1725 (100*sum->i+50)/active_classes, sum->l, (100*sum->l+50)/total_traffic);
1726 }
1727
1728 if_exists(sum,sums,sum->l>=total_traffic/2)
1729 {
1730 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());
1731 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1732 <td style=\"text-align: right\">%d %%</td>\n\
1733 <td style=\"text-align: right\">%Lu MB</td>\n\
1734 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1735 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1736 }
1737
1738 if_exists(sum,sums,sum->l>=4*total_traffic/5)
1739 {
1740 fprintf(f,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());
1741 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1742 <td style=\"text-align: right\">%d %%</td>\n\
1743 <td style=\"text-align: right\">%Lu MB</td>\n\
1744 <td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",
1745 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1746 }
1747
1748 if_exists(sum,sums,sum->i>=(active_classes+1)/5)
1749 {
1750 fprintf(f,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());
1751 top20_count=sum->i;
1752 top20_perc1=(100*sum->i+50)/active_classes;
1753 top20_sum=sum->l;
1754 top20_perc2=(100*sum->l+50)/total_traffic;
1755 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1756 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1757 <td style=\"text-align: right\">%Lu MB</td>\n\
1758 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1759 top20_count,top20_perc1,top20_sum,top20_perc2);
1760 }
1761
1762 if_exists(sum,sums,sum->i>=(active_classes+1)/4)
1763 {
1764 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());
1765 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1766 <td style=\"text-align: right\">%d %%</td>\n\
1767 <td style=\"text-align: right\">%Lu MB</td>\n\
1768 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1769 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1770 }
1771
1772 if_exists(sum,sums,sum->i>=(active_classes+1)/2)
1773 {
1774 fprintf(f,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());
1775 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1776 <td style=\"text-align: right\"><strong>%d %%</strong></td>\n\
1777 <td style=\"text-align: right\">%Lu MB</td>\n\
1778 <td style=\"text-align: right\">%Ld %%</td></tr>\n",
1779 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1780 }
1781
1782 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)
1783 {
1784 fprintf(f,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());
1785 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\
1786 <td style=\"text-align: right\">%d %%</td>\n\
1787 <td style=\"text-align: right\">%Lu MB</td>\n\
1788 <td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",
1789 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);
1790 }
1791
1792 fprintf(f,"<thead><tr><th><a class=\"blue\" target=\"_blank\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url);
1793 fprintf(f,"<th style=\"text-align: right\">%d</th>\n\
1794 <th style=\"text-align: right\">100 %%</th>\n\
1795 <th style=\"text-align: right\">%Lu MB</th>\n\
1796 <th style=\"text-align: right\">100 %%</th></tr>\n",active_classes,total_traffic);
1797 fputs("</thead></table>\n", f);
1798
1799 /* write basic ERP data to log directory */
1800 if(!just_preview)
1801 {
1802 FILE *iplog;
1803 sprintf(str,"%s/ERP.log",log_dir);
1804 iplog=fopen(str,"a");
1805 if(iplog)
1806 {
1807 fprintf(iplog,"%ld\t%d\t%d %%\t%Lu M\t%Ld %%\tACTIVE %d\tTRAFFIC %Lu M\tCLASSES %d\tFUP-LIMIT %d\tLOW-PRIO %d\t%s",
1808 time(NULL), top20_count, top20_perc1, top20_sum, top20_perc2,
1809 active_classes, total_traffic, i, limit_count, prio_count, d); /* d = date*/
1810 fclose(iplog);
1811 }
1812 else
1813 {
1814 perror(str);
1815 }
1816 }
1817 }
1818
1819 fprintf(f, stats_html_signature, version);
1820 fclose(f);
1821 }
1822
1823 if(just_preview)
1824 {
1825 char swchar='p';
1826 if(start_shaping)
1827 {
1828 swchar='s';
1829 }
1830 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);
1831 exit(0);
1832 }
1833
1834 i=0;
1835 #ifdef DEBUG
1836 printf("%-22s %-15s mark\n","name","ip");
1837 #endif
1838
1839 printf("Writing %s ... ", classmap);
1840 f = fopen(classmap, "w");
1841 if(f < 0)
1842 {
1843 perror(classmap);
1844 }
1845
1846 /*-----------------------------------------------------------------*/
1847 puts("Generating iptables and tc classes ... ");
1848 /*-----------------------------------------------------------------*/
1849
1850 for_each(ip, ips) if(ip->mark > 0)
1851 {
1852 if(idxs)
1853 {
1854 char *buf;
1855 duplicate(ip->addr,buf);
1856 buf=hash_id(ip->addr,32-idxtable_bitmask1);
1857
1858 string(chain_forward,6+strlen(buf));
1859 strcpy(chain_forward,"forw_");
1860 strcat(chain_forward,buf);
1861
1862 string(chain_postrouting,6+strlen(buf));
1863 strcpy(chain_postrouting,"post_");
1864 strcat(chain_postrouting,buf);
1865
1866 free(buf);
1867 }
1868 else
1869 {
1870 chain_forward="FORWARD";
1871 chain_postrouting="POSTROUTING";
1872 }
1873
1874 #ifdef DEBUG
1875 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark);
1876 #endif
1877
1878 /* -------------------------------------------------------- mark download */
1879
1880 sprintf(str, "-A %s -d %s/32 -o %s -j %s%d",
1881 chain_postrouting, ip->addr, lan, mark_iptables, ip->mark);
1882 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/
1883 /* -m limit --limit 1/s */
1884 save_line(str);
1885
1886 if(qos_proxy)
1887 {
1888 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",
1889 chain_postrouting, proxy_ip, proxy_port, ip->addr, lan, mark_iptables, ip->mark);
1890 /*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);*/
1891 save_line(str);
1892 }
1893
1894 sprintf(str, "-A %s -d %s/32 -o %s -j ACCEPT",
1895 chain_postrouting, ip->addr, lan);
1896 save_line(str);
1897
1898 /* -------------------------------------------------------- mark upload */
1899 sprintf(str, "-A %s -s %s/32 -o %s -j %s%d",
1900 chain_forward, ip->addr, wan, mark_iptables, ip->mark);
1901 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/
1902 save_line(str);
1903
1904 sprintf(str, "-A %s -s %s/32 -o %s -j ACCEPT",
1905 chain_forward, ip->addr, wan);
1906 save_line(str);
1907
1908 if(ip->min)
1909 {
1910 /* -------------------------------------------------------- download class */
1911 #ifdef DEBUG
1912 printf("(down: %dk-%dk ", ip->min, ip->max);
1913 #endif
1914
1915 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1916 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);
1917 safe_run(str);
1918
1919 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1920 {
1921 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1922 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1923 safe_run(str);
1924 }
1925
1926 if(filter_type == 1)
1927 {
1928 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1929 tc, lan, ip->mark, ip->mark);
1930 safe_run(str);
1931 }
1932
1933 /* -------------------------------------------------------- upload class */
1934 #ifdef DEBUG
1935 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1936 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));
1937 #endif
1938
1939 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",
1940 tc, wan, ip->group, ip->mark,
1941 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),
1942 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);
1943 safe_run(str);
1944
1945 if(strcmpi(ip->keyword->leaf_discipline, "none"))
1946 {
1947 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",
1948 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/
1949 safe_run(str);
1950 }
1951
1952 if(filter_type == 1)
1953 {
1954 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",
1955 tc, wan, ip->mark, ip->mark);
1956 safe_run(str);
1957 }
1958
1959 if(f > 0)
1960 {
1961 fprintf(f, "%s %d\n", ip->addr, ip->mark);
1962 }
1963 }
1964 else
1965 {
1966 #ifdef DEBUG
1967 printf("(sharing %s)\n", ip->sharing);
1968 #endif
1969 }
1970 i++;
1971 }
1972 if(f > 0)
1973 {
1974 puts("done.");
1975 fclose(f);
1976 }
1977
1978 if(idxs)
1979 {
1980 chain_forward = "forw_common";
1981 chain_postrouting = "post_common";
1982 }
1983 else
1984 {
1985 chain_forward = "FORWARD";
1986 chain_postrouting = "POSTROUTING";
1987 }
1988 /* -------------------------------- classify or reject free download */
1989 {
1990 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */
1991 if(free_min)
1992 {
1993 final_chain = "ACCEPT";
1994 }
1995 if(qos_proxy)
1996 {
1997 if(free_min)
1998 {
1999 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",
2000 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);
2001 save_line(str);
2002 }
2003 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",
2004 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);
2005 save_line(str);
2006 }
2007 if(free_min)
2008 {
2009 sprintf(str,"-A %s -o %s -j %s%d", chain_postrouting, lan, mark_iptables, 3);
2010 save_line(str);
2011 }
2012 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);
2013 save_line(str);
2014 /* ------------------------------- classify or reject free upload */
2015 if(free_min)
2016 {
2017 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);
2018 save_line(str);
2019 }
2020 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);
2021 save_line(str);
2022 }
2023
2024 if(free_min) /* allocate free bandwith if it is not zero... */
2025 {
2026 /*-----------------------------------------------------------------*/
2027 puts("Generating free bandwith classes ...");
2028 /*-----------------------------------------------------------------*/
2029 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2030 tc, lan, parent, free_min, free_max,burst, lowest_priority);
2031 safe_run(str);
2032 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",
2033 tc, wan, parent, free_min, free_max, burst, lowest_priority);
2034 safe_run(str);
2035 /* tc SFQ */
2036 if(strcmpi(qos_leaf, "none"))
2037 {
2038 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);
2039 safe_run(str);
2040
2041 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);
2042 safe_run(str);
2043 }
2044 /* tc handle 1 fw flowid */
2045 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);
2046 safe_run(str);
2047
2048 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);
2049 safe_run(str);
2050 }
2051 printf("Total IP count: %d\n", i);
2052 run_restore();
2053 if(log_file)
2054 {
2055 fclose(log_file);
2056 }
2057 return 0;
2058 /* that's all folks, thank you for reading it all the way up to this point ;-) */
2059 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */
2060 }
This page took 1.298538 seconds and 4 git commands to generate.