bug fix
[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 free(cmd);\r
660}\r
661 \r
662/* ========== This function executes, logs OR ALSO prints command ========== */\r
663\r
664void safe_run(char *cmd)\r
665{\r
666 if(dry_run)\r
667 {\r
668 printf("\n=>%s\n",cmd);\r
669 }\r
670 else\r
671 {\r
672 system(cmd);\r
673 }\r
674 if(log_file)\r
675 {\r
676 fprintf(log_file,"%s\n",cmd);\r
677 }\r
678}\r
679\r
680void save_line(char *line)\r
681{\r
682 fprintf(iptables_file,"%s\n",line);\r
683}\r
684\r
685void run_restore(void)\r
686{\r
687 char *restor;\r
688 string(restor,STRLEN);\r
689\r
690 /*-----------------------------------------------------------------*/\r
691 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
692 /*-----------------------------------------------------------------*/\r
693 \r
694 save_line("COMMIT");\r
695 fclose(iptables_file);\r
696 if(dry_run) \r
697 {\r
698 parse(iptablesfile)\r
699 {\r
700 printf("%s\n",_);\r
701 }\r
702 done;\r
703 }\r
704\r
705 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
706 safe_run(restor);\r
707 \r
708 free(restor);\r
709}\r
710\r
711/* == This function strips extra characters after IP address and stores it = */\r
712\r
713void parse_ip(char *str)\r
714{\r
715 char *ptr,*ipaddr=NULL,*ipname=NULL,*lmsid=NULL;\r
716\r
717 ptr=strchr(str,'{');\r
718 if(ptr)\r
719 {\r
720 lmsid=++ptr;\r
721 while(*ptr && *ptr!='}')\r
722 {\r
723 ptr++;\r
724 }\r
725 *ptr=0;\r
726 }\r
727 \r
728 ptr=str;\r
729 while(*ptr && *ptr!=' ' && *ptr!=9)\r
730 {\r
731 ptr++;\r
732 }\r
733 \r
734 *ptr=0;\r
735 ipaddr=str;\r
736 ptr++;\r
737 while(*ptr && (*ptr==' ' || *ptr==9))\r
738 {\r
739 ptr++;\r
740 }\r
741 ipname=ptr; \r
742 while(*ptr && *ptr!=' ' && *ptr!=9)\r
743 {\r
744 ptr++;\r
745 }\r
746 *ptr=0;\r
747\r
748 if_exists(ip,ips,eq(ip->addr,ipaddr));\r
749 else\r
750 {\r
751 TheIP();\r
752 }\r
753 ip->addr=ipaddr;\r
754 ip->name=ipname;\r
755 if(lmsid)\r
756 {\r
757 ip->lmsid=atoi(lmsid);\r
758 found_lmsid=1;\r
759 }\r
760}\r
761\r
762char *parse_datafile_line(char *str)\r
763{\r
764 char *ptr=strchr(str,' ');\r
765\r
766 if(ptr)\r
767 {\r
768 *ptr=0;\r
769 ptr++;\r
770 return ptr;\r
771 } \r
772 else \r
773 {\r
774 return NULL;\r
775 }\r
776}\r
777\r
778struct IpLog\r
779{\r
780 char *name;\r
781 long traffic;\r
782 long guaranted;\r
783 int i;\r
784 int lmsid;\r
785 long l;\r
786 list(IpLog);\r
787} *iplog,*iplogs;\r
788\r
789void parse_ip_log(int argc, char **argv) \r
790{\r
791 char *month, *year, *str, *name="(undefined)", *ptr, *ptr2, *filename;\r
792 long traffic=0l, traffic_month, total=0, guaranted;\r
793 int col, col2, y_ok, m_ok, accept_month, i=1, any_month=0, lmsid;\r
794 char mstr[4], ystr[5];\r
795 FILE *f; \r
796 string(str,STRLEN);\r
797 string(filename,STRLEN);\r
798\r
799 if(argv[1][1]=='l') /* -l */\r
800 {\r
801 if(argc<4)\r
802 {\r
803 puts("Missing parameter(s)!\nUsage: prometheus -l Mmm YYYY (Mmm=Jan-Dec or Year, YYYY=year)");\r
804 exit(-1);\r
805 }\r
806 else\r
807 {\r
808 month=argv[2];\r
809 if(eq(month,"Year")) any_month=1;\r
810 year=argv[3];\r
811 }\r
812 }\r
813 else\r
814 { \r
815 time_t t = time(NULL) - 3600*24 ; /* yesterday's timestamp*/\r
816 struct tm *timep = localtime(&t); \r
817\r
818 if(argv[1][1]=='m') /* -m yestarday - month */\r
819 {\r
820 strftime(mstr, 4, "%b", timep);\r
821 month=mstr;\r
822 strftime(ystr, 5, "%Y", timep);\r
823 year=ystr; \r
824 }\r
825 else /* -y yesterday - year */\r
826 {\r
827 month="Year";\r
828 any_month=1;\r
829 strftime(ystr, 5, "%Y", timep);\r
830 year=ystr;\r
831 }\r
832 }\r
833 printf("Analysing traffic for %s %s ...\n",month,year);\r
834\r
835 /* sorry... next release of C<<1 header file will include for_path_files(name,path) { } macro */\r
836 sprintf(str,"%s %s/",ls,log_dir);\r
837 shell(str);\r
838 input(str,STRLEN) \r
839 {\r
840 if(strstr(str,".log"))\r
841 {\r
842 ptr=strrchr(str,'\n');\r
843 if(ptr) *ptr='\0';\r
844 sprintf(filename,"%s/%s",log_dir,str);\r
845 printf("Parsing %s ...",filename);\r
846 accept_month=0;\r
847 traffic_month=0;\r
848 guaranted=0;\r
849 lmsid=-1;\r
850 parse(filename)\r
851 {\r
852 y_ok=m_ok=0; \r
853 valid_columns(ptr,_,'\t',col) switch(col)\r
854 {\r
855 case 2: name = ptr;break;\r
856 case 3: traffic = atol(ptr);break;\r
857 /* column number - was 7, now 11...*/\r
858 case 7:\r
859 case 8:\r
860 case 9:\r
861 case 10:\r
862 case 11: if(isalpha(*ptr)) /* character, not numeric string = date, just one*/\r
863 {\r
864 valid_columns(ptr2,ptr,' ',col2) switch(col2)\r
865 {\r
866 case 2: if(any_month || eq(ptr2,month)) m_ok = 1; break;\r
867 case 5: if(eq(ptr2,year)) y_ok = 1; break;\r
868 }\r
869 }\r
870 else\r
871 {\r
872 if(col == 7) guaranted = atol(ptr);\r
873 if(col == 10) lmsid = atoi(ptr);\r
874 }\r
875 }\r
876 \r
877 if(y_ok && m_ok) \r
878 {\r
879 traffic_month += traffic;\r
880 accept_month = 1;\r
881 }\r
882 }\r
883 done;\r
884\r
885 if(accept_month)\r
886 {\r
887 create(iplog,IpLog);\r
888 iplog->name = name;\r
889 iplog->guaranted = guaranted;\r
890 iplog->traffic = traffic_month;\r
891 iplog->lmsid = lmsid;\r
892 insert(iplog,iplogs,desc_order_by,traffic);\r
893 printf(" %ld MB\n",iplog->traffic);\r
894 }\r
895 else\r
896 {\r
897 puts(" no records.");\r
898 }\r
899 }\r
900 }\r
901 sprintf(str,"%s/%s-%s.html",html_log_dir,year,month);\r
902 printf("Writing %s ... ",str);\r
903 f=fopen(str,"w");\r
904 if(f > 0)\r
905 {\r
906 fprintf(f, "<table class=\"decorated last\"><thead>\n\\r
907<tr><th colspan=\"2\">%s %s</th>\n\\r
908<th style=\"text-align: right\">lms</th>\n\\r
909<th colspan=\"2\">Data transfers</th>\n\\r
910<th style=\"text-align: right\">Min.speed</th>\n\\r
911</tr></thead><tbody>\n ",\r
912 month, year);\r
913\r
914 row_odd_even = 0;\r
915 for_each(iplog, iplogs)\r
916 {\r
917 if(iplog->traffic)\r
918 {\r
919 fprintf(f, "%s<td style=\"text-align: right\">%d</td>\n\\r
920<td style=\"text-align: left\"><a class=\"blue\" href=\"%s%s.log\">%s</td>\n\\r
921<td style=\"text-align: right\">", \r
922 tr_odd_even(), i++, log_url, iplog->name, iplog->name); \r
923 if(iplog->lmsid > 0)\r
924 {\r
925 /*base URL will be configurable soon ... */\r
926 fprintf(f, "<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url, iplog->lmsid, iplog->lmsid);\r
927 }\r
928 else if(iplog->lmsid == 0)\r
929 {\r
930 fputs("-------",f);\r
931 } \r
932 fprintf(f, "<td style=\"text-align: right\">%ld&nbsp;MB</td>\n\\r
933 <td style=\"text-align: right\"><strong>%ld&nbsp;GB</strong></td>\n\\r
934 <td style=\"text-align: right\">%ld&nbsp;kb/s</th></tr>\n",\r
935 iplog->traffic, iplog->traffic>>10, iplog->guaranted);\r
936 total+=iplog->traffic>>10;\r
937 iplog->i=i;\r
938 iplog->l=total;\r
939 }\r
940 }\r
941 fprintf(f,"</tbody><thead><tr>\\r
942 <td colspan=\"4\" style=\"text-align: left\">Total:</td>\\r
943 <td style=\"text-align: right\"><strong>%ld&nbsp;GB</strong></td>\\r
944 <td style=\"text-align: right\"><strong>%Ld&nbsp;kb/s</strong></td></tr>\n", total, line);\r
945 fputs("</thead></table>\n", f);\r
946\r
947 row_odd_even = 0;\r
948 if(i>10)\r
949 {\r
950 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\">\n\\r
951<caption>Enterprise Resource Planning (ERP)</caption>\n\\r
952<thead><tr>\n\\r
953<th>Analytic category</th>\n\\r
954<th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\\r
955<th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\\r
956</tr></thead><tbody>\n",f);\r
957\r
958 if_exists(iplog,iplogs,iplog->l>=total/4)\r
959 {\r
960 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());\r
961 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
962 }\r
963 \r
964 if_exists(iplog,iplogs,iplog->i==10)\r
965 {\r
966 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());\r
967 fprintf(f,"<td style=\"text-align: right\"><strong>10</strong></td>\n\\r
968<td style=\"text-align: right\">%d %%</td>\n\\r
969<td style=\"text-align: right\">%ld G</td>\n\\r
970<td style=\"text-align: right\">%d %%</td></tr>\n",\r
971 (100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));\r
972 }\r
973\r
974 if_exists(iplog,iplogs,iplog->l>=total/2)\r
975 {\r
976 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());\r
977 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
978<td style=\"text-align: right\">%d %%</td>\n\\r
979<td style=\"text-align: right\">%ld G</td>\n\\r
980<td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",\r
981 iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));\r
982 }\r
983\r
984 if_exists(iplog,iplogs,iplog->l>=4*total/5)\r
985 {\r
986 fprintf(f,"%s<td>Top 80%% of traffic</td>\n",tr_odd_even());\r
987 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
988<td style=\"text-align: right\">%d %%</td>\n\\r
989<td style=\"text-align: right\">%ld G</td>\n\\r
990<td style=\"text-align: right\"><strong>%d %%</strong></td></tr>\n",\r
991 iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));\r
992 }\r
993\r
994 if_exists (iplog,iplogs,iplog->i>=i/5)\r
995 {\r
996 fprintf(f,"%s<td>Top 20%% downloaders</td>\n",tr_odd_even());\r
997 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
998<td style=\"text-align: right\"><strong>%d %%</strong></td>\n\\r
999<td style=\"text-align: right\">%ld G</td>\n\\r
1000<td style=\"text-align: right\">%d %%</td></tr>\n",\r
1001 iplog->i,(100*iplog->i+50)/i,iplog->l,(int)((100*iplog->l+50)/total));\r
1002 }\r
1003\r
1004 if_exists(iplog,iplogs,iplog->i>=i/4)\r
1005 {\r
1006 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());\r
1007 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
1008 }\r
1009\r
1010 if_exists(iplog,iplogs,iplog->i>=i/2)\r
1011 {\r
1012 fprintf(f,"%s<td>Top 50%% downloaders</td>\n",tr_odd_even());\r
1013 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1014<td style=\"text-align: right\"><strong>%d %%</strong></td>\n\\r
1015<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
1016 }\r
1017\r
1018 if_exists(iplog,iplogs,iplog->i>=4*i/5)\r
1019 {\r
1020 fprintf(f,"%s<td>Top 80%% downloaders</td>\n",tr_odd_even());\r
1021 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
1022 }\r
1023\r
1024 fprintf(f,"</tbody><thead><tr>\n\\r
1025<th>All users, all traffic</th>\n\\r
1026<th style=\"text-align: right\">%d</th>\n\\r
1027<th style=\"text-align: right\">100 %%</th>\n\\r
1028<th style=\"text-align: right\">%ld G</th>\n\\r
1029<th style=\"text-align: right\">100 %%</th></tr>\n",i-1,total);\r
1030 fputs("</thead></table>\n", f);\r
1031 }\r
1032\r
1033 fprintf(f, stats_html_signature, version);\r
1034 fclose(f);\r
1035 puts("done.");\r
1036 }\r
1037 else\r
1038 {\r
1039 perror(str);\r
1040 }\r
1041}\r
1042\r
1043void append_log(struct IP *self) /*using global variables*/\r
1044{\r
1045 char *d, *str;\r
1046 FILE *f; \r
1047\r
1048 date(d); /* this is typical cll1.h macro - prints current date */ \r
1049 string(str,STRLEN); \r
1050 sprintf(str,"%s/%s.log", log_dir, self->name);\r
1051 f=fopen(str,"a");\r
1052 if(f > 0)\r
1053 {\r
1054 fprintf(f,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%d\t%s",\r
1055 time(NULL), self->name, self->traffic, self->direct, self->proxy,\r
1056 self->upload, self->min, self->max, self->desired, self->lmsid, d); /* d = date*/\r
1057 fclose(f);\r
1058 }\r
1059 else\r
1060 {\r
1061 perror(str);\r
1062 }\r
1063}\r
1064\r
1065\r
1066/*-----------------------------------------------------------------*/\r
1067/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
1068/*-----------------------------------------------------------------*/\r
1069\r
1070program\r
1071{\r
1072 int i=0;\r
1073 FILE *f=NULL;\r
1074 char *str, *ptr, *d;\r
1075 char *substring;\r
1076 int class_count=0,ip_count=0;\r
1077 int parent=1;\r
1078 int just_flush=FALSE;\r
1079 int nodelay=FALSE;\r
1080 int just_preview=FALSE; /* preview - generate just stats */\r
1081 int just_logs=FALSE; /* just parse logs */\r
1082 int run=FALSE;\r
1083 int total=0;\r
1084 \r
1085 char *chain_forward, *chain_postrouting;\r
1086 char *althosts=NULL;\r
1087 \r
1088 printf("\n\\r
1089Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
1090Version %s - Copyright (C)2005-2012 Michael Polak (xChaos)\n\\r
1091iptables-restore & burst tunning & classify modification by Ludva\n\\r
1092Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
1093\r
1094 /*----- Boring... we have to check command line options first: ----*/\r
1095 \r
1096 arguments\r
1097 {\r
1098 argument("-c") { nextargument(config); }\r
1099 argument("-h") { nextargument(althosts);}\r
1100 argument("-d") { run=TRUE; dry_run=TRUE; }\r
1101 argument("-f") { run=TRUE; just_flush=TRUE; }\r
1102 argument("-9") { run=TRUE; just_flush=9; }\r
1103 argument("-p") { run=TRUE; just_preview=TRUE; }\r
1104 argument("-r") { run=TRUE; }\r
1105 argument("-n") { run=TRUE; nodelay=TRUE; }\r
1106 argument("-l") { just_logs=TRUE; }\r
1107 argument("-m") { just_logs=TRUE; }\r
1108 argument("-y") { just_logs=TRUE; }\r
1109 argument("-?") { help(); exit(0); }\r
1110 argument("--help") { help(); exit(0); }\r
1111 argument("-v") { exit(0); } \r
1112 argument("--version") { exit(0); } \r
1113 }\r
1114 \r
1115 if(dry_run)\r
1116 {\r
1117 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
1118 }\r
1119\r
1120 date(d); /* this is typical cll1.h macro - prints current date */\r
1121\r
1122 /*-----------------------------------------------------------------*/\r
1123 printf("Parsing configuration file %s ...\n", config);\r
1124 /*-----------------------------------------------------------------*/\r
1125 get_config(config);\r
1126 \r
1127 if(just_logs)\r
1128 {\r
1129 parse_ip_log(argc,argv);\r
1130 exit(0);\r
1131 }\r
1132 else if(not run)\r
1133 {\r
1134 help();\r
1135 exit(0);\r
1136 }\r
1137\r
1138 if(althosts)\r
1139 {\r
1140 hosts=althosts;\r
1141 }\r
1142\r
1143 if(just_flush<9)\r
1144 {\r
1145 /*-----------------------------------------------------------------*/\r
1146 puts("Parsing iptables verbose output ...");\r
1147 /*-----------------------------------------------------------------*/\r
1148 get_traffic_statistics();\r
1149 }\r
1150\r
1151 /*-----------------------------------------------------------------*/\r
1152 printf("Parsing class defintion file %s ...\n", hosts);\r
1153 /*-----------------------------------------------------------------*/\r
1154 int groupidx = FIRSTGROUPID;\r
1155 parse(hosts)\r
1156 {\r
1157 str=_;\r
1158\r
1159 if(*str<'0' || *str>'9')\r
1160 {\r
1161 /* any line starting with non-number is comment ...*/\r
1162 continue;\r
1163 }\r
1164 \r
1165 //Does this IP share QoS class with some other ?\r
1166 substring=strstr(str,"sharing-");\r
1167 if(substring)\r
1168 { \r
1169 substring+=8; //"sharing-"\r
1170 parse_ip(str);\r
1171 ip_count++;\r
1172 ip->sharing=substring;\r
1173 ip->keyword=defaultkeyword; /* settings for default keyword */\r
1174 while(*substring && *substring!='\n')\r
1175 {\r
1176 substring++;\r
1177 }\r
1178 *substring=0; \r
1179 }\r
1180 else\r
1181 {\r
1182 //Do we have to create new QoS class for this IP ?\r
1183\r
1184 if_exists(keyword,keywords,(substring=strstr(str,keyword->key)))\r
1185 {\r
1186 parse_ip(str);\r
1187 ip_count++;\r
1188 ip->keyword=keyword;\r
1189 keyword->ip_count++;\r
1190 ip->prio=keyword->default_prio;\r
1191 substring+=strlen(keyword->key)+1;\r
1192 ptr=substring;\r
1193 while(*ptr && *ptr!='-')\r
1194 {\r
1195 ptr++;\r
1196 }\r
1197 if(*ptr=='-')\r
1198 {\r
1199 *ptr=0;\r
1200 ip->max = ip->desired=atoi(ptr+1);\r
1201 }\r
1202 ip->min = atoi(substring);\r
1203 if(ip->min <= 0)\r
1204 {\r
1205 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kb/s\n",\r
1206 str, free_min);\r
1207 ip->min = free_min;\r
1208 }\r
1209 if(ip->max <= ip->min)\r
1210 {\r
1211 ip->fixedprio = 1;\r
1212 ip->max = ip->min+ip->keyword->reserve_min;\r
1213 }\r
1214 else \r
1215 {\r
1216 ip->max -= ip->keyword->reserve_max;\r
1217 if(ip->max<ip->min)\r
1218 {\r
1219 ip->max=ip->min;\r
1220 }\r
1221 }\r
1222 ip->mark=FIRSTIPCLASS+1+class_count++;\r
1223\r
1224 if_exists(group,groups,group->min==ip->min) \r
1225 { \r
1226 group->count++; \r
1227 group->desired += ip->min;\r
1228 ip->group = group->id; \r
1229 }\r
1230 else\r
1231 {\r
1232 create(group,Group);\r
1233 group->min = ip->min;\r
1234 group->id = groupidx++;\r
1235 ip->group = group->id;\r
1236\r
1237 if(group->min<8) group->min=8;\r
1238 /* Warning - this is maybe because of primitive tc namespace, can be fixed */\r
1239 /* it is because class IDs are derived from min. bandwidth. - xCh */\r
1240 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;\r
1241 \r
1242 group->count=1;\r
1243 group->desired=ip->min; \r
1244 insert(group,groups,desc_order_by,min);\r
1245 }\r
1246 }//endif keyword-\r
1247 }//endif sharing-\r
1248 }\r
1249 fail\r
1250 {\r
1251 perror(hosts);\r
1252 exit(-1);\r
1253 }\r
1254 done;\r
1255\r
1256 /*-----------------------------------------------------------------*/\r
1257 /* cll1.h - let's allocate brand new character buffer... */\r
1258 /*-----------------------------------------------------------------*/\r
1259 string(str,STRLEN); \r
1260\r
1261 /*-----------------------------------------------------------------*/\r
1262 puts("Resolving shared connections ...");\r
1263 /*-----------------------------------------------------------------*/\r
1264 for_each(ip,ips) if(ip->sharing)\r
1265 {\r
1266 for_each(sharedip,ips) if(eq(sharedip->name,ip->sharing))\r
1267 {\r
1268 sharedip->traffic+=ip->traffic;\r
1269 ip->traffic=0;\r
1270 ip->mark=sharedip->mark; \r
1271 ip->lmsid=sharedip->lmsid;\r
1272 break;\r
1273 }\r
1274 if(!sharedip)\r
1275 {\r
1276 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
1277 ip->addr, ip->name, ip->sharing);\r
1278 }\r
1279 }\r
1280\r
1281 if(enable_credit && just_flush<9)\r
1282 {\r
1283 /*-----------------------------------------------------------------*/\r
1284 printf("Parsing credit file %s ...\n", credit);\r
1285 /*-----------------------------------------------------------------*/\r
1286 parse(credit)\r
1287 {\r
1288 ptr=parse_datafile_line(_);\r
1289 if(ptr)\r
1290 {\r
1291 if_exists(ip,ips,eq(ip->addr,_))\r
1292 {\r
1293 sscanf(ptr,"%Lu",&(ip->credit));\r
1294 }\r
1295 }\r
1296 }\r
1297 done;\r
1298 }\r
1299\r
1300 if(!just_preview)\r
1301 {\r
1302 /*-----------------------------------------------------------------*/\r
1303 puts("Initializing iptables and tc classes ...");\r
1304 /*-----------------------------------------------------------------*/\r
1305 \r
1306 iptables_file=fopen(iptablesfile,"w");\r
1307 if(iptables_file == NULL)\r
1308 {\r
1309 puts("Cannot open iptablesfile!");\r
1310 exit(-1);\r
1311 }\r
1312 \r
1313 log_file=fopen(cmdlog,"w");\r
1314 if(log_file == NULL) \r
1315 {\r
1316 puts("Cannot open logfile!");\r
1317 exit(-1);\r
1318 }\r
1319 \r
1320 save_line(iptablespreamble);\r
1321 run_restore();\r
1322 \r
1323 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
1324 safe_run(str);\r
1325\r
1326 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
1327 safe_run(str);\r
1328 \r
1329 iptables_file=fopen(iptablesfile,"w");\r
1330 save_line(iptablespreamble);\r
1331\r
1332 if(qos_free_zone && *qos_free_zone!='0')\r
1333 {\r
1334 char *chain;\r
1335 \r
1336 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
1337 save_line(str);\r
1338 \r
1339 if(qos_proxy)\r
1340 {\r
1341 save_line(":post_noproxy - [0:0]");\r
1342 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);\r
1343 save_line(str); \r
1344 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);\r
1345 save_line(str); \r
1346 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
1347 save_line(str); \r
1348\r
1349 chain="post_noproxy"; \r
1350 }\r
1351 else\r
1352 {\r
1353 chain="POSTROUTING";\r
1354 }\r
1355 \r
1356 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
1357 save_line(str);\r
1358 }\r
1359 \r
1360 if(ip_count>idxtable_treshold1 && !just_flush)\r
1361 {\r
1362 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */\r
1363 char *subnet, *buf;\r
1364 /*-----------------------------------------------------------------*/\r
1365 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
1366 /*-----------------------------------------------------------------*/\r
1367\r
1368 save_line(":post_common - [0:0]");\r
1369 save_line(":forw_common - [0:0]");\r
1370\r
1371 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))\r
1372 {\r
1373 buf=hash_id(ip->addr,bitmask);\r
1374 if_exists(idx,idxs,eq(idx->id,buf))\r
1375 {\r
1376 idx->children++;\r
1377 }\r
1378 else\r
1379 {\r
1380 create(idx,Index);\r
1381 idx->addr=ip->addr;\r
1382 idx->id=buf;\r
1383 idx->bitmask=bitmask;\r
1384 idx->parent=NULL;\r
1385 idx->children=0;\r
1386 idxcount++;\r
1387 push(idx,idxs);\r
1388 }\r
1389 }\r
1390\r
1391 /* brutal perfomance optimalization */\r
1392 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)\r
1393 {\r
1394 bitmask-=idxtable_bitmask2;\r
1395 idxcount=0;\r
1396\r
1397 for_each(idx,idxs) if(idx->parent == NULL)\r
1398 {\r
1399 buf=hash_id(idx->addr,bitmask);\r
1400 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
1401 {\r
1402 metaindex->children++;\r
1403 }\r
1404 else\r
1405 {\r
1406 create(metaindex,Index);\r
1407 metaindex->addr=idx->addr;\r
1408 metaindex->id=buf;\r
1409 metaindex->bitmask=bitmask;\r
1410 metaindex->parent=NULL;\r
1411 metaindex->children=0;\r
1412 idxcount++;\r
1413 push(metaindex,idxs);\r
1414 }\r
1415 idx->parent=metaindex;\r
1416 }\r
1417 }\r
1418\r
1419 /* this should slightly optimize throughout ... */\r
1420 sort(idx,idxs,desc_order_by,children);\r
1421 sort(idx,idxs,order_by,bitmask);\r
1422\r
1423 i=0;\r
1424 for_each(idx,idxs)\r
1425 {\r
1426 subnet=subnet_id(idx->addr,idx->bitmask);\r
1427 printf("%d: %s/%d\n",\r
1428 ++i, subnet, idx->bitmask);\r
1429 \r
1430 sprintf(str,":post_%s - [0:0]", idx->id);\r
1431 save_line(str);\r
1432\r
1433 sprintf(str,":forw_%s - [0:0]", idx->id);\r
1434 save_line(str);\r
1435\r
1436 if(idx->parent)\r
1437 {\r
1438 string(buf,strlen(idx->parent->id)+6);\r
1439 sprintf(buf,"post_%s",idx->parent->id);\r
1440 }\r
1441 else\r
1442 {\r
1443 buf="POSTROUTING";\r
1444 }\r
1445\r
1446 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
1447 save_line(str);\r
1448\r
1449 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
1450 save_line(str);\r
1451\r
1452 if(idx->parent)\r
1453 {\r
1454 string(buf,strlen(idx->parent->id)+6);\r
1455 sprintf(buf,"forw_%s",idx->parent->id);\r
1456 }\r
1457 else\r
1458 {\r
1459 buf="FORWARD";\r
1460 }\r
1461\r
1462 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
1463 save_line(str);\r
1464\r
1465 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
1466 save_line(str);\r
1467 }\r
1468 printf("Total indexed iptables chains created: %d\n", i);\r
1469\r
1470 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
1471 save_line(str);\r
1472 \r
1473 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
1474 save_line(str);\r
1475 }\r
1476 \r
1477 }\r
1478\r
1479 if(just_flush)\r
1480 {\r
1481 fclose(iptables_file);\r
1482 if(log_file)\r
1483 { \r
1484 fclose(log_file);\r
1485 }\r
1486 puts("Just flushed iptables and tc classes - now exiting ...");\r
1487 exit(0);\r
1488 }\r
1489\r
1490 if(!just_preview)\r
1491 {\r
1492 if(!dry_run && !nodelay && qos_free_delay)\r
1493 {\r
1494 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
1495 sleep(qos_free_delay);\r
1496 }\r
1497\r
1498 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
1499 tc,lan,htb_r2q);\r
1500 safe_run(str);\r
1501\r
1502 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
1503 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);\r
1504 safe_run(str);\r
1505\r
1506 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
1507 tc,lan,line,line,burst_main,highest_priority);\r
1508 safe_run(str);\r
1509\r
1510 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
1511 safe_run(str);\r
1512\r
1513 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
1514 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);\r
1515 safe_run(str);\r
1516\r
1517 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
1518 tc,wan,up,up,burst_main,highest_priority);\r
1519 safe_run(str);\r
1520 }\r
1521\r
1522 /*-----------------------------------------------------------------*/\r
1523 puts("Locating heavy downloaders and generating root classes ...");\r
1524 /*-----------------------------------------------------------------*/\r
1525 sort(ip,ips,desc_order_by,traffic); \r
1526\r
1527 /*-----------------------------------------------------------------*/\r
1528 /* sub-scope - local variables */ \r
1529 {\r
1530 long long int rate = line;\r
1531 long long int max = line;\r
1532 int group_count = 0;\r
1533 FILE *credit_file = NULL;\r
1534 \r
1535 if(!just_preview && !dry_run && enable_credit)\r
1536 {\r
1537 credit_file = fopen(credit,"w");\r
1538 }\r
1539 \r
1540 for_each(group,groups)\r
1541 {\r
1542 if(!just_preview)\r
1543 {\r
1544 //download\r
1545 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
1546 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
1547 safe_run(str);\r
1548 \r
1549 //upload\r
1550 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
1551 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);\r
1552 safe_run(str);\r
1553 }\r
1554 \r
1555 if(group_count++ < max_nesting)\r
1556 {\r
1557 parent = group->id;\r
1558 }\r
1559 \r
1560 rate -= digital_divide*group->min;\r
1561 if(rate < group->min)\r
1562 {\r
1563 rate = group->min;\r
1564 }\r
1565 \r
1566 /*shaping of aggresive downloaders, with credit file support */\r
1567 if(use_credit)\r
1568 {\r
1569 int group_rate = group->min, priority_sequence = lowest_priority;\r
1570 \r
1571 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
1572 {\r
1573 if( ip->keyword->data_limit && !ip->fixedprio \r
1574 && ( ip->traffic>ip->credit\r
1575 + (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))) )\r
1576 {\r
1577 if(group_rate<ip->max)\r
1578 {\r
1579 ip->max=group_rate;\r
1580 }\r
1581 group_rate+=magic_treshold;\r
1582 ip->prio=lowest_priority;\r
1583 if(ip->prio<highest_priority+2)\r
1584 {\r
1585 ip->prio=highest_priority+2;\r
1586 }\r
1587 }\r
1588 else\r
1589 {\r
1590 if( ip->keyword->data_prio \r
1591 && !ip->fixedprio \r
1592 && ( ip->traffic>ip->credit\r
1593 + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
1594 {\r
1595 ip->prio=priority_sequence--;\r
1596 if(ip->prio<highest_priority+1)\r
1597 {\r
1598 ip->prio=highest_priority+1;\r
1599 }\r
1600 }\r
1601 \r
1602 if(credit_file)\r
1603 {\r
1604 unsigned long long lcredit=0;\r
1605 \r
1606 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1607 {\r
1608 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1609 }\r
1610 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1611 }\r
1612 }\r
1613 } \r
1614 }\r
1615 }\r
1616 if(credit_file)\r
1617 {\r
1618 fclose(credit_file);\r
1619 }\r
1620 }\r
1621\r
1622 if(just_preview)\r
1623 {\r
1624 f=fopen(preview,"w");\r
1625 ptr=preview; \r
1626 }\r
1627 else if(!dry_run && !just_flush)\r
1628 {\r
1629 /*-----------------------------------------------------------------*/\r
1630 printf("Writing daily statistics %s ... ", json);\r
1631 /*-----------------------------------------------------------------*/\r
1632 f=fopen(json, "w");\r
1633 if(f > 0)\r
1634 {\r
1635 int jsoncount=0;\r
1636 fprintf(f, "{\n");\r
1637 for_each(ip, ips)\r
1638 {\r
1639 if(jsoncount)\r
1640 {\r
1641 fprintf(f, ",\n");\r
1642 }\r
1643 if(ip->traffic || ip->direct || ip->proxy || ip->upload)\r
1644 {\r
1645 fprintf(f, " %d:{ \"ip\":\"%s\", \"total\":%Lu, \"down\":%Lu, \"proxy\":%Lu, \"up\":%Lu }",\r
1646 ip->lmsid, ip->addr, ip->traffic, ip->direct, ip->proxy, ip->upload);\r
1647 }\r
1648 jsoncount++;\r
1649 }\r
1650 fprintf(f, "}\n");\r
1651 fclose(f);\r
1652 puts("done.");\r
1653 }\r
1654 else\r
1655 {\r
1656 perror(json);\r
1657 }\r
1658 f=fopen(html,"w");\r
1659 ptr=html;\r
1660 }\r
1661\r
1662 if(f)\r
1663 {\r
1664 int count=1;\r
1665 i=0;\r
1666\r
1667 /*-----------------------------------------------------------------*/\r
1668 printf("Sorting data and generating statistics page %s ...\n", ptr);\r
1669 /*-----------------------------------------------------------------*/\r
1670\r
1671 if(use_jquery_popups)\r
1672 {\r
1673 fprintf(f,"<script type=\"text/javascript\" src=\"%s\"></script>\n", jquery_url);\r
1674 }\r
1675 fputs("<table class=\"decorated last\">\n\\r
1676<caption>Bandwidth classes</caption>\n\\r
1677<thead><tr>\n\\r
1678<th style=\"text-align: right\">#</th>\n\\r
1679<th style=\"text-align: right\">group</th>\n\\r
1680<th style=\"text-align: right\">IPs</th>\n\\r
1681<th style=\"text-align: right\">requested</th>\n",f);\r
1682 fprintf(f,"<th colspan=\"%d\">data limits</th>\n", keywordcount);\r
1683 fputs("</tr></thead><tbody>\n",f);\r
1684\r
1685 row_odd_even = 0;\r
1686 for_each(group, groups) \r
1687 { \r
1688#ifdef DEBUG\r
1689 printf("%d kb/s group: %d bandwidth requested: %d kb/s\n",group->min,group->count,group->desired);\r
1690#endif\r
1691 fprintf(f, "%s<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",\r
1692 tr_odd_even(), count, group->min);\r
1693 fprintf(f, "<td style=\"text-align: right\">%d</td><td style=\"text-align: right\">%d&nbsp;kb/s</td>",\r
1694 group->count, group->desired);\r
1695\r
1696 for_each(keyword, keywords) if(keyword->ip_count)\r
1697 {\r
1698 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%d&nbsp;MB</span></td>",\r
1699 keyword->html_color, group->min*keyword->data_limit);\r
1700 } \r
1701 i += group->desired; \r
1702 total += group->count;\r
1703 count++; \r
1704 }\r
1705#ifdef DEBUG\r
1706 printf("Total groups: %d Total bandwidth requested: %d kb/s\nAGGREGATION: 1/%d\n",\r
1707 count, i, i/line);\r
1708#endif\r
1709 fprintf(f,"</tr></tbody>\n\\r
1710<thead><tr>\n\\r
1711<th colspan=\"2\" style=\"text-align: left\">Line %Ld kb/s</td>",line);\r
1712 fprintf(f,"<th style=\"text-align: right\">%d</td><th style=\"text-align: right\">%d kb/s</td>",total,i);\r
1713\r
1714 for_each(keyword, keywords) if(keyword->ip_count)\r
1715 {\r
1716 fprintf(f,"<th style=\"text-align: right\">%d IPs</th>",keyword->ip_count);\r
1717 }\r
1718 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n", (int)(0.5+i/line));\r
1719 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n", keywordcount, total);\r
1720\r
1721 fputs("</thead></table>\n",f);\r
1722 }\r
1723 else if(!dry_run && !just_flush)\r
1724 {\r
1725 perror(html);\r
1726 }\r
1727\r
1728 i=0;\r
1729 if(f)\r
1730 {\r
1731 unsigned long long total_traffic=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;\r
1732 int active_classes=0;\r
1733 int colspan=12;\r
1734 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;\r
1735 int limit_count=0, prio_count=0;\r
1736 int popup_button=0;\r
1737\r
1738 if(qos_proxy)\r
1739 {\r
1740 colspan++;\r
1741 }\r
1742 \r
1743 fprintf(f,"<p><table class=\"decorated last\">\n<caption>%s",title);\r
1744 fprintf(f," (%s)</caption>\n", d);\r
1745 fputs("<thead><tr>\n<th colspan=\"3\">&nbsp;</th>\n",f);\r
1746 fputs("<th style=\"text-align: right\">credit</th>\n\\r
1747<th style=\"text-align: right\">FUP</th>\n\\r
1748<th style=\"text-align: right\">total</th>\n\\r
1749<th style=\"text-align: right\">down</th>\n",f);\r
1750 if(qos_proxy)\r
1751 {\r
1752 fputs("<th style=\"text-align: right\">proxy</th>\n",f);\r
1753 }\r
1754 fputs("<th style=\"text-align: right\">up</th>\n\\r
1755<th style=\"text-align: right\">min</th>\n\\r
1756<th style=\"text-align: right\">max</th>\n\\r
1757<th style=\"text-align: right\">limit</th>\n\\r
1758<th>&nbsp;</th>\n\\r
1759</tr><tr>\n\\r
1760<th style=\"text-align: right\">#</th>\n\\r
1761<th>hostname [+sharing]</th>\n\\r
1762<th style=\"text-align: right\">LMS</th>\n\\r
1763<th style=\"text-align: right\">MB</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\">kb/s</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>prio</th>\n\\r
1772</tr></thead><tbody>\n",f); \r
1773\r
1774 row_odd_even = 0;\r
1775 for_each(ip,ips) if(!use_jquery_popups || !ip->sharing)\r
1776 {\r
1777 char *f1="", *f2="";\r
1778 i++;\r
1779 \r
1780 if(ip->max < ip->desired)\r
1781 {\r
1782 f1="<span style=\"color:red\">";\r
1783 f2="</span>";\r
1784 limit_count++;\r
1785 }\r
1786 else if(ip->prio > highest_priority+1)\r
1787 {\r
1788 f1="<span style=\"color:brown\">";\r
1789 f2="</span>";\r
1790 prio_count++;\r
1791 }\r
1792\r
1793#ifdef DEBUG\r
1794 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max); \r
1795#endif\r
1796 /* hostnames -------------------------------------- */\r
1797 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
1798 tr_odd_even(), ip->name, i, log_url, ip->name, ip->name);\r
1799\r
1800 if(use_jquery_popups)\r
1801 {\r
1802 fprintf(f,"<span id=\"sharing_%d\" style=\"display:none\">",i);\r
1803 popup_button=0;\r
1804 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))\r
1805 {\r
1806 fprintf(f,"<br /><a class=\"blue\" href=\"%s%s.log\">%s</a>\n", log_url, sharedip->name, sharedip->name);\r
1807 popup_button++;\r
1808 }\r
1809 fputs("</span>\n",f);\r
1810 if(popup_button)\r
1811 {\r
1812 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
1813 i, i, i, popup_button);\r
1814 }\r
1815 }\r
1816 fputs("</td>\n",f);\r
1817 /* ----------------------------------------------- */\r
1818\r
1819 if(found_lmsid)\r
1820 {\r
1821 fputs("<td style=\"text-align: right\">",f);\r
1822 if(ip->lmsid > 0)\r
1823 {\r
1824 fprintf(f,"<a class=\"blue\" href=\"%s%d\">%04d</a>\n", lms_url, ip->lmsid, ip->lmsid);\r
1825 }\r
1826 else if(ip->lmsid == 0)\r
1827 {\r
1828 fputs("-------",f);\r
1829 }\r
1830 fputs("</td>\n",f);\r
1831 }\r
1832 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->credit);\r
1833 fprintf(f,"<td style=\"text-align: right\"><span style=\"color:#%s\">%Lu</span></td>",\r
1834 ip->keyword->html_color,\r
1835 ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));\r
1836 fprintf(f,"<td style=\"text-align: right\">%s%Lu%s", f1, ip->traffic, f2);\r
1837\r
1838 /* download --------------------------------------- */\r
1839 fprintf(f,"</td><td style=\"text-align: right\">%Lu", ip->direct);\r
1840 if(use_jquery_popups)\r
1841 {\r
1842 fprintf(f,"<span id=\"download_%d\" style=\"display:none\">",i);\r
1843 for_each(sharedip, ips) if(eq(ip->name, sharedip->sharing))\r
1844 {\r
1845 fprintf(f,"<br />%Lu", sharedip->direct);\r
1846 }\r
1847 fputs("</span>\n",f);\r
1848 }\r
1849 fputs("</td>\n",f);\r
1850 /* ----------------------------------------------- */\r
1851\r
1852 if(qos_proxy)\r
1853 {\r
1854 fprintf(f,"<td style=\"text-align: right\">%Lu</td>\n", ip->proxy);\r
1855 }\r
1856 /* upload ---------------------------------------- */\r
1857 fprintf(f,"<td style=\"text-align: right\">%Lu", ip->upload);\r
1858 if(use_jquery_popups)\r
1859 {\r
1860 fprintf(f,"<span id=\"upload_%d\" style=\"display:none\">",i);\r
1861 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))\r
1862 {\r
1863 fprintf(f,"<br />%Lu", sharedip->upload);\r
1864 }\r
1865 fputs("</span>\n",f);\r
1866 }\r
1867 fputs("</td>\n",f);\r
1868 /* ----------------------------------------------- */\r
1869\r
1870 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1871<td style=\"text-align: right\">%d</td>\n\\r
1872<td style=\"text-align: right\">%s%d%s</td>\n\\r
1873<td>%s%d%s</td></tr>\n",\r
1874 ip->min, ip->desired, \r
1875 f1, ip->max, f2, \r
1876 f1, ip->prio, f2);\r
1877\r
1878 total_traffic+=ip->traffic;\r
1879 total_direct+=ip->direct;\r
1880 total_proxy+=ip->proxy;\r
1881 total_upload+=ip->upload;\r
1882 if(ip->traffic>0)\r
1883 {\r
1884 active_classes++;\r
1885 tmp_sum+=ip->traffic;\r
1886 create(sum,Sum);\r
1887 sum->l=tmp_sum;\r
1888 sum->i=active_classes;\r
1889 insert(sum,sums,order_by,i);\r
1890 }\r
1891\r
1892 if(!just_preview)\r
1893 {\r
1894 append_log(ip);\r
1895 for_each(sharedip,ips) if(eq(ip->name, sharedip->sharing))\r
1896 {\r
1897 append_log(sharedip);\r
1898 }\r
1899 }\r
1900 }\r
1901 fprintf(f,"</tbody><thead><tr>\n\\r
1902<th colspan=\"%d\" style=\"text-align: left\">%d CLASSES</th>", colspan-7, i);\r
1903 fprintf(f,"<th style=\"text-align: right\">%Lu</th><th style=\"text-align: right\">%Lu</th>\n", total_traffic, total_direct);\r
1904 if(qos_proxy)\r
1905 {\r
1906 fprintf(f,"<th style=\"text-align: right\">%Lu</th>\n", total_proxy);\r
1907 }\r
1908 fprintf(f,"<th style=\"text-align: right\">%Lu</th>", total_upload);\r
1909 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
1910\r
1911 row_odd_even = 0;\r
1912 if(active_classes>10)\r
1913 {\r
1914 int top20_count=0,top20_perc1=0;\r
1915 long long top20_perc2=0;\r
1916 unsigned long long top20_sum=0l;\r
1917 \r
1918 fputs("<a name=\"erp\"></a><p><table class=\"decorated last\"><caption>Enterprise Resource Planning (ERP)</caption>\n",f);\r
1919 fputs("<thead><tr>\n\\r
1920<th>Analytic category</th>\n\\r
1921<th colspan=\"2\" style=\"text-align: center\">Active Classes</th>\n\\r
1922<th colspan=\"2\" style=\"text-align: center\">Data transfers</th>\n\\r
1923</tr></thead><tbody>\n",f);\r
1924\r
1925 if_exists(sum,sums,sum->l>=total_traffic/4)\r
1926 {\r
1927 fprintf(f,"%s<td>Top 25%% of traffic</td>\n", tr_odd_even());\r
1928 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
1929 }\r
1930 \r
1931 if_exists(sum,sums,sum->i==10)\r
1932 {\r
1933 fprintf(f,"%s<td>Top 10 downloaders</td>\n", tr_odd_even());\r
1934 fprintf(f,"<td style=\"text-align: right\"><strong>10</strong></td>\n\\r
1935<td style=\"text-align: right\">%d %%</td>\n\\r
1936<td style=\"text-align: right\">%Lu MB</td>\n\\r
1937<td style=\"text-align: right\">%Ld %%</td></tr>\n",\r
1938 (100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
1939 }\r
1940\r
1941 if_exists(sum,sums,sum->l>=total_traffic/2)\r
1942 {\r
1943 fprintf(f,"%s<td>Top 50%% of traffic</td>\n", tr_odd_even());\r
1944 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1945<td style=\"text-align: right\">%d %%</td>\n\\r
1946<td style=\"text-align: right\">%Lu MB</td>\n\\r
1947<td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",\r
1948 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
1949 }\r
1950\r
1951 if_exists(sum,sums,sum->l>=4*total_traffic/5)\r
1952 {\r
1953 fprintf(f,"%s<td>Top 80%% of traffic</td>\n", tr_odd_even());\r
1954 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1955<td style=\"text-align: right\">%d %%</td>\n\\r
1956<td style=\"text-align: right\">%Lu MB</td>\n\\r
1957<td style=\"text-align: right\"><strong>%Ld %%</strong></td></tr>\n",\r
1958 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
1959 }\r
1960\r
1961 if_exists(sum,sums,sum->i>=(active_classes+1)/5)\r
1962 {\r
1963 fprintf(f,"%s<td>Top 20%% downloaders</td>\n", tr_odd_even());\r
1964 top20_count=sum->i;\r
1965 top20_perc1=(100*sum->i+50)/active_classes;\r
1966 top20_sum=sum->l;\r
1967 top20_perc2=(100*sum->l+50)/total_traffic;\r
1968 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1969<td style=\"text-align: right\"><strong>%d %%</strong></td>\n\\r
1970<td style=\"text-align: right\">%Lu MB</td>\n\\r
1971<td style=\"text-align: right\">%Ld %%</td></tr>\n",\r
1972 top20_count,top20_perc1,top20_sum,top20_perc2);\r
1973 }\r
1974\r
1975 if_exists(sum,sums,sum->i>=(active_classes+1)/4)\r
1976 {\r
1977 fprintf(f,"%s<td>Top 25%% downloaders</td>\n", tr_odd_even());\r
1978 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1979<td style=\"text-align: right\">%d %%</td>\n\\r
1980<td style=\"text-align: right\">%Lu MB</td>\n\\r
1981<td style=\"text-align: right\">%Ld %%</td></tr>\n",\r
1982 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
1983 }\r
1984\r
1985 if_exists(sum,sums,sum->i>=(active_classes+1)/2)\r
1986 {\r
1987 fprintf(f,"%s<td>Top 50%% downloaders</td>\n", tr_odd_even());\r
1988 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1989<td style=\"text-align: right\"><strong>%d %%</strong></td>\n\\r
1990<td style=\"text-align: right\">%Lu MB</td>\n\\r
1991<td style=\"text-align: right\">%Ld %%</td></tr>\n",\r
1992 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
1993 }\r
1994\r
1995 if_exists(sum,sums,sum->i>=4*(active_classes+1)/5)\r
1996 {\r
1997 fprintf(f,"%s<td>Top 80%% downloaders</td>\n", tr_odd_even());\r
1998 fprintf(f,"<td style=\"text-align: right\">%d</td>\n\\r
1999<td style=\"text-align: right\">%d %%</td>\n\\r
2000<td style=\"text-align: right\">%Lu MB</td>\n\\r
2001<td style=\"text-align: right\">%Ld %%</td></tr></tbody>\n",\r
2002 sum->i,(100*sum->i+50)/active_classes,sum->l,(100*sum->l+50)/total_traffic);\r
2003 }\r
2004\r
2005 fprintf(f,"<tr><thead><th><a class=\"blue\" href=\"%sERP.log\">All users, all traffic</a></th>\n", log_url);\r
2006 fprintf(f,"<th style=\"text-align: right\">%d</th>\n\\r
2007<th style=\"text-align: right\">100 %%</th>\n\\r
2008<th style=\"text-align: right\">%Lu M</th>\n\\r
2009<th style=\"text-align: right\">100 %%</th></tr>\n",active_classes,total_traffic);\r
2010 fputs("</thead></table>\n", f);\r
2011\r
2012 /* write basic ERP data to log directory */\r
2013 if(!just_preview)\r
2014 {\r
2015 FILE *iplog;\r
2016 sprintf(str,"%s/ERP.log",log_dir);\r
2017 iplog=fopen(str,"a");\r
2018 if(iplog)\r
2019 {\r
2020 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
2021 time(NULL), top20_count, top20_perc1, top20_sum, top20_perc2, \r
2022 active_classes, total_traffic, i, limit_count, prio_count, d); /* d = date*/\r
2023 fclose(iplog);\r
2024 }\r
2025 else\r
2026 {\r
2027 perror(str);\r
2028 }\r
2029 }\r
2030 }\r
2031\r
2032 fprintf(f, stats_html_signature, version);\r
2033 fclose(f);\r
2034 }\r
2035\r
2036 if(just_preview)\r
2037 {\r
2038 puts("Statistics preview generated (-p switch) - now exiting ...");\r
2039 exit(0);\r
2040 } \r
2041\r
2042 i=0;\r
2043#ifdef DEBUG\r
2044 printf("%-22s %-15s mark\n","name","ip");\r
2045#endif\r
2046\r
2047 printf("Writing %s ... ", classmap); \r
2048 f = fopen(classmap, "w"); \r
2049 if(f < 0)\r
2050 {\r
2051 perror(classmap);\r
2052 }\r
2053\r
2054 /*-----------------------------------------------------------------*/\r
2055 puts("Generating iptables and tc classes ... ");\r
2056 /*-----------------------------------------------------------------*/\r
2057\r
2058 for_each(ip, ips) if(ip->mark > 0)\r
2059 {\r
2060 if(idxs)\r
2061 {\r
2062 char *buf;\r
2063 duplicate(ip->addr,buf);\r
2064 buf=hash_id(ip->addr,32-idxtable_bitmask1); \r
2065 \r
2066 string(chain_forward,6+strlen(buf));\r
2067 strcpy(chain_forward,"forw_");\r
2068 strcat(chain_forward,buf);\r
2069\r
2070 string(chain_postrouting,6+strlen(buf));\r
2071 strcpy(chain_postrouting,"post_");\r
2072 strcat(chain_postrouting,buf);\r
2073 \r
2074 free(buf);\r
2075 }\r
2076 else\r
2077 {\r
2078 chain_forward="FORWARD";\r
2079 chain_postrouting="POSTROUTING";\r
2080 }\r
2081\r
2082#ifdef DEBUG\r
2083 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark); \r
2084#endif\r
2085\r
2086 /* -------------------------------------------------------- mark download */\r
2087 \r
2088 sprintf(str, "-A %s -d %s/32 -o %s -j %s%d",\r
2089 chain_postrouting, ip->addr, lan, mark_iptables, ip->mark);\r
2090 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/\r
2091 /* -m limit --limit 1/s */ \r
2092 save_line(str);\r
2093\r
2094 if(qos_proxy)\r
2095 {\r
2096 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/32 -o %s -j %s%d",\r
2097 chain_postrouting, proxy_ip, proxy_port, ip->addr, lan, mark_iptables, ip->mark);\r
2098 /*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
2099 save_line(str);\r
2100 }\r
2101\r
2102 sprintf(str, "-A %s -d %s/32 -o %s -j ACCEPT",\r
2103 chain_postrouting, ip->addr, lan);\r
2104 save_line(str);\r
2105\r
2106 /* -------------------------------------------------------- mark upload */\r
2107 sprintf(str, "-A %s -s %s/32 -o %s -j %s%d", \r
2108 chain_forward, ip->addr, wan, mark_iptables, ip->mark);\r
2109 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/\r
2110 save_line(str);\r
2111\r
2112 sprintf(str, "-A %s -s %s/32 -o %s -j ACCEPT",\r
2113 chain_forward, ip->addr, wan);\r
2114 save_line(str);\r
2115\r
2116 if(ip->min)\r
2117 {\r
2118 /* -------------------------------------------------------- download class */\r
2119#ifdef DEBUG\r
2120 printf("(down: %dk-%dk ", ip->min, ip->max); \r
2121#endif\r
2122\r
2123 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
2124 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);\r
2125 safe_run(str);\r
2126\r
2127 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
2128 {\r
2129 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
2130 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
2131 safe_run(str);\r
2132 }\r
2133\r
2134 if(filter_type == 1)\r
2135 {\r
2136 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
2137 tc, lan, ip->mark, ip->mark);\r
2138 safe_run(str);\r
2139 }\r
2140\r
2141 /* -------------------------------------------------------- upload class */\r
2142#ifdef DEBUG\r
2143 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
2144 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
2145#endif\r
2146\r
2147 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
2148 tc, wan, ip->group, ip->mark,\r
2149 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
2150 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
2151 safe_run(str);\r
2152 \r
2153 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
2154 {\r
2155 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",\r
2156 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
2157 safe_run(str);\r
2158 } \r
2159\r
2160 if(filter_type == 1)\r
2161 {\r
2162 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
2163 tc, wan, ip->mark, ip->mark);\r
2164 safe_run(str);\r
2165 }\r
2166 \r
2167 if(f)\r
2168 {\r
2169 fprintf(f, "%s %d", ip->addr, ip->mark);\r
2170 }\r
2171 }\r
2172 else\r
2173 {\r
2174#ifdef DEBUG\r
2175 printf("(sharing %s)\n", ip->sharing);\r
2176#endif\r
2177 }\r
2178 i++;\r
2179 }\r
2180 if(f)\r
2181 {\r
2182 puts("done.");\r
2183 fclose(f);\r
2184 }\r
2185 \r
2186 if(idxs)\r
2187 {\r
2188 chain_forward = "forw_common";\r
2189 chain_postrouting = "post_common";\r
2190 }\r
2191 else\r
2192 {\r
2193 chain_forward = "FORWARD";\r
2194 chain_postrouting = "POSTROUTING";\r
2195 }\r
2196 /* -------------------------------- classify or reject free download */\r
2197 {\r
2198 char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */\r
2199 if(free_min)\r
2200 {\r
2201 final_chain = "ACCEPT";\r
2202 }\r
2203 if(qos_proxy)\r
2204 {\r
2205 if(free_min)\r
2206 {\r
2207 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s%d",\r
2208 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables,3);\r
2209 save_line(str);\r
2210 }\r
2211 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j %s",\r
2212 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);\r
2213 save_line(str);\r
2214 }\r
2215 if(free_min)\r
2216 {\r
2217 sprintf(str,"-A %s -o %s -j %s%d", chain_postrouting, lan, mark_iptables, 3);\r
2218 save_line(str);\r
2219 }\r
2220 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
2221 save_line(str);\r
2222 /* ------------------------------- classify or reject free upload */\r
2223 if(free_min)\r
2224 {\r
2225 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, 3);\r
2226 save_line(str);\r
2227 }\r
2228 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);\r
2229 save_line(str);\r
2230 }\r
2231\r
2232 if(free_min) /* allocate free bandwith if it is not zero... */ \r
2233 {\r
2234 /*-----------------------------------------------------------------*/\r
2235 puts("Generating free bandwith classes ...");\r
2236 /*-----------------------------------------------------------------*/\r
2237 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
2238 tc, lan, parent, free_min, free_max,burst, lowest_priority);\r
2239 safe_run(str);\r
2240 sprintf(str, "%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
2241 tc, wan, parent, free_min, free_max, burst, lowest_priority);\r
2242 safe_run(str);\r
2243 /* tc SFQ */\r
2244 if(strcmpi(qos_leaf, "none"))\r
2245 {\r
2246 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, lan, qos_leaf);\r
2247 safe_run(str);\r
2248 \r
2249 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s", tc, wan, qos_leaf);\r
2250 safe_run(str);\r
2251 } \r
2252 /* tc handle 1 fw flowid */\r
2253 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, lan);\r
2254 safe_run(str);\r
2255\r
2256 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3", tc, wan);\r
2257 safe_run(str);\r
2258 }\r
2259 printf("Total IP count: %d\n", i);\r
2260 run_restore(); \r
2261 if(log_file)\r
2262 {\r
2263 fclose(log_file);\r
2264 }\r
2265 return 0;\r
2266 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
2267 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
2268}\r
This page took 0.316836 seconds and 4 git commands to generate.