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