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