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