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