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