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