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