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