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