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