license issues
[svn/Prometheus-QoS/.git] / prometheus.c
... / ...
CommitLineData
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
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 */
28\r
29#define STRLEN 256\r
30#define FIRSTGROUPID 1024\r
31#define MAX_GUARANTED_KBPS 2048\r
32#undef DEBUG\r
33\r
34#include "cll1.h"\r
35\r
36const char *version="0.7.7-1"; /*0.7.9 will be last development, 0.8.0 first stable */\r
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
62char *config="/etc/prometheus/prometheus.conf"; /* main configuration file */\r
63char *hosts="/etc/prometheus/hosts"; /* line bandwidth definition file */\r
64char *tc="/sbin/tc"; /* requires tc with HTB support */\r
65char *iptables="/sbin/iptables"; /* requires iptables utility */\r
66char *iptablessave="/sbin/iptables-save"; /* new */\r
67char *iptablesrestore="/sbin/iptables-restore"; /* new */\r
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
77char *log_dir="/var/www/logs/"; /* log directory pathname */\r
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
91long long int line=1024; /* WAN/ISP download in kbps */\r
92long long int up=1024; /* WAN/ISP upload in kbps */\r
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
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
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
176 int prio_limit; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */\r
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
305 keyword->prio_limit=4; /* soft shaping (qos): reduce HTB prio if max*prio_limit MB exceeded */\r
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
337 ioption("magic-relative-prio",keyword->prio_limit);\r
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
352 keyword->prio_limit || keyword->fixed_prio)\r
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
491 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)\r
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
566 \r
567 save_line("COMMIT");\r
568 fclose(iptables_file);\r
569 if(dry_run) {\r
570 parse(iptablesfile)\r
571 {\r
572 str=_;\r
573 printf("%s\n", str);\r
574 }done;\r
575 }else{\r
576 //sprintf(restor,"cat %s",iptablesfile); else \r
577 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
578 system(restor);\r
579 };\r
580 \r
581 free(restor);\r
582}\r
583\r
584/* == This function strips extra characters after IP address and stores it = */\r
585\r
586void parse_ip(char *str)\r
587{\r
588 char *ptr=str,*ipaddr=NULL,*ipname=NULL;;\r
589 \r
590 while(*ptr && *ptr!=' ' && *ptr!=9)\r
591 ptr++;\r
592 \r
593 *ptr=0;\r
594 ipaddr=str;\r
595 ptr++;\r
596 while(*ptr && (*ptr==' ' || *ptr==9))\r
597 ptr++;\r
598 ipname=ptr; \r
599 while(*ptr && *ptr!=' ' && *ptr!=9)\r
600 ptr++;\r
601 *ptr=0;\r
602\r
603 find(ip,ips,eq(ip->addr,ipaddr)); else TheIP();\r
604 ip->addr=ipaddr;\r
605 ip->name=ipname;\r
606}\r
607\r
608char *parse_datafile_line(char *str)\r
609{\r
610 char *ptr=strchr(str,' ');\r
611\r
612 if(ptr)\r
613 {\r
614 *ptr=0;\r
615 ptr++;\r
616 return ptr;\r
617 } \r
618 else \r
619 return NULL;\r
620}\r
621\r
622/*-----------------------------------------------------------------*/\r
623/* Are you looking for int main (int argc, char **argv) ? :-)) */\r
624/*-----------------------------------------------------------------*/\r
625\r
626program\r
627{\r
628 int i=0;\r
629 FILE *f=NULL;\r
630 char *str, *ptr, *d;\r
631 char *substring;\r
632 int class_count=0,ip_count=0;\r
633 int parent=1;\r
634 int just_flush=0;\r
635 int nodelay=0;\r
636 int just_preview=0; /* preview - generate just stats */\r
637 char *chain_forward, *chain_postrouting;\r
638 char *althosts=NULL;\r
639 \r
640 printf("\n\\r
641Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
642Version %s - Copyright (C)2005-2007 Michael Polak (xChaos)\n\\r
643iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\\r
644Credits: CZFree.Net, Martin Devera, Netdave, Aquarius\n\n",version);\r
645\r
646 /*----- Boring... we have to check command line options first: ----*/\r
647 \r
648 arguments\r
649 {\r
650 argument("-c") { nextargument(config); }\r
651 argument("-h") { nextargument(althosts);}\r
652 argument("-d") { dry_run=1; }\r
653 argument("-f") { just_flush=1; }\r
654 argument("-9") { just_flush=9; }\r
655 argument("-p") { just_preview=1; }\r
656 argument("-n") { nodelay=1; }\r
657 argument("-?") { help(); exit(0); }\r
658 argument("--help") { help(); exit(0); }\r
659 argument("-v") { exit(0); } \r
660 argument("--version") { exit(0); } \r
661 }\r
662\r
663 if(dry_run)\r
664 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
665\r
666 date(d); /* this is typical cll1.h macro */\r
667\r
668 /*-----------------------------------------------------------------*/\r
669 printf("Parsing configuration file %s ...\n", config);\r
670 /*-----------------------------------------------------------------*/\r
671 get_config(config);\r
672\r
673 if(althosts) hosts=althosts;\r
674\r
675 if(just_flush<9)\r
676 {\r
677 /*-----------------------------------------------------------------*/\r
678 puts("Parsing iptables verbose output ...");\r
679 /*-----------------------------------------------------------------*/\r
680 get_traffic_statistics();\r
681 }\r
682\r
683 /*-----------------------------------------------------------------*/\r
684 printf("Parsing class defintion file %s ...\n", hosts);\r
685 /*-----------------------------------------------------------------*/\r
686 int groupidx = FIRSTGROUPID;\r
687 parse(hosts)\r
688 {\r
689 str=_;\r
690\r
691 if(*str<'0' || *str>'9')\r
692 continue;\r
693 \r
694 //Does this IP share QoS class with some other ?\r
695 substring=strstr(str,"sharing-");\r
696 if(substring)\r
697 { \r
698 substring+=8; //"sharing-"\r
699 parse_ip(str);\r
700 ip_count++;\r
701 ip->sharing=substring;\r
702 ip->keyword=defaultkeyword; /* settings for default keyword */\r
703 while(*substring && *substring!='\n')\r
704 substring++;\r
705 *substring=0; \r
706 }\r
707 else\r
708 {\r
709 //Do we have to create new QoS class for this IP ?\r
710\r
711 find(keyword,keywords,(substring=strstr(str,keyword->key)))\r
712 {\r
713 parse_ip(str);\r
714 ip_count++;\r
715 ip->keyword=keyword;\r
716 keyword->ip_count++;\r
717 ip->prio=keyword->default_prio;\r
718 substring+=strlen(keyword->key)+1;\r
719 ptr=substring;\r
720 while(*ptr && *ptr!='-')\r
721 ptr++;\r
722 if(*ptr=='-')\r
723 {\r
724 *ptr=0;\r
725 ip->max=ip->desired=atoi(ptr+1);\r
726 }\r
727 ip->min=atoi(substring);\r
728 if(ip->min<=0)\r
729 {\r
730 puts("Illegal value of minimum bandwidth: 0 kbps.");\r
731 reject_config_and_exit(hosts);\r
732 }\r
733 if(ip->max<=ip->min)\r
734 {\r
735 ip->fixedprio=1;\r
736 ip->max=ip->min+ip->keyword->reserve_min;\r
737 }\r
738 else \r
739 {\r
740 ip->max-=ip->keyword->reserve_max;\r
741\r
742/*\r
743 if(ip->keyword->divide_max>1)\r
744 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;\r
745 if(ip->keyword->htb_ceil_bonus_divide>0)\r
746 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;\r
747*/\r
748 if(ip->max<ip->min)\r
749 ip->max=ip->min;\r
750 }\r
751 ip->mark=MAX_GUARANTED_KBPS+1+class_count++;\r
752\r
753 find(group,groups,group->min==ip->min) \r
754 { \r
755 group->count++; \r
756 group->desired+=ip->min;\r
757 ip->group = group->id; \r
758 }\r
759 else\r
760 {\r
761 create(group,Group);\r
762 group->min=ip->min;\r
763 group->id = groupidx++;\r
764 ip->group = group->id;\r
765\r
766 if(group->min<8) group->min=8;\r
767 /* Warning - this is maybe because of primitive tc namespace, can be fixed */\r
768 /* it is because class IDs are derived from min. bandwidth. - xCh */\r
769 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;\r
770 \r
771 group->count=1;\r
772 group->desired=ip->min; \r
773 insert(group,groups,desc_order_by,min);\r
774 }\r
775 }//endif keyword-\r
776 }//endif sharing-\r
777 }\r
778 fail\r
779 {\r
780 perror(hosts);\r
781 exit(-1);\r
782 }\r
783 done;\r
784\r
785 /*-----------------------------------------------------------------*/\r
786 /* cll1.h - let's allocate brand new character buffer... */\r
787 /*-----------------------------------------------------------------*/\r
788 string(str,STRLEN); \r
789\r
790 /*-----------------------------------------------------------------*/\r
791 puts("Resolving shared connections ...");\r
792 /*-----------------------------------------------------------------*/\r
793 search(ip,ips,ip->sharing)\r
794 {\r
795 search(sharedip,ips,eq(sharedip->name,ip->sharing))\r
796 {\r
797 sharedip->traffic+=ip->traffic;\r
798 ip->traffic=0;\r
799 ip->mark=sharedip->mark; \r
800 break;\r
801 }\r
802 if(!sharedip)\r
803 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);\r
804 }\r
805\r
806 if(enable_credit && just_flush<9)\r
807 {\r
808 /*-----------------------------------------------------------------*/\r
809 printf("Parsing credit file %s ...\n", credit);\r
810 /*-----------------------------------------------------------------*/\r
811 parse(credit)\r
812 {\r
813 ptr=parse_datafile_line(_);\r
814 if(ptr)\r
815 {\r
816 find(ip,ips,eq(ip->addr,_))\r
817 sscanf(ptr,"%Lu",&(ip->credit));\r
818 }\r
819 }\r
820 done;\r
821 }\r
822\r
823 if(!just_preview)\r
824 {\r
825 /*-----------------------------------------------------------------*/\r
826 puts("Initializing iptables and tc classes ...");\r
827 /*-----------------------------------------------------------------*/\r
828 \r
829 iptables_file=fopen(iptablesfile,"w");\r
830 if (iptables_file == NULL) {\r
831 puts("Cannot open iptablesfile!");\r
832 exit(-1);\r
833 }\r
834 \r
835 log_file=fopen(cmdlog,"w");\r
836 if (log_file == NULL) {\r
837 puts("Cannot open logfile!");\r
838 exit(-1);\r
839 }\r
840 \r
841 save_line(iptablespreamble);\r
842 run_restore();\r
843 \r
844 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
845 safe_run(str);\r
846\r
847 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
848 safe_run(str);\r
849 \r
850 iptables_file=fopen(iptablesfile,"w");\r
851 save_line(iptablespreamble);\r
852\r
853 if(qos_free_zone && *qos_free_zone!='0')\r
854 {\r
855 char *chain;\r
856 \r
857 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
858 save_line(str);\r
859 \r
860 if(qos_proxy)\r
861 {\r
862 save_line(":post_noproxy - [0:0]");\r
863 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);\r
864 save_line(str); \r
865 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);\r
866 save_line(str); \r
867 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
868 save_line(str); \r
869\r
870 chain="post_noproxy"; \r
871 }\r
872 else\r
873 chain="POSTROUTING";\r
874 \r
875 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
876 save_line(str);\r
877 }\r
878 \r
879 if(ip_count>idxtable_treshold1 && !just_flush)\r
880 {\r
881 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */\r
882 char *subnet, *buf;\r
883 /*-----------------------------------------------------------------*/\r
884 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
885 /*-----------------------------------------------------------------*/\r
886\r
887 save_line(":post_common - [0:0]");\r
888 save_line(":forw_common - [0:0]");\r
889\r
890 search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))\r
891 {\r
892 buf=hash_id(ip->addr,bitmask);\r
893 find(idx,idxs,eq(idx->id,buf))\r
894 idx->children++;\r
895 else\r
896 {\r
897 create(idx,Index);\r
898 idx->addr=ip->addr;\r
899 idx->id=buf;\r
900 idx->bitmask=bitmask;\r
901 idx->parent=NULL;\r
902 idx->children=0;\r
903 idxcount++;\r
904 push(idx,idxs);\r
905 }\r
906 }\r
907\r
908 /* brutal perfomance optimalization */\r
909 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)\r
910 {\r
911 bitmask-=idxtable_bitmask2;\r
912 idxcount=0;\r
913 search(idx,idxs,idx->parent==NULL)\r
914 {\r
915 buf=hash_id(idx->addr,bitmask);\r
916 find(metaindex,idxs,eq(metaindex->id,buf))\r
917 metaindex->children++; \r
918 else\r
919 {\r
920 create(metaindex,Index);\r
921 metaindex->addr=idx->addr;\r
922 metaindex->id=buf;\r
923 metaindex->bitmask=bitmask;\r
924 metaindex->parent=NULL;\r
925 metaindex->children=0;\r
926 idxcount++;\r
927 push(metaindex,idxs);\r
928 }\r
929 idx->parent=metaindex;\r
930 }\r
931 }\r
932\r
933 /* this should slightly optimize throughout ... */\r
934 sort(idx,idxs,desc_order_by,children);\r
935 sort(idx,idxs,order_by,bitmask);\r
936\r
937 i=0;\r
938 every(idx,idxs)\r
939 {\r
940 subnet=subnet_id(idx->addr,idx->bitmask);\r
941 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);\r
942 \r
943 sprintf(str,":post_%s - [0:0]", idx->id);\r
944 save_line(str);\r
945\r
946 sprintf(str,":forw_%s - [0:0]", idx->id);\r
947 save_line(str);\r
948\r
949 if(idx->parent)\r
950 {\r
951 string(buf,strlen(idx->parent->id)+6);\r
952 sprintf(buf,"post_%s",idx->parent->id);\r
953 }\r
954 else\r
955 buf="POSTROUTING";\r
956\r
957 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
958 save_line(str);\r
959\r
960 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
961 save_line(str);\r
962\r
963 if(idx->parent)\r
964 {\r
965 string(buf,strlen(idx->parent->id)+6);\r
966 sprintf(buf,"forw_%s",idx->parent->id);\r
967 }\r
968 else\r
969 buf="FORWARD";\r
970\r
971 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
972 save_line(str);\r
973\r
974 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
975 save_line(str);\r
976 }\r
977 printf("Total indexed iptables chains created: %d\n", i);\r
978\r
979 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
980 save_line(str);\r
981 \r
982 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
983 save_line(str);\r
984 }\r
985 \r
986 }\r
987\r
988 if(just_flush)\r
989 {\r
990 fclose(iptables_file);\r
991 if (log_file) fclose(log_file);\r
992 puts("Just flushed iptables and tc classes - now exiting ...");\r
993 exit(0);\r
994 }\r
995\r
996 if(!just_preview)\r
997 {\r
998 if(!dry_run && !nodelay && qos_free_delay)\r
999 {\r
1000 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
1001 sleep(qos_free_delay);\r
1002 }\r
1003\r
1004 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);\r
1005 safe_run(str);\r
1006\r
1007 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
1008 safe_run(str);\r
1009\r
1010 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
1011 safe_run(str);\r
1012\r
1013 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
1014 safe_run(str);\r
1015\r
1016 sprintf(str,"%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio 0",tc,wan,wan_medium,wan_medium,burst_main);\r
1017 safe_run(str);\r
1018\r
1019 sprintf(str,"%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio 0",tc,wan,up,up,burst_main);\r
1020 safe_run(str);\r
1021 }\r
1022\r
1023 /*-----------------------------------------------------------------*/\r
1024 puts("Locating suckers and generating root classes ...");\r
1025 /*-----------------------------------------------------------------*/\r
1026 sort(ip,ips,desc_order_by,traffic);\r
1027 \r
1028\r
1029 /*-----------------------------------------------------------------*/\r
1030 /* sub-scope - local variables */ \r
1031 {\r
1032 long long int rate=line;\r
1033 long long int max=line;\r
1034 int group_count=0;\r
1035 FILE *credit_file=NULL;\r
1036 \r
1037 if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");\r
1038 \r
1039 every(group,groups)\r
1040 {\r
1041 if(!just_preview)\r
1042 {\r
1043 \r
1044 //download\r
1045 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
1046 tc, lan, parent, group->id, rate, max, burst_group, group->desired);\r
1047 safe_run(str);\r
1048 \r
1049 //upload\r
1050 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
1051 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, group->desired);\r
1052 safe_run(str);\r
1053 }\r
1054 \r
1055 if(group_count++<max_nesting) parent=group->id;\r
1056 \r
1057 rate-=digital_divide*group->min;\r
1058 if(rate<group->min)rate=group->min;\r
1059 \r
1060 /*shaping of aggresive downloaders, with credit file support */\r
1061 if(use_credit)\r
1062 {\r
1063 int group_rate=group->min, priority_sequence=magic_priorities+1;\r
1064 \r
1065 search(ip, ips, ip->min==group->min && ip->max>ip->min)\r
1066 {\r
1067 if(ip->keyword->data_limit>0 &&\r
1068 ip->traffic>ip->credit+\r
1069 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) \r
1070 && !ip->fixedprio)\r
1071 {\r
1072 if(group_rate<ip->max) ip->max=group_rate;\r
1073 group_rate+=magic_treshold;\r
1074 ip->prio=magic_priorities+2;\r
1075 if(ip->prio<3) ip->prio=3;\r
1076 }\r
1077 else\r
1078 {\r
1079 if(ip->traffic>ip->credit+\r
1080 (ip->min*ip->keyword->prio_limit+(ip->keyword->fixed_prio<<20)) && \r
1081 !ip->fixedprio)\r
1082 {\r
1083 ip->prio=priority_sequence--;\r
1084 if(ip->prio<2) ip->prio=2;\r
1085 }\r
1086 \r
1087 if(credit_file)\r
1088 {\r
1089 unsigned long long lcredit=0;\r
1090 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic) \r
1091 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1092 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1093 }\r
1094 }\r
1095 }\r
1096 \r
1097 }\r
1098 }\r
1099 if(credit_file)fclose(credit_file);\r
1100 }\r
1101\r
1102 if(just_preview)\r
1103 {\r
1104 f=fopen(preview,"w");\r
1105 ptr=preview; \r
1106 }\r
1107 else if(!dry_run && !just_flush)\r
1108 {\r
1109 /*-----------------------------------------------------------------*/\r
1110 printf("Writing data transfer database ...\n");\r
1111 /*-----------------------------------------------------------------*/\r
1112 f=fopen("/var/run/prometheus.previous","w");\r
1113 if(f)\r
1114 {\r
1115 search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)\r
1116 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);\r
1117 fclose(f);\r
1118 }\r
1119\r
1120 f=fopen(html,"w");\r
1121 ptr=html;\r
1122 }\r
1123\r
1124 if(f)\r
1125 {\r
1126 int total=0;\r
1127 int count=1;\r
1128 i=0;\r
1129\r
1130 /*-----------------------------------------------------------------*/\r
1131 printf("Sorting data and generating statistics page %s ...\n",ptr);\r
1132 /*-----------------------------------------------------------------*/\r
1133\r
1134 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
1135 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);\r
1136 fputs("</tr>\n",f);\r
1137 every(group,groups) \r
1138 { \r
1139#ifdef DEBUG\r
1140 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);\r
1141#endif\r
1142 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);\r
1143 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);\r
1144\r
1145 every(keyword,keywords)\r
1146 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit); \r
1147 \r
1148 i+=group->desired; \r
1149 total+=group->count;\r
1150 count++; \r
1151 }\r
1152#ifdef DEBUG\r
1153 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);\r
1154#endif\r
1155 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);\r
1156 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);\r
1157\r
1158 every(keyword,keywords)\r
1159 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count); \r
1160\r
1161 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));\r
1162 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);\r
1163\r
1164 fputs("</table>\n",f);\r
1165 }\r
1166 else if(!dry_run && !just_flush) \r
1167 perror(html);\r
1168\r
1169 i=1;\r
1170 if(f)\r
1171 {\r
1172 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;\r
1173 int active_classes=0;\r
1174 int colspan;\r
1175 FILE *iplog;\r
1176 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;\r
1177\r
1178 if(qos_proxy)\r
1179 colspan=12;\r
1180 else \r
1181 colspan=11;\r
1182 \r
1183 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);\r
1184 fprintf(f," (%s)</th></tr>\n", d);\r
1185 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\\r
1186 <td align=\"right\">credit</td>\\r
1187 <td align=\"right\">limit</td>\\r
1188 <td align=\"right\">total</td>\\r
1189 <td align=\"right\">direct</td>\n",f);\r
1190 if(qos_proxy)\r
1191 fputs("<td align=\"right\">proxy</td>\n",f);\r
1192 fputs("<td align=\"right\">upload</td>\\r
1193 <td align=\"right\">minimum</td>\\r
1194 <td align=\"right\">desired</td>\\r
1195 <td align=\"right\">maximum</td>\\r
1196 <td>prio</td></tr>\n",f); \r
1197\r
1198 every(ip,ips)\r
1199 {\r
1200 char *f1="", *f2="";\r
1201 if(ip->max<ip->desired)\r
1202 {\r
1203 f1="<font color=\"red\">";\r
1204 f2="</font>";\r
1205 }\r
1206 else if(ip->prio>1)\r
1207 {\r
1208 f1="<font color=\"brown\">";\r
1209 f2="</font>";\r
1210 }\r
1211\r
1212#ifdef DEBUG\r
1213 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max); \r
1214#endif\r
1215 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
1216 ip->name, i, log_url, ip->name, ip->name, ip->credit);\r
1217 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
1218 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);\r
1219 if(qos_proxy)\r
1220 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);\r
1221 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);\r
1222 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
1223 total+=ip->traffic;\r
1224 total_direct+=ip->direct;\r
1225 total_proxy+=ip->proxy;\r
1226 total_upload+=ip->upload;\r
1227 if(ip->traffic>0)\r
1228 {\r
1229 active_classes++;\r
1230 tmp_sum+=ip->traffic;\r
1231 create(sum,Sum);\r
1232 sum->l=tmp_sum;\r
1233 sum->i=active_classes;\r
1234 insert(sum,sums,order_by,i);\r
1235 }\r
1236 \r
1237 i++;\r
1238 \r
1239 if(!just_preview)\r
1240 {\r
1241 sprintf(str,"%s%s.log",log_dir,ip->name);\r
1242 iplog=fopen(str,"a");\r
1243 if(iplog)\r
1244 {\r
1245 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
1246 fclose(iplog);\r
1247 }\r
1248 }\r
1249\r
1250 }\r
1251 fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");\r
1252 fprintf(f,"<th align=\"right\">%Lu M</th>\\r
1253 <th align=\"right\">%Lu M</th>\n", total, total_direct);\r
1254 if(qos_proxy)\r
1255 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);\r
1256 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);\r
1257 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);\r
1258\r
1259 if(active_classes>10)\r
1260 {\r
1261 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"4\">Enterprise Research and Planning (ERP)</th></tr>\n",f);\r
1262 fputs("<tr><td colspan=\"2\">Active Classes</td><td colspan=\"2\">Data transfers</td></tr>\n",f);\r
1263 find (sum,sums,sum->l>=total/4)\r
1264 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
1265 find (sum,sums,sum->i==10)\r
1266 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
1267 find (sum,sums,sum->l>=total/2)\r
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
1269 find (sum,sums,sum->i>=(active_classes+3)/4)\r
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
1271 find (sum,sums,sum->i>=(active_classes+1)/2)\r
1272 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
1273 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
1274 fputs("</table>\n",f);\r
1275 }\r
1276 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
1277 fclose(f);\r
1278 }\r
1279\r
1280 if(just_preview)\r
1281 {\r
1282 puts("Statistics preview generated (-p switch) - now exiting ...");\r
1283 exit(0);\r
1284 }\r
1285 \r
1286 /*-----------------------------------------------------------------*/\r
1287 puts("Generating iptables and tc classes ...");\r
1288 /*-----------------------------------------------------------------*/\r
1289\r
1290 i=0;\r
1291 printf("%-22s %-15s mark\n","name","ip");\r
1292 search(ip,ips,ip->mark>0)\r
1293 { \r
1294 \r
1295 if(idxs)\r
1296 {\r
1297 char *buf;\r
1298 duplicate(ip->addr,buf);\r
1299 buf=hash_id(ip->addr,32-idxtable_bitmask1); \r
1300 \r
1301 string(chain_forward,6+strlen(buf));\r
1302 strcpy(chain_forward,"forw_");\r
1303 strcat(chain_forward,buf);\r
1304\r
1305 string(chain_postrouting,6+strlen(buf));\r
1306 strcpy(chain_postrouting,"post_");\r
1307 strcat(chain_postrouting,buf);\r
1308 \r
1309 free(buf);\r
1310 }\r
1311 else\r
1312 {\r
1313 chain_forward="FORWARD";\r
1314 chain_postrouting="POSTROUTING";\r
1315 }\r
1316\r
1317 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark); \r
1318\r
1319 /* -------------------------------------------------------- mark download */\r
1320 \r
1321 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);\r
1322 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/\r
1323 /* -m limit --limit 1/s */ \r
1324 save_line(str);\r
1325\r
1326 if(qos_proxy)\r
1327 {\r
1328 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
1329 /*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
1330 save_line(str);\r
1331 }\r
1332\r
1333 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);\r
1334 save_line(str);\r
1335\r
1336 /* -------------------------------------------------------- mark upload */\r
1337 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);\r
1338 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/\r
1339 save_line(str);\r
1340\r
1341 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);\r
1342 save_line(str);\r
1343\r
1344 if(ip->min)\r
1345 {\r
1346 /* -------------------------------------------------------- download class */\r
1347 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1348\r
1349 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
1350 safe_run(str);\r
1351\r
1352 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1353 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
1354 safe_run(str);\r
1355 }\r
1356 \r
1357 if (filter_type == 1){\r
1358 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
1359 safe_run(str);\r
1360 }\r
1361\r
1362 /* -------------------------------------------------------- upload class */\r
1363 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1364 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1365\r
1366 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1367 tc, wan, ip->group, ip->mark,\r
1368 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1369 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1370 safe_run(str);\r
1371 \r
1372 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1373 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
1374 safe_run(str);\r
1375 }\r
1376 \r
1377 if (filter_type == 1){\r
1378 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
1379 safe_run(str);\r
1380 }\r
1381 }\r
1382 else\r
1383 printf("(sharing %s)\n", ip->sharing);\r
1384 i++;\r
1385 }\r
1386\r
1387\r
1388 if(idxs)\r
1389 {\r
1390 chain_forward="forw_common";\r
1391 chain_postrouting="post_common";\r
1392 }\r
1393 else\r
1394 {\r
1395 chain_forward="FORWARD";\r
1396 chain_postrouting="POSTROUTING";\r
1397 }\r
1398\r
1399 /* -------------------------------------------------------- mark download */\r
1400\r
1401 if(qos_proxy)\r
1402 {\r
1403 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
1404 save_line(str);\r
1405 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",chain_postrouting,proxy_ip,proxy_port,lan);\r
1406 save_line(str);\r
1407 }\r
1408 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_postrouting,lan);\r
1409 save_line(str);\r
1410 sprintf(str,"-A %s -o %s -j ACCEPT",chain_postrouting,lan);\r
1411 save_line(str);\r
1412\r
1413 /* -------------------------------------------------------- mark upload */\r
1414 sprintf(str,"-A %s -o %s -j MARK --set-mark 3",chain_forward,wan);\r
1415 save_line(str);\r
1416 sprintf(str,"-A %s -o %s -j ACCEPT",chain_forward,wan);\r
1417 save_line(str);\r
1418\r
1419 printf("Total IP count: %d\n", i);\r
1420\r
1421 /* ---------------------------------------- tc - free bandwith shared class */\r
1422 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
1423 safe_run(str);\r
1424\r
1425 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
1426 safe_run(str);\r
1427\r
1428 /* tc SFQ */\r
1429 if (strcmpi(qos_leaf, "none")){\r
1430 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);\r
1431 safe_run(str);\r
1432 \r
1433 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);\r
1434 safe_run(str);\r
1435 }\r
1436 \r
1437 /* tc handle 1 fw flowid */\r
1438 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);\r
1439 safe_run(str);\r
1440\r
1441 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);\r
1442 safe_run(str);\r
1443 \r
1444 run_restore();\r
1445 \r
1446 if (log_file) fclose(log_file);\r
1447 return 0;\r
1448\r
1449 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1450 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1451}\r
This page took 0.266429 seconds and 4 git commands to generate.