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