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