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