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