..
[svn/Prometheus-QoS/.git] / prometheus.c
CommitLineData
0d5026c6 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
007c44c5 9\r
ae776b10 10/* Modified: xChaos, 20080202\r
007c44c5 11 ludva, 20071227\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
d1ae4fa7 23 You should have received a copy of the GNU General Public License
24 along with Prometheus Qos; if not, write to the Free Software
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 */
007c44c5 28\r
29#define STRLEN 256\r
30#define FIRSTGROUPID 1024\r
43e07280 31#define FIRSTIPCLASS 2048\r
007c44c5 32#undef DEBUG\r
33\r
211415b9 34#include "cll1-0.6.h"\r
007c44c5 35\r
43e07280 36const char *version="0.7.8"; /*0.7.9 will be last development, 0.8.0 first stable */\r
007c44c5 37\r
ae776b10 38/* ======= All path names are defined hear (for RPM patch) ======= */\r
39\r
40char *tc = "/sbin/tc"; /* requires tc with HTB support */\r
41char *iptables = "/sbin/iptables"; /* requires iptables utility */\r
42char *iptablessave = "/sbin/iptables-save"; /* not yet required */\r
43char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */\r
44\r
45char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */\r
46char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */\r
47\r
48char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/\r
49char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */\r
50char *html = "/var/www/traffic.html"; /* hall of fame filename */\r
51char *preview = "/var/www/preview.html"; /* hall of fame preview */\r
52char *cmdlog = "/var/log/prometheuslog"; /* command log filename */\r
53char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */\r
54char *log_url = "logs/"; /* log directory relative URI prefix (partial URL) */\r
55\r
007c44c5 56/* ======= Help screen is hopefuly self-documenting part of code :-) ======= */\r
57\r
58void help(void)\r
59{\r
60 puts("Command line switches:\n\\r
61\n\\r
62-?, --help this help screen\n\\r
63-v, --version show version number of this utility and exit\n\\r
64-c filename force alternative /etc/prometheus.conf filename\n\\r
65-h filename force alternative /etc/hosts filename (overrides hosts keyword)\n\\r
66-f just flush iptables and tc classes and exit (stop shaping)\n\\r
67-9 emergency iptables flush (do not read data transfer statistics)\n\\r
68-p just generate preview of data transfer statistics and exit\n\\r
69-n no delay (overrides qos-free-delay keyword)\n\\r
70-d dry run (preview tc and iptables commands on stdout)\n\\r
71");\r
72}\r
73\r
74/* === Configuraration file values defaults - stored in global variables ==== */\r
75\r
76int filter_type=1; /*1 mark, 2 classify*/\r
77char *mark="MARK";\r
78char *mark_iptables="MARK --set-mark ";\r
79int dry_run=0; /* preview - use puts() instead of system() */\r
007c44c5 80char *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
81FILE *iptables_file=NULL;\r
007c44c5 82int enable_credit=1; /* enable credit file */\r
83int use_credit=0; /* use credit file (if enabled)*/\r
007c44c5 84char *title="Hall of Fame - Greatest Suckers"; /* hall of fame title */\r
85int hall_of_fame=1; /* enable hall of fame */\r
86char *lan="eth0"; /* LAN interface */\r
87char *lan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */\r
88char *wan="eth1"; /* WAN/ISP interface */\r
89char *wan_medium="100Mbit"; /* 10Mbit/100Mbit ethernet */\r
90char *qos_leaf="sfq perturb 5"; /* leaf discipline */\r
91char *qos_free_zone=NULL; /* QoS free zone */\r
92int qos_proxy=1; /* include proxy port to QoS */\r
93int include_upload=1; /* upload+download=total traffic */\r
94char *proxy_ip="192.168.1.1/32"; /* our IP with proxy port */\r
95int proxy_port=3128; /* proxy port number */\r
0d5026c6 96long long int line=1024; /* WAN/ISP download in kbps */\r
97long long int up=1024; /* WAN/ISP upload in kbps */\r
007c44c5 98int free_min=32; /* minimum guaranted bandwidth for all undefined hosts */\r
99int free_max=64; /* maximum allowed bandwidth for all undefined hosts */\r
100int qos_free_delay=0; /* seconds to sleep before applying new QoS rules */\r
101int digital_divide=2; /* controls digital divide weirdness ratio, 1...3 */ \r
102int max_nesting=3; /* maximum nesting of HTB clases, built-in maximum seems to be 4 */\r
103int htb_r2q=1; \r
104int burst=8; /* HTB burst (in kbits) */\r
105int burst_main=64;\r
106int burst_group=32;\r
107int magic_priorities=8; /* number of priority levels (soft shaping) */\r
108int magic_treshold=8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */\r
109int keywordcount=0;\r
110\r
111/* not yet implemented:\r
112 int fixed_packets=0; maximum number of pps per IP address (not class!) \r
113 int packet_limit=5; maximum number of pps to htn CEIL, not rate !!! \r
114*/\r
115FILE *log_file=NULL;\r
116\r
117char *kwd="via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */\r
118\r
0d5026c6 119const int idxtable_treshold1=24; /* this is no longer configurable */\r
120const int idxtable_treshold2=12; /* this is no longer configurable */\r
121const int idxtable_bitmask1=3; /* this is no longer configurable */\r
122const int idxtable_bitmask2=3; /* this is no longer configurable */\r
007c44c5 123\r
124\r
125/* not yet implemented:\r
126-s start shaping! (keep data transfer statistics - but apply shaping)\n\\r
127-r just reload configuration (...and keep data transfer statistics)\n\\r
128*/\r
129\r
130/* ==== This is C<<1 stuff - learn C<<1 first! http://cll1.arachne.cz ==== */\r
131\r
132struct IP\r
133{\r
134 char *addr;\r
135 char *name;\r
136 char *sharing;\r
137 int min;\r
138 int desired;\r
139 int max;\r
140 int mark;\r
141 int prio;\r
142 int fixedprio;\r
143 int group;\r
144 unsigned long long direct;\r
145 unsigned long long proxy;\r
146 unsigned long long upload;\r
147 unsigned long long traffic;\r
148 unsigned long long credit;\r
149 unsigned long pktsup;\r
150 unsigned long pktsdown;\r
151 struct Keyword *keyword;\r
152 list(IP);\r
153} *ips=NULL, *ip, *sharedip;\r
154\r
155struct Group\r
156{\r
157 int min;\r
158 int count;\r
159 int desired;\r
160 int id;\r
161 list(Group);\r
162} *groups=NULL, *group;\r
163\r
164struct Index\r
165{\r
166 char *addr;\r
167 char *id;\r
168 struct Index *parent;\r
169 int bitmask;\r
170 int children;\r
171 list(Index);\r
172} *idxs=NULL, *idx, *metaindex;\r
173\r
174struct Keyword\r
175{\r
176 char *key;\r
177 \r
178 int asymetry_ratio; /* ratio for ADSL-like upload */\r
179 int asymetry_fixed; /* fixed treshold for ADSL-like upload */\r
180 int data_limit; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
99127c70 181 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
007c44c5 182 long fixed_limit; /* fixed data limit for setting lower HTB ceil */\r
183 long fixed_prio; /* fixed data lmit for setting lower HTB prio */\r
184 int reserve_min; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
185 int reserve_max; /* malus for nominal HTB ceil (in kbps) */\r
186// int divide_max; /* relative malus: new_ceil=rate+(old_ceil-rate)/divide_max */\r
187// int htb_ceil_bonus_divide; /* relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide */\r
188 int default_prio; /* default HTB priority for this keyword */\r
189 char *html_color;\r
190 int ip_count;\r
191 char *leaf_discipline;\r
192 \r
193 list(Keyword);\r
194} *keyword,*defaultkeyword=NULL,*keywords=NULL;\r
195\r
196/* Damned, this must be object oriented! This looks almost like constructor ;-) */\r
197\r
198void TheIP(void)\r
199{\r
200 create(ip,IP);\r
201 ip->name="";\r
202 ip->addr="";\r
203 ip->sharing=NULL;\r
204 ip->prio=1;\r
205 ip->fixedprio=0;\r
206 ip->mark=ip->min=ip->max=ip->desired=ip->credit=0;\r
207 ip->upload=ip->proxy=ip->direct=ip->traffic=0;\r
208 ip->pktsup=ip->pktsdown=0;\r
209 ip->keyword=keywords;\r
210 push(ip,ips);\r
211}\r
212\r
213/* ====== Iptables indexes are used to reduce complexity to log8(N) ===== */\r
214\r
215char *very_ugly_ipv4_code(char *inip,int bitmask,int format_as_chainname)\r
216{\r
217 /* warning: this function was debugged only for bitmask values 20,24,28 !!!*/\r
218 int dot=0,n;\r
219 char *ip,*outip,*outptr,*fmt;\r
220\r
221 duplicate(inip,ip);\r
222 /* debug printf("(%s,%d) -> ",ip,bitmask); */\r
223\r
224 if(ip && *ip && bitmask>=0 && bitmask<=32)\r
225 string(outip,strlen(ip)+10); /*fuck unicode? assertion: 10>strlen("_%d_%d") */\r
226 else \r
227 /* should never exit here */\r
228 return "undefined";\r
229 outptr=outip;\r
230 while(ip && *ip)\r
231 {\r
232 if(*ip=='.')\r
233 {\r
234 if(dot<(bitmask/8-1)) \r
235 {\r
236 if(format_as_chainname)\r
237 *outptr='_';\r
238 else\r
239 *outptr='.';\r
240 outptr++;\r
241 dot++;\r
242 }\r
243 else\r
244 {\r
245 char *cutdot=strchr(ip+1,'.'); /*for bitmask<24*/\r
246 if(cutdot)*cutdot='\0';\r
247 if(format_as_chainname)\r
248 fmt="_%d_%d";\r
249 else\r
250 fmt=".%d";\r
251 if(bitmask%8)\r
252 n=atoi(ip+1)-atoi(ip+1)%(1<<(8-bitmask%8));\r
253 else\r
254 n=0;\r
255\r
256 /*debug printf("%d/%d => [_%d_%d]\n",atoi(ip+1),bitmask,n,bitmask); */\r
257 sprintf(outptr,fmt,n,bitmask);\r
258 if(!format_as_chainname) while(bitmask<24)\r
259 {\r
260 strcat(outip,".0");\r
261 bitmask+=8;\r
262 }\r
263 /* debug printf("[%s]\n",outip); */\r
264 return outip;\r
265 }\r
266 }\r
267 else \r
268 {\r
269 *outptr=*ip;\r
270 outptr++;\r
271 }\r
272 ip++;\r
273 }\r
274 /*should never exit here*/\r
275 *outptr='\0';\r
276 return outip;\r
277}\r
278\r
279char *hash_id(char *ip,int bitmask)\r
280{ return very_ugly_ipv4_code(ip,bitmask,1); }\r
281\r
282char *subnet_id(char *ip,int bitmask)\r
283{ return very_ugly_ipv4_code(ip,bitmask,0); }\r
284\r
285/* ================= Let's parse configuration file here =================== */\r
286\r
287void reject_config_and_exit(char *filename)\r
288{\r
289 printf("Configuration file %s rejected - abnormal exit.",filename);\r
290 exit(-1);\r
291}\r
292\r
293void get_config(char *config_filename)\r
294{\r
295 char *cnf="mark";\r
296 \r
297 printf("Configured keywords: ");\r
298 parse(config_filename)\r
299 {\r
300 option("keyword",kwd);\r
301 if(kwd)\r
302 {\r
303 printf("%s ",kwd);\r
304\r
305 create(keyword,Keyword);\r
306 keyword->key=kwd;\r
307 keyword->asymetry_ratio=1; /* ratio for ADSL-like upload */\r
308 keyword->asymetry_fixed=0; /* fixed treshold for ADSL-like upload */\r
309 keyword->data_limit=8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
99127c70 310 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
007c44c5 311 keyword->fixed_limit=0; /* fixed data limit for setting lower HTB ceil */\r
312 keyword->fixed_prio=0; /* fixed data limit for setting lower HTB prio */\r
313 keyword->reserve_min=8; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
314 keyword->reserve_max=0; /* malus for nominal HTB ceil (in kbps) */\r
315/* obsolete:\r
316 keyword->divide_max=0; relative malus: new_ceil=rate+(old_ceil-rate)/divide_max\r
317 keyword->htb_ceil_bonus_divide=0; relative bonus: new_ceil=old_ceil+old_ceil/htb_ceil_bonus_divide\r
318*/\r
319 keyword->default_prio=1;\r
320 keyword->html_color="000000";\r
321 keyword->ip_count=0;\r
322 keyword->leaf_discipline="";\r
323\r
324 push(keyword,keywords);\r
325 if(!defaultkeyword) defaultkeyword=keyword;\r
326 keywordcount++;\r
327 \r
328 kwd=NULL;\r
329 }\r
330 else every(keyword,keywords)\r
331 {\r
332 int l=strlen(keyword->key);\r
333\r
334\r
335 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)\r
336 {\r
337 char *tmptr=_; /* <---- l+1 ----> */\r
338 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */\r
339 ioption("asymetry-ratio",keyword->asymetry_ratio);\r
340 ioption("asymetry-treshold",keyword->asymetry_fixed);\r
341 ioption("magic-relative-limit",keyword->data_limit);\r
99127c70 342 ioption("magic-relative-prio",keyword->data_prio);\r
007c44c5 343 loption("magic-fixed-limit",keyword->fixed_limit);\r
344 loption("magic-fixed-prio",keyword->fixed_prio);\r
345 ioption("htb-default-prio",keyword->default_prio);\r
346 ioption("htb-rate-bonus",keyword->reserve_min);\r
347 ioption("htb-ceil-malus",keyword->reserve_max);\r
348/* obsolete:\r
349 ioption("htb-ceil-divide",keyword->divide_max);\r
350 ioption("htb-ceil-bonus-divide",keyword->htb_ceil_bonus_divide);\r
351*/\r
352 option("leaf-discipline",keyword->leaf_discipline);\r
353 option("html-color",keyword->html_color);\r
354 _=tmptr;\r
355 \r
356 if(keyword->data_limit || keyword->fixed_limit || \r
99127c70 357 keyword->data_prio || keyword->fixed_prio)\r
007c44c5 358 use_credit=1;\r
359 \r
360\r
361 }\r
362 }\r
363\r
364 option("tc",tc);\r
365 option("iptables",iptables);\r
366 option("iptables-save",iptablessave); /* new */\r
367 option("iptables-restore",iptablesrestore); /* new */\r
368 option("iptables-file",iptablesfile); /* new */\r
369 option("hosts",hosts);\r
370 option("lan-interface",lan);\r
371 option("wan-interface",wan);\r
372 option("lan-medium",lan_medium);\r
373 option("wan-medium",wan_medium);\r
374 lloption("wan-download",line);\r
375 lloption("wan-upload",up);\r
376 ioption("hall-of-fame-enable",hall_of_fame);\r
377 option("hall-of-fame-title",title);\r
378 option("hall-of-fame-filename",html);\r
379 option("hall-of-fame-preview",preview);\r
380 option("log-filename",cmdlog);\r
381 option("credit-filename",credit);\r
382 ioption("credit-enable",enable_credit);\r
383 option("log-traffic-directory",log_dir);\r
384 option("log-traffic-url-path",log_url);\r
385 option("qos-free-zone",qos_free_zone);\r
386 ioption("qos-free-delay",qos_free_delay);\r
387 ioption("qos-proxy-enable",qos_proxy);\r
388 option("qos-proxy-ip",proxy_ip);\r
389 option("htb-leaf-discipline",qos_leaf);\r
390 ioption("qos-proxy-port",proxy_port);\r
391 ioption("free-rate",free_min);\r
392 ioption("free-ceil",free_max);\r
393 ioption("htb-burst",burst);\r
394 ioption("htb-burst-main",burst_main);\r
395 ioption("htb-burst-group",burst_group);\r
396 ioption("htb-nesting-limit",max_nesting);\r
397 ioption("htb-r2q",htb_r2q);\r
398 ioption("magic-include-upload",include_upload);\r
399 ioption("magic-priorities",magic_priorities);\r
400 ioption("magic-treshold",magic_treshold);\r
401 \r
402 option("filter-type", cnf);\r
403 \r
404/* not yet implemented:\r
405 ioption("magic-fixed-packets",fixed_packets);\r
406 ioption("magic-relative-packets",packet_limit);\r
407*/\r
408 }\r
409 fail\r
410 { \r
411 perror(config_filename);\r
412 puts("Warning - using built-in defaults instead ...");\r
413 }\r
414 done;\r
415 printf("\n");\r
416 \r
417 /*leaf discipline for keywords*/\r
418 every(keyword,keywords)\r
419 {\r
420 if (!strcmpi(keyword->leaf_discipline, "")){\r
421 keyword->leaf_discipline = qos_leaf;\r
422 }\r
423 }\r
424\r
425 if (strcmpi(cnf, "mark")){\r
426 filter_type = 2;\r
427 mark = "CLASSIFY";\r
428 mark_iptables = "CLASSIFY --set-class 1:";\r
429 }else{\r
430 filter_type = 1;\r
431 mark = "MARK";\r
432 mark_iptables = "MARK --set-mark ";\r
433 }\r
434\r
435 /* are supplied values meaningful ?*/\r
436 if(line<=0 || up<=0)\r
437 {\r
438 puts("Illegal value of wan bandwidth: 0 kbps.");\r
439 reject_config_and_exit(config_filename);\r
440 }\r
441}\r
442\r
443/* ===================== traffic analyser - uses iptables ================ */ \r
444\r
445void get_traffic_statistics(void)\r
446{\r
447 char *str,*cmd;\r
448 int downloadflag=0;\r
449\r
450 textfile(Pipe,str) *line,*lines=NULL;\r
451 string(str,STRLEN);\r
452 string(cmd,STRLEN);\r
453\r
454 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);\r
455 shell(cmd);\r
456 input(str,STRLEN)\r
457 {\r
458 create(line,Pipe);\r
459 line->str=str;\r
460 string(str,STRLEN);\r
461 append(line,lines);\r
462 }\r
463\r
464 every(line,lines)\r
465 {\r
466 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0; \r
467 unsigned long long traffic=0;\r
468 unsigned long pkts=0;\r
469 char *ipaddr=NULL,*ptr;\r
470 \r
471 /* debug puts(line->str); */\r
472 valid_columns(ptr,line->str,' ',col) \r
473 if(valid) switch(col)\r
474 { \r
475 case 1: if(eq(ptr,"Chain"))\r
476 setchainname=1;\r
477 else if(eq(ptr,"pkts")) \r
478 valid=0;\r
479 else\r
480 sscanf(ptr,"%lu",&pkts); \r
481 break;\r
482 case 2: if(setchainname)\r
483 {\r
484 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))\r
485 downloadflag=1; \r
486 else \r
487 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))\r
488 downloadflag=0;\r
489 \r
490 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))\r
491 commonflag=1;\r
492 }\r
493 else\r
494 sscanf(ptr,"%Lu",&traffic); traffic+=(1<<19); traffic>>=20;\r
495 break;\r
0045483c 496 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)\r
007c44c5 497 accept=eq(ptr,mark);\r
498 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/\r
499 break;\r
500 case 8: if(downloadflag)\r
501 { \r
502 if(strstr(proxy_ip,ptr))proxyflag=1; \r
503 }\r
504 else\r
505 ipaddr=ptr; \r
506 break;\r
507 case 9: if(downloadflag)ipaddr=ptr;break;\r
508 }\r
509 \r
510 if(accept && traffic>0 && ipaddr)\r
511 {\r
512 if(proxyflag)printf("(proxy) ");\r
513 else if(!downloadflag) printf("(upload) ");\r
514 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr, traffic, pkts);\r
515 find(ip,ips,eq(ip->addr,ipaddr)); \r
516 else \r
517 {\r
518 TheIP();\r
519 ip->addr=ipaddr;\r
520 if(eq(ip->addr,"0.0.0.0/0"))\r
521 {\r
522 ip->name="(unregistered)";\r
523 ip->min=free_min;\r
524 ip->max=ip->desired=free_max;\r
525 }\r
526 }\r
527 \r
528 if(downloadflag)\r
529 {\r
530 if(proxyflag)\r
531 ip->proxy=traffic;\r
532 else\r
533 ip->traffic+=traffic;\r
534 ip->direct=ip->traffic-ip->upload-ip->proxy;\r
535 ip->pktsdown=pkts;\r
536 }\r
537 else\r
538 {\r
539 ip->upload=traffic;\r
540 ip->pktsup=pkts;\r
541 if(include_upload)\r
542 ip->traffic+=traffic;\r
543 else \r
544 if(traffic>ip->traffic)\r
545 ip->traffic=traffic; \r
546 }\r
547 } \r
548 }\r
549\r
550\r
551 free(cmd);\r
552}\r
553 \r
554/* ========== This function executes, logs OR ALSO prints command ========== */\r
555\r
556void safe_run(char *cmd)\r
557{\r
558 if(dry_run) printf("\n=>%s\n",cmd); else system(cmd);\r
559 if(log_file) fprintf(log_file,"%s\n",cmd);\r
560}\r
561\r
562void save_line(char *line)\r
563{\r
564 fprintf(iptables_file,"%s\n",line);\r
565}\r
566\r
567void run_restore(void)\r
568{\r
569 char *restor, *str;\r
570 string(restor,STRLEN);\r
abe9b855 571\r
572 /*-----------------------------------------------------------------*/\r
573 printf("Running %s <%s ...\n",iptablesrestore,iptablesfile);\r
574 /*-----------------------------------------------------------------*/\r
007c44c5 575 \r
576 save_line("COMMIT");\r
577 fclose(iptables_file);\r
ae776b10 578 if(dry_run) \r
579 {\r
007c44c5 580 parse(iptablesfile)\r
581 {\r
582 str=_;\r
583 printf("%s\n", str);\r
584 }done;\r
ae776b10 585 }\r
586\r
587 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
588 safe_run(restor);\r
007c44c5 589 \r
590 free(restor);\r
591}\r
592\r
593/* == This function strips extra characters after IP address and stores it = */\r
594\r
595void parse_ip(char *str)\r
596{\r
597 char *ptr=str,*ipaddr=NULL,*ipname=NULL;;\r
598 \r
599 while(*ptr && *ptr!=' ' && *ptr!=9)\r
600 ptr++;\r
601 \r
602 *ptr=0;\r
603 ipaddr=str;\r
604 ptr++;\r
605 while(*ptr && (*ptr==' ' || *ptr==9))\r
606 ptr++;\r
607 ipname=ptr; \r
608 while(*ptr && *ptr!=' ' && *ptr!=9)\r
609 ptr++;\r
610 *ptr=0;\r
611\r
612 find(ip,ips,eq(ip->addr,ipaddr)); else TheIP();\r
613 ip->addr=ipaddr;\r
614 ip->name=ipname;\r
615}\r
616\r
617char *parse_datafile_line(char *str)\r
618{\r
619 char *ptr=strchr(str,' ');\r
620\r
621 if(ptr)\r
622 {\r
623 *ptr=0;\r
624 ptr++;\r
625 return ptr;\r
626 } \r
627 else \r
628 return NULL;\r
629}\r
630\r
631/*-----------------------------------------------------------------*/\r
632/* Are you looking for int main (int argc, char **argv) ? :-)) */\r
633/*-----------------------------------------------------------------*/\r
634\r
635program\r
636{\r
637 int i=0;\r
638 FILE *f=NULL;\r
639 char *str, *ptr, *d;\r
640 char *substring;\r
641 int class_count=0,ip_count=0;\r
642 int parent=1;\r
643 int just_flush=0;\r
644 int nodelay=0;\r
645 int just_preview=0; /* preview - generate just stats */\r
646 char *chain_forward, *chain_postrouting;\r
647 char *althosts=NULL;\r
648 \r
649 printf("\n\\r
650Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
ab85aff7 651Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\\r
007c44c5 652iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\\r
0d5026c6 653Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
007c44c5 654\r
655 /*----- Boring... we have to check command line options first: ----*/\r
656 \r
657 arguments\r
658 {\r
659 argument("-c") { nextargument(config); }\r
660 argument("-h") { nextargument(althosts);}\r
661 argument("-d") { dry_run=1; }\r
662 argument("-f") { just_flush=1; }\r
663 argument("-9") { just_flush=9; }\r
664 argument("-p") { just_preview=1; }\r
665 argument("-n") { nodelay=1; }\r
666 argument("-?") { help(); exit(0); }\r
667 argument("--help") { help(); exit(0); }\r
668 argument("-v") { exit(0); } \r
669 argument("--version") { exit(0); } \r
670 }\r
671\r
672 if(dry_run)\r
673 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
674\r
675 date(d); /* this is typical cll1.h macro */\r
676\r
677 /*-----------------------------------------------------------------*/\r
678 printf("Parsing configuration file %s ...\n", config);\r
679 /*-----------------------------------------------------------------*/\r
680 get_config(config);\r
681\r
682 if(althosts) hosts=althosts;\r
683\r
684 if(just_flush<9)\r
685 {\r
686 /*-----------------------------------------------------------------*/\r
687 puts("Parsing iptables verbose output ...");\r
688 /*-----------------------------------------------------------------*/\r
689 get_traffic_statistics();\r
690 }\r
691\r
692 /*-----------------------------------------------------------------*/\r
693 printf("Parsing class defintion file %s ...\n", hosts);\r
694 /*-----------------------------------------------------------------*/\r
695 int groupidx = FIRSTGROUPID;\r
696 parse(hosts)\r
697 {\r
698 str=_;\r
699\r
700 if(*str<'0' || *str>'9')\r
701 continue;\r
702 \r
703 //Does this IP share QoS class with some other ?\r
704 substring=strstr(str,"sharing-");\r
705 if(substring)\r
706 { \r
707 substring+=8; //"sharing-"\r
708 parse_ip(str);\r
709 ip_count++;\r
710 ip->sharing=substring;\r
711 ip->keyword=defaultkeyword; /* settings for default keyword */\r
712 while(*substring && *substring!='\n')\r
713 substring++;\r
714 *substring=0; \r
715 }\r
716 else\r
717 {\r
718 //Do we have to create new QoS class for this IP ?\r
719\r
720 find(keyword,keywords,(substring=strstr(str,keyword->key)))\r
721 {\r
722 parse_ip(str);\r
723 ip_count++;\r
724 ip->keyword=keyword;\r
725 keyword->ip_count++;\r
726 ip->prio=keyword->default_prio;\r
727 substring+=strlen(keyword->key)+1;\r
728 ptr=substring;\r
729 while(*ptr && *ptr!='-')\r
730 ptr++;\r
731 if(*ptr=='-')\r
732 {\r
733 *ptr=0;\r
734 ip->max=ip->desired=atoi(ptr+1);\r
735 }\r
736 ip->min=atoi(substring);\r
737 if(ip->min<=0)\r
738 {\r
739 puts("Illegal value of minimum bandwidth: 0 kbps.");\r
740 reject_config_and_exit(hosts);\r
741 }\r
742 if(ip->max<=ip->min)\r
743 {\r
744 ip->fixedprio=1;\r
745 ip->max=ip->min+ip->keyword->reserve_min;\r
746 }\r
747 else \r
748 {\r
749 ip->max-=ip->keyword->reserve_max;\r
750\r
751/*\r
752 if(ip->keyword->divide_max>1)\r
753 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;\r
754 if(ip->keyword->htb_ceil_bonus_divide>0)\r
755 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;\r
756*/\r
757 if(ip->max<ip->min)\r
758 ip->max=ip->min;\r
759 }\r
43e07280 760 ip->mark=FIRSTIPCLASS+1+class_count++;\r
007c44c5 761\r
762 find(group,groups,group->min==ip->min) \r
763 { \r
764 group->count++; \r
765 group->desired+=ip->min;\r
766 ip->group = group->id; \r
767 }\r
768 else\r
769 {\r
770 create(group,Group);\r
771 group->min=ip->min;\r
772 group->id = groupidx++;\r
773 ip->group = group->id;\r
774\r
775 if(group->min<8) group->min=8;\r
776 /* Warning - this is maybe because of primitive tc namespace, can be fixed */\r
777 /* it is because class IDs are derived from min. bandwidth. - xCh */\r
778 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;\r
779 \r
780 group->count=1;\r
781 group->desired=ip->min; \r
782 insert(group,groups,desc_order_by,min);\r
783 }\r
784 }//endif keyword-\r
785 }//endif sharing-\r
786 }\r
787 fail\r
788 {\r
789 perror(hosts);\r
790 exit(-1);\r
791 }\r
792 done;\r
793\r
794 /*-----------------------------------------------------------------*/\r
795 /* cll1.h - let's allocate brand new character buffer... */\r
796 /*-----------------------------------------------------------------*/\r
797 string(str,STRLEN); \r
798\r
799 /*-----------------------------------------------------------------*/\r
800 puts("Resolving shared connections ...");\r
801 /*-----------------------------------------------------------------*/\r
802 search(ip,ips,ip->sharing)\r
803 {\r
804 search(sharedip,ips,eq(sharedip->name,ip->sharing))\r
805 {\r
806 sharedip->traffic+=ip->traffic;\r
807 ip->traffic=0;\r
808 ip->mark=sharedip->mark; \r
809 break;\r
810 }\r
811 if(!sharedip)\r
812 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);\r
813 }\r
814\r
815 if(enable_credit && just_flush<9)\r
816 {\r
817 /*-----------------------------------------------------------------*/\r
818 printf("Parsing credit file %s ...\n", credit);\r
819 /*-----------------------------------------------------------------*/\r
820 parse(credit)\r
821 {\r
822 ptr=parse_datafile_line(_);\r
823 if(ptr)\r
824 {\r
825 find(ip,ips,eq(ip->addr,_))\r
826 sscanf(ptr,"%Lu",&(ip->credit));\r
827 }\r
828 }\r
829 done;\r
830 }\r
831\r
832 if(!just_preview)\r
833 {\r
834 /*-----------------------------------------------------------------*/\r
835 puts("Initializing iptables and tc classes ...");\r
836 /*-----------------------------------------------------------------*/\r
837 \r
838 iptables_file=fopen(iptablesfile,"w");\r
839 if (iptables_file == NULL) {\r
840 puts("Cannot open iptablesfile!");\r
841 exit(-1);\r
842 }\r
843 \r
844 log_file=fopen(cmdlog,"w");\r
845 if (log_file == NULL) {\r
846 puts("Cannot open logfile!");\r
847 exit(-1);\r
848 }\r
849 \r
850 save_line(iptablespreamble);\r
851 run_restore();\r
852 \r
853 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
854 safe_run(str);\r
855\r
856 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
857 safe_run(str);\r
858 \r
859 iptables_file=fopen(iptablesfile,"w");\r
860 save_line(iptablespreamble);\r
861\r
862 if(qos_free_zone && *qos_free_zone!='0')\r
863 {\r
864 char *chain;\r
865 \r
866 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
867 save_line(str);\r
868 \r
869 if(qos_proxy)\r
870 {\r
871 save_line(":post_noproxy - [0:0]");\r
872 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);\r
873 save_line(str); \r
874 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);\r
875 save_line(str); \r
876 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
877 save_line(str); \r
878\r
879 chain="post_noproxy"; \r
880 }\r
881 else\r
882 chain="POSTROUTING";\r
883 \r
884 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
885 save_line(str);\r
886 }\r
887 \r
888 if(ip_count>idxtable_treshold1 && !just_flush)\r
889 {\r
890 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */\r
e0161edb 891 char *subnet, *buf;\r
007c44c5 892 /*-----------------------------------------------------------------*/\r
893 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
894 /*-----------------------------------------------------------------*/\r
895\r
896 save_line(":post_common - [0:0]");\r
897 save_line(":forw_common - [0:0]");\r
898\r
899 search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))\r
900 {\r
901 buf=hash_id(ip->addr,bitmask);\r
902 find(idx,idxs,eq(idx->id,buf))\r
903 idx->children++;\r
904 else\r
905 {\r
906 create(idx,Index);\r
907 idx->addr=ip->addr;\r
908 idx->id=buf;\r
909 idx->bitmask=bitmask;\r
910 idx->parent=NULL;\r
911 idx->children=0;\r
912 idxcount++;\r
913 push(idx,idxs);\r
914 }\r
915 }\r
916\r
917 /* brutal perfomance optimalization */\r
918 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)\r
919 {\r
920 bitmask-=idxtable_bitmask2;\r
921 idxcount=0;\r
922 search(idx,idxs,idx->parent==NULL)\r
923 {\r
924 buf=hash_id(idx->addr,bitmask);\r
925 find(metaindex,idxs,eq(metaindex->id,buf))\r
926 metaindex->children++; \r
927 else\r
928 {\r
929 create(metaindex,Index);\r
930 metaindex->addr=idx->addr;\r
931 metaindex->id=buf;\r
932 metaindex->bitmask=bitmask;\r
933 metaindex->parent=NULL;\r
934 metaindex->children=0;\r
935 idxcount++;\r
936 push(metaindex,idxs);\r
937 }\r
938 idx->parent=metaindex;\r
939 }\r
940 }\r
941\r
942 /* this should slightly optimize throughout ... */\r
943 sort(idx,idxs,desc_order_by,children);\r
944 sort(idx,idxs,order_by,bitmask);\r
945\r
946 i=0;\r
947 every(idx,idxs)\r
948 {\r
949 subnet=subnet_id(idx->addr,idx->bitmask);\r
950 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);\r
951 \r
952 sprintf(str,":post_%s - [0:0]", idx->id);\r
953 save_line(str);\r
954\r
955 sprintf(str,":forw_%s - [0:0]", idx->id);\r
956 save_line(str);\r
957\r
958 if(idx->parent)\r
959 {\r
960 string(buf,strlen(idx->parent->id)+6);\r
961 sprintf(buf,"post_%s",idx->parent->id);\r
962 }\r
963 else\r
964 buf="POSTROUTING";\r
965\r
966 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
967 save_line(str);\r
968\r
969 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
970 save_line(str);\r
971\r
972 if(idx->parent)\r
973 {\r
974 string(buf,strlen(idx->parent->id)+6);\r
975 sprintf(buf,"forw_%s",idx->parent->id);\r
976 }\r
977 else\r
978 buf="FORWARD";\r
979\r
980 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
981 save_line(str);\r
982\r
983 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
984 save_line(str);\r
985 }\r
986 printf("Total indexed iptables chains created: %d\n", i);\r
987\r
988 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
989 save_line(str);\r
990 \r
991 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
992 save_line(str);\r
993 }\r
994 \r
995 }\r
996\r
997 if(just_flush)\r
998 {\r
999 fclose(iptables_file);\r
1000 if (log_file) fclose(log_file);\r
1001 puts("Just flushed iptables and tc classes - now exiting ...");\r
1002 exit(0);\r
1003 }\r
1004\r
1005 if(!just_preview)\r
1006 {\r
1007 if(!dry_run && !nodelay && qos_free_delay)\r
1008 {\r
1009 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
1010 sleep(qos_free_delay);\r
1011 }\r
1012\r
1013 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);\r
1014 safe_run(str);\r
1015\r
1016 sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,lan,lan_medium,lan_medium,burst_main);\r
1017 safe_run(str);\r
1018\r
1019 sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc,lan,line,line,burst_main);\r
1020 safe_run(str);\r
1021\r
1022 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
1023 safe_run(str);\r
1024\r
1025 sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,wan,wan_medium,wan_medium,burst_main);\r
1026 safe_run(str);\r
1027\r
1028 sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc,wan,up,up,burst_main);\r
1029 safe_run(str);\r
1030 }\r
1031\r
1032 /*-----------------------------------------------------------------*/\r
1033 puts("Locating suckers and generating root classes ...");\r
1034 /*-----------------------------------------------------------------*/\r
1035 sort(ip,ips,desc_order_by,traffic);\r
1036 \r
1037\r
1038 /*-----------------------------------------------------------------*/\r
1039 /* sub-scope - local variables */ \r
1040 {\r
1041 long long int rate=line;\r
1042 long long int max=line;\r
1043 int group_count=0;\r
1044 FILE *credit_file=NULL;\r
1045 \r
1046 if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");\r
1047 \r
1048 every(group,groups)\r
1049 {\r
1050 if(!just_preview)\r
1051 {\r
1052 \r
1053 //download\r
1054 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #down desired %d", \r
1055 tc, lan, parent, group->id, rate, max, burst_group, group->desired);\r
1056 safe_run(str);\r
1057 \r
1058 //upload\r
1059 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %Ldkbit ceil %Ldkbit burst %dk prio 1 #up desired %d", \r
1060 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, group->desired);\r
1061 safe_run(str);\r
1062 }\r
1063 \r
1064 if(group_count++<max_nesting) parent=group->id;\r
1065 \r
1066 rate-=digital_divide*group->min;\r
1067 if(rate<group->min)rate=group->min;\r
1068 \r
1069 /*shaping of aggresive downloaders, with credit file support */\r
1070 if(use_credit)\r
1071 {\r
1072 int group_rate=group->min, priority_sequence=magic_priorities+1;\r
1073 \r
1074 search(ip, ips, ip->min==group->min && ip->max>ip->min)\r
1075 {\r
99127c70 1076 if( ip->keyword->data_limit && !ip->fixedprio &&\r
007c44c5 1077 ip->traffic>ip->credit+\r
99127c70 1078 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )\r
007c44c5 1079 {\r
1080 if(group_rate<ip->max) ip->max=group_rate;\r
1081 group_rate+=magic_treshold;\r
1082 ip->prio=magic_priorities+2;\r
1083 if(ip->prio<3) ip->prio=3;\r
1084 }\r
1085 else\r
1086 {\r
abe9b855 1087 if( ip->keyword->data_prio && !ip->fixedprio &&\r
99127c70 1088 ip->traffic>ip->credit+\r
1089 (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )\r
007c44c5 1090 {\r
1091 ip->prio=priority_sequence--;\r
1092 if(ip->prio<2) ip->prio=2;\r
1093 }\r
1094 \r
1095 if(credit_file)\r
1096 {\r
1097 unsigned long long lcredit=0;\r
99127c70 1098 \r
007c44c5 1099 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic) \r
1100 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1101 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1102 }\r
1103 }\r
1104 }\r
1105 \r
1106 }\r
1107 }\r
1108 if(credit_file)fclose(credit_file);\r
1109 }\r
1110\r
1111 if(just_preview)\r
1112 {\r
1113 f=fopen(preview,"w");\r
1114 ptr=preview; \r
1115 }\r
1116 else if(!dry_run && !just_flush)\r
1117 {\r
1118 /*-----------------------------------------------------------------*/\r
1119 printf("Writing data transfer database ...\n");\r
1120 /*-----------------------------------------------------------------*/\r
1121 f=fopen("/var/run/prometheus.previous","w");\r
1122 if(f)\r
1123 {\r
1124 search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)\r
1125 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);\r
1126 fclose(f);\r
1127 }\r
1128\r
1129 f=fopen(html,"w");\r
1130 ptr=html;\r
1131 }\r
1132\r
1133 if(f)\r
1134 {\r
1135 int total=0;\r
1136 int count=1;\r
1137 i=0;\r
1138\r
1139 /*-----------------------------------------------------------------*/\r
1140 printf("Sorting data and generating statistics page %s ...\n",ptr);\r
1141 /*-----------------------------------------------------------------*/\r
1142\r
1143 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
1144 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);\r
1145 fputs("</tr>\n",f);\r
1146 every(group,groups) \r
1147 { \r
1148#ifdef DEBUG\r
1149 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);\r
1150#endif\r
1151 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);\r
1152 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);\r
1153\r
1154 every(keyword,keywords)\r
1155 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit); \r
1156 \r
1157 i+=group->desired; \r
1158 total+=group->count;\r
1159 count++; \r
1160 }\r
1161#ifdef DEBUG\r
1162 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);\r
1163#endif\r
e0161edb 1164 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);\r
007c44c5 1165 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);\r
1166\r
1167 every(keyword,keywords)\r
1168 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count); \r
1169\r
1170 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));\r
1171 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);\r
1172\r
1173 fputs("</table>\n",f);\r
1174 }\r
1175 else if(!dry_run && !just_flush) \r
1176 perror(html);\r
1177\r
1178 i=1;\r
1179 if(f)\r
1180 {\r
1181 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;\r
1182 int active_classes=0;\r
1183 int colspan;\r
1184 FILE *iplog;\r
1185 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;\r
1186\r
1187 if(qos_proxy)\r
1188 colspan=12;\r
1189 else \r
1190 colspan=11;\r
1191 \r
1192 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);\r
1193 fprintf(f," (%s)</th></tr>\n", d);\r
1194 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\\r
1195 <td align=\"right\">credit</td>\\r
1196 <td align=\"right\">limit</td>\\r
1197 <td align=\"right\">total</td>\\r
1198 <td align=\"right\">direct</td>\n",f);\r
1199 if(qos_proxy)\r
1200 fputs("<td align=\"right\">proxy</td>\n",f);\r
1201 fputs("<td align=\"right\">upload</td>\\r
1202 <td align=\"right\">minimum</td>\\r
1203 <td align=\"right\">desired</td>\\r
1204 <td align=\"right\">maximum</td>\\r
1205 <td>prio</td></tr>\n",f); \r
1206\r
1207 every(ip,ips)\r
1208 {\r
1209 char *f1="", *f2="";\r
1210 if(ip->max<ip->desired)\r
1211 {\r
1212 f1="<font color=\"red\">";\r
1213 f2="</font>";\r
1214 }\r
1215 else if(ip->prio>1)\r
1216 {\r
1217 f1="<font color=\"brown\">";\r
1218 f2="</font>";\r
1219 }\r
1220\r
1221#ifdef DEBUG\r
1222 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max); \r
1223#endif\r
1224 fprintf(f,"<tr><td align=\"right\"><a name=\"%s\"></a>%d</td><td><a href=\"%s%s.log\">%s</a></td><td align=\"right\">%Lu M</td>\n",\r
1225 ip->name, i, log_url, ip->name, ip->name, ip->credit);\r
1226 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%Lu M</font></td>",ip->keyword->html_color,ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)));\r
1227 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);\r
1228 if(qos_proxy)\r
1229 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);\r
1230 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);\r
1231 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",ip->min,ip->desired,f1,ip->max,f2,f1,ip->prio,f2);\r
1232 total+=ip->traffic;\r
1233 total_direct+=ip->direct;\r
1234 total_proxy+=ip->proxy;\r
1235 total_upload+=ip->upload;\r
1236 if(ip->traffic>0)\r
1237 {\r
1238 active_classes++;\r
1239 tmp_sum+=ip->traffic;\r
1240 create(sum,Sum);\r
1241 sum->l=tmp_sum;\r
1242 sum->i=active_classes;\r
1243 insert(sum,sums,order_by,i);\r
1244 }\r
1245 \r
1246 i++;\r
1247 \r
1248 if(!just_preview)\r
1249 {\r
1250 sprintf(str,"%s%s.log",log_dir,ip->name);\r
1251 iplog=fopen(str,"a");\r
1252 if(iplog)\r
1253 {\r
1254 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%s",time(NULL),ip->name,ip->traffic, ip->direct, ip->proxy, ip->upload,d);\r
1255 fclose(iplog);\r
1256 }\r
1257 }\r
1258\r
1259 }\r
1260 fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");\r
1261 fprintf(f,"<th align=\"right\">%Lu M</th>\\r
1262 <th align=\"right\">%Lu M</th>\n", total, total_direct);\r
1263 if(qos_proxy)\r
1264 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);\r
1265 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);\r
1266 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);\r
1267\r
1268 if(active_classes>10)\r
ab85aff7 1269 {
1270 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);
1271 fputs("<tr><td>Analytic category</td>\n",f);
1272 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);
1273
1274 find(sum,sums,sum->l>=total/4)
1275 {
1276 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");
1277 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);
1278 }
1279
1280 find(sum,sums,sum->i==10)
1281 {
1282 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");
1283 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);
1284 }
1285
1286 find(sum,sums,sum->l>=total/2)
1287 {
1288 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");
1289 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);
1290 }
1291
1292 find(sum,sums,sum->l>=4*total/5)
1293 {
1294 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");
1295 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);
1296 }
1297
1298 find (sum,sums,sum->i>=(active_classes+1)/5)
1299 {
1300 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");
1301 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);
1302 }
1303
1304 find(sum,sums,sum->i>=(active_classes+1)/4)
1305 {
1306 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");
1307 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);
1308 }
1309
1310 find(sum,sums,sum->i>=(active_classes+1)/2)
1311 {
1312 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");
1313 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);
1314 }
1315
1316 find(sum,sums,sum->i>=4*(active_classes+1)/5)
1317 {
1318 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");
1319 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);
1320 }
1321
1322 fprintf(f,"<tr><td>All users, all traffic</td>\n");
1323 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);
1324 fputs("</table>\n",f);
1325 }
1326 fprintf(f,"<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005-2008 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n",version);\r
007c44c5 1327 fclose(f);\r
1328 }\r
1329\r
1330 if(just_preview)\r
1331 {\r
1332 puts("Statistics preview generated (-p switch) - now exiting ...");\r
1333 exit(0);\r
1334 }\r
1335 \r
1336 /*-----------------------------------------------------------------*/\r
1337 puts("Generating iptables and tc classes ...");\r
1338 /*-----------------------------------------------------------------*/\r
1339\r
1340 i=0;\r
1341 printf("%-22s %-15s mark\n","name","ip");\r
1342 search(ip,ips,ip->mark>0)\r
1343 { \r
1344 \r
1345 if(idxs)\r
1346 {\r
1347 char *buf;\r
1348 duplicate(ip->addr,buf);\r
1349 buf=hash_id(ip->addr,32-idxtable_bitmask1); \r
1350 \r
1351 string(chain_forward,6+strlen(buf));\r
1352 strcpy(chain_forward,"forw_");\r
1353 strcat(chain_forward,buf);\r
1354\r
1355 string(chain_postrouting,6+strlen(buf));\r
1356 strcpy(chain_postrouting,"post_");\r
1357 strcat(chain_postrouting,buf);\r
1358 \r
1359 free(buf);\r
1360 }\r
1361 else\r
1362 {\r
1363 chain_forward="FORWARD";\r
1364 chain_postrouting="POSTROUTING";\r
1365 }\r
1366\r
1367 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark); \r
1368\r
1369 /* -------------------------------------------------------- mark download */\r
1370 \r
1371 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);\r
1372 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/\r
1373 /* -m limit --limit 1/s */ \r
1374 save_line(str);\r
1375\r
1376 if(qos_proxy)\r
1377 {\r
1378 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
1379 /*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
1380 save_line(str);\r
1381 }\r
1382\r
1383 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);\r
1384 save_line(str);\r
1385\r
1386 /* -------------------------------------------------------- mark upload */\r
1387 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);\r
1388 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/\r
1389 save_line(str);\r
1390\r
1391 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);\r
1392 save_line(str);\r
1393\r
1394 if(ip->min)\r
1395 {\r
1396 /* -------------------------------------------------------- download class */\r
1397 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1398\r
1399 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
1400 safe_run(str);\r
1401\r
1402 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1403 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
1404 safe_run(str);\r
1405 }\r
1406 \r
1407 if (filter_type == 1){\r
1408 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
1409 safe_run(str);\r
1410 }\r
1411\r
1412 /* -------------------------------------------------------- upload class */\r
1413 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1414 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1415\r
1416 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1417 tc, wan, ip->group, ip->mark,\r
1418 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1419 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1420 safe_run(str);\r
1421 \r
1422 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1423 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
1424 safe_run(str);\r
1425 }\r
1426 \r
1427 if (filter_type == 1){\r
1428 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
1429 safe_run(str);\r
1430 }\r
1431 }\r
1432 else\r
1433 printf("(sharing %s)\n", ip->sharing);\r
1434 i++;\r
1435 }\r
1436\r
1437\r
1438 if(idxs)\r
1439 {\r
1440 chain_forward="forw_common";\r
1441 chain_postrouting="post_common";\r
1442 }\r
1443 else\r
1444 {\r
1445 chain_forward="FORWARD";\r
1446 chain_postrouting="POSTROUTING";\r
1447 }\r
1448\r
1449 /* -------------------------------------------------------- mark download */\r
1450\r
1451 if(qos_proxy)\r
1452 {\r
1453 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j MARK --set-mark 3",chain_postrouting,proxy_ip,proxy_port,lan);\r
1454 save_line(str);\r
1455 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",chain_postrouting,proxy_ip,proxy_port,lan);\r
1456 save_line(str);\r
1457 }\r
1458 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_postrouting,lan);\r
1459 save_line(str);\r
1460 sprintf(str,"-A %s -o %s -j ACCEPT",chain_postrouting,lan);\r
1461 save_line(str);\r
1462\r
1463 /* -------------------------------------------------------- mark upload */\r
1464 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_forward,wan);\r
1465 save_line(str);\r
1466 sprintf(str,"-A %s -o %s -j ACCEPT",chain_forward,wan);\r
1467 save_line(str);\r
1468\r
1469 printf("Total IP count: %d\n", i);\r
1470\r
abe9b855 1471 /*-----------------------------------------------------------------*/\r
1472 puts("Generating free bandwith classes ...");\r
1473 /*-----------------------------------------------------------------*/\r
1474\r
007c44c5 1475 /* ---------------------------------------- tc - free bandwith shared class */\r
1476 sprintf(str,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc,lan,parent,free_min,free_max,burst);\r
1477 safe_run(str);\r
1478\r
1479 sprintf(str,"%s class add dev %s parent 1:%d classid 1:3 htb rate %dkbit ceil %dkbit burst %dk prio 2",tc,wan,parent,free_min,free_max,burst);\r
1480 safe_run(str);\r
1481\r
1482 /* tc SFQ */\r
1483 if (strcmpi(qos_leaf, "none")){\r
1484 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);\r
1485 safe_run(str);\r
1486 \r
1487 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);\r
1488 safe_run(str);\r
1489 }\r
1490 \r
1491 /* tc handle 1 fw flowid */\r
1492 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);\r
1493 safe_run(str);\r
1494\r
1495 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);\r
1496 safe_run(str);\r
abe9b855 1497\r
007c44c5 1498 run_restore();\r
1499 \r
1500 if (log_file) fclose(log_file);\r
1501 return 0;\r
1502\r
1503 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1504 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1505}\r
This page took 1.311223 seconds and 4 git commands to generate.