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