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