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