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