commit test
[svn/Prometheus-QoS/.git] / prometheus.c
CommitLineData
312ac2c1 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
33ec95ab 10/* Modified: xChaos, 20080422\r
11 ludva, 20080415\r
007c44c5 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
c9012978 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
d1ae4fa7 25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \r
26 \r
c9012978 27 GNU General Public License is located in file COPYING */\r
007c44c5 28\r
29#define STRLEN 256\r
30#define FIRSTGROUPID 1024\r
43e07280 31#define FIRSTIPCLASS 2048\r
007c44c5 32#undef DEBUG\r
33\r
211415b9 34#include "cll1-0.6.h"\r
007c44c5 35\r
33ec95ab 36const char *version="0.7.9.2"; /*0.7.9 will be last development, 0.8.0 first stable */\r
007c44c5 37\r
82c702a1 38/* ======= All path names are defined here (for RPM patch) ======= */\r
ae776b10 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
5b902402 44char *ls = "/bin/ls"; /* this is not user configurable :-) */\r
ae776b10 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
5b902402 56char *html_log_dir = "/var/www/logs/html/";\r
ae776b10 57\r
007c44c5 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
5b902402 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
007c44c5 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
007c44c5 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
007c44c5 90int enable_credit=1; /* enable credit file */\r
91int use_credit=0; /* use credit file (if enabled)*/\r
007c44c5 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
0d5026c6 104long long int line=1024; /* WAN/ISP download in kbps */\r
105long long int up=1024; /* WAN/ISP upload in kbps */\r
007c44c5 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
0d5026c6 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
007c44c5 131\r
007c44c5 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
99127c70 183 int data_prio; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
007c44c5 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
5b902402 215/* ====== iptables indexes are used to reduce complexity to log8(N) ===== */\r
007c44c5 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
99127c70 312 keyword->data_prio=4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
007c44c5 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
99127c70 344 ioption("magic-relative-prio",keyword->data_prio);\r
007c44c5 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
99127c70 359 keyword->data_prio || keyword->fixed_prio)\r
5b902402 360 use_credit=1; \r
007c44c5 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
5b902402 384 option("log-traffic-html-directory",html_log_dir);\r
007c44c5 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
5b902402 401 ioption("magic-treshold",magic_treshold); \r
007c44c5 402 option("filter-type", cnf);\r
403 \r
404/* not yet implemented:\r
405 ioption("magic-fixed-packets",fixed_packets);\r
406 ioption("magic-relative-packets",packet_limit);\r
407*/\r
408 }\r
409 fail\r
410 { \r
411 perror(config_filename);\r
412 puts("Warning - using built-in defaults instead ...");\r
413 }\r
414 done;\r
415 printf("\n");\r
416 \r
417 /*leaf discipline for keywords*/\r
418 every(keyword,keywords)\r
419 {\r
420 if (!strcmpi(keyword->leaf_discipline, "")){\r
421 keyword->leaf_discipline = qos_leaf;\r
422 }\r
423 }\r
424\r
425 if (strcmpi(cnf, "mark")){\r
426 filter_type = 2;\r
427 mark = "CLASSIFY";\r
428 mark_iptables = "CLASSIFY --set-class 1:";\r
429 }else{\r
430 filter_type = 1;\r
431 mark = "MARK";\r
432 mark_iptables = "MARK --set-mark ";\r
433 }\r
434\r
435 /* are supplied values meaningful ?*/\r
436 if(line<=0 || up<=0)\r
437 {\r
438 puts("Illegal value of wan bandwidth: 0 kbps.");\r
439 reject_config_and_exit(config_filename);\r
440 }\r
441}\r
442\r
443/* ===================== traffic analyser - uses iptables ================ */ \r
444\r
445void get_traffic_statistics(void)\r
446{\r
447 char *str,*cmd;\r
448 int downloadflag=0;\r
449\r
450 textfile(Pipe,str) *line,*lines=NULL;\r
451 string(str,STRLEN);\r
452 string(cmd,STRLEN);\r
453\r
454 sprintf(cmd,"%s -L -v -x -n -t mangle",iptables);\r
455 shell(cmd);\r
456 input(str,STRLEN)\r
457 {\r
458 create(line,Pipe);\r
459 line->str=str;\r
460 string(str,STRLEN);\r
461 append(line,lines);\r
462 }\r
463\r
464 every(line,lines)\r
465 {\r
466 int col, accept=0,proxyflag=0,valid=1,setchainname=0,commonflag=0; \r
467 unsigned long long traffic=0;\r
468 unsigned long pkts=0;\r
469 char *ipaddr=NULL,*ptr;\r
470 \r
471 /* debug puts(line->str); */\r
472 valid_columns(ptr,line->str,' ',col) \r
473 if(valid) switch(col)\r
474 { \r
475 case 1: if(eq(ptr,"Chain"))\r
476 setchainname=1;\r
477 else if(eq(ptr,"pkts")) \r
478 valid=0;\r
479 else\r
480 sscanf(ptr,"%lu",&pkts); \r
481 break;\r
482 case 2: if(setchainname)\r
483 {\r
484 if(!strncmp(ptr,"post_",5) || eq(ptr,"POSTROUTING"))\r
485 downloadflag=1; \r
486 else \r
487 if(!strncmp(ptr,"forw_",5) || eq(ptr,"FORWARD"))\r
488 downloadflag=0;\r
489 \r
490 if(eq(ptr,"post_common") || eq(ptr,"forw_common"))\r
491 commonflag=1;\r
492 }\r
493 else\r
494 sscanf(ptr,"%Lu",&traffic); traffic+=(1<<19); traffic>>=20;\r
495 break;\r
0045483c 496 case 3: if((strncmp(ptr,"post_",5) && strncmp(ptr,"forw_",5)) || commonflag)\r
007c44c5 497 accept=eq(ptr,mark);\r
498 /*if (filter_type==1) accept=eq(ptr,"MARK"); else accept=eq(ptr,"CLASSIFY");*/\r
499 break;\r
500 case 8: if(downloadflag)\r
501 { \r
502 if(strstr(proxy_ip,ptr))proxyflag=1; \r
503 }\r
504 else\r
505 ipaddr=ptr; \r
506 break;\r
507 case 9: if(downloadflag)ipaddr=ptr;break;\r
508 }\r
509 \r
510 if(accept && traffic>0 && ipaddr)\r
511 {\r
512 if(proxyflag)printf("(proxy) ");\r
513 else if(!downloadflag) printf("(upload) ");\r
514 printf("IP %s: %Lu M (%ld pkts)\n", ipaddr, traffic, pkts);\r
515 find(ip,ips,eq(ip->addr,ipaddr)); \r
516 else \r
517 {\r
518 TheIP();\r
519 ip->addr=ipaddr;\r
520 if(eq(ip->addr,"0.0.0.0/0"))\r
521 {\r
522 ip->name="(unregistered)";\r
523 ip->min=free_min;\r
524 ip->max=ip->desired=free_max;\r
525 }\r
526 }\r
527 \r
528 if(downloadflag)\r
529 {\r
530 if(proxyflag)\r
531 ip->proxy=traffic;\r
532 else\r
533 ip->traffic+=traffic;\r
534 ip->direct=ip->traffic-ip->upload-ip->proxy;\r
535 ip->pktsdown=pkts;\r
536 }\r
537 else\r
538 {\r
539 ip->upload=traffic;\r
540 ip->pktsup=pkts;\r
541 if(include_upload)\r
542 ip->traffic+=traffic;\r
543 else \r
544 if(traffic>ip->traffic)\r
545 ip->traffic=traffic; \r
546 }\r
547 } \r
548 }\r
549\r
550\r
551 free(cmd);\r
552}\r
553 \r
554/* ========== This function executes, logs OR ALSO prints command ========== */\r
555\r
556void safe_run(char *cmd)\r
557{\r
558 if(dry_run) printf("\n=>%s\n",cmd); else system(cmd);\r
559 if(log_file) fprintf(log_file,"%s\n",cmd);\r
560}\r
561\r
562void save_line(char *line)\r
563{\r
564 fprintf(iptables_file,"%s\n",line);\r
565}\r
566\r
567void run_restore(void)\r
568{\r
569 char *restor, *str;\r
570 string(restor,STRLEN);\r
abe9b855 571\r
572 /*-----------------------------------------------------------------*/\r
573 printf("Running %s <%s ...\n",iptablesrestore,iptablesfile);\r
574 /*-----------------------------------------------------------------*/\r
007c44c5 575 \r
576 save_line("COMMIT");\r
577 fclose(iptables_file);\r
ae776b10 578 if(dry_run) \r
579 {\r
007c44c5 580 parse(iptablesfile)\r
581 {\r
582 str=_;\r
583 printf("%s\n", str);\r
584 }done;\r
ae776b10 585 }\r
586\r
587 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
588 safe_run(restor);\r
007c44c5 589 \r
590 free(restor);\r
591}\r
592\r
593/* == This function strips extra characters after IP address and stores it = */\r
594\r
595void parse_ip(char *str)\r
596{\r
597 char *ptr=str,*ipaddr=NULL,*ipname=NULL;;\r
598 \r
599 while(*ptr && *ptr!=' ' && *ptr!=9)\r
600 ptr++;\r
601 \r
602 *ptr=0;\r
603 ipaddr=str;\r
604 ptr++;\r
605 while(*ptr && (*ptr==' ' || *ptr==9))\r
606 ptr++;\r
607 ipname=ptr; \r
608 while(*ptr && *ptr!=' ' && *ptr!=9)\r
609 ptr++;\r
610 *ptr=0;\r
611\r
612 find(ip,ips,eq(ip->addr,ipaddr)); else TheIP();\r
613 ip->addr=ipaddr;\r
614 ip->name=ipname;\r
615}\r
616\r
617char *parse_datafile_line(char *str)\r
618{\r
619 char *ptr=strchr(str,' ');\r
620\r
621 if(ptr)\r
622 {\r
623 *ptr=0;\r
624 ptr++;\r
625 return ptr;\r
626 } \r
627 else \r
628 return NULL;\r
629}\r
630\r
c9012978 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
5b902402 642 int col,col2,y_ok,m_ok,accept_month,i=1,any_month=0;\r
c9012978 643 char mstr[4],ystr[5];\r
644 FILE *f;\r
645 \r
646 string(str,STRLEN);\r
647\r
5b902402 648 if(argv[1][1]=='l') /* -l */\r
649 {\r
c9012978 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
5b902402 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
c9012978 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
5b902402 742\r
743\r
007c44c5 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
33ec95ab 758 int just_preview=0; /* preview - generate just stats */\r
759 int just_logs=0; /* just parse logs */\r
760 \r
007c44c5 761 char *chain_forward, *chain_postrouting;\r
762 char *althosts=NULL;\r
763 \r
764 printf("\n\\r
765Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
ab85aff7 766Version %s - Copyright (C)2005-2008 Michael Polak (xChaos)\n\\r
007c44c5 767iptables-restore & burst tunning & classify modification 0.7d by Ludva\n\\r
0d5026c6 768Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
007c44c5 769\r
770 /*----- Boring... we have to check command line options first: ----*/\r
771 \r
772 arguments\r
773 {\r
774 argument("-c") { nextargument(config); }\r
775 argument("-h") { nextargument(althosts);}\r
776 argument("-d") { dry_run=1; }\r
777 argument("-f") { just_flush=1; }\r
778 argument("-9") { just_flush=9; }\r
779 argument("-p") { just_preview=1; }\r
780 argument("-n") { nodelay=1; }\r
33ec95ab 781 argument("-l") { just_logs=1; }\r
782 argument("-m") { just_logs=1; }\r
783 argument("-y") { just_logs=1; }\r
007c44c5 784 argument("-?") { help(); exit(0); }\r
785 argument("--help") { help(); exit(0); }\r
786 argument("-v") { exit(0); } \r
787 argument("--version") { exit(0); } \r
788 }\r
789\r
790 if(dry_run)\r
791 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
792\r
793 date(d); /* this is typical cll1.h macro */\r
794\r
795 /*-----------------------------------------------------------------*/\r
796 printf("Parsing configuration file %s ...\n", config);\r
797 /*-----------------------------------------------------------------*/\r
798 get_config(config);\r
c9012978 799 \r
33ec95ab 800 if(just_logs)\r
c9012978 801 {\r
33ec95ab 802 parse_ip_log(argc,argv);\r
803 exit(0);\r
c9012978 804 }\r
007c44c5 805\r
806 if(althosts) hosts=althosts;\r
807\r
808 if(just_flush<9)\r
809 {\r
810 /*-----------------------------------------------------------------*/\r
811 puts("Parsing iptables verbose output ...");\r
812 /*-----------------------------------------------------------------*/\r
813 get_traffic_statistics();\r
814 }\r
815\r
816 /*-----------------------------------------------------------------*/\r
817 printf("Parsing class defintion file %s ...\n", hosts);\r
818 /*-----------------------------------------------------------------*/\r
819 int groupidx = FIRSTGROUPID;\r
820 parse(hosts)\r
821 {\r
822 str=_;\r
823\r
824 if(*str<'0' || *str>'9')\r
825 continue;\r
826 \r
827 //Does this IP share QoS class with some other ?\r
828 substring=strstr(str,"sharing-");\r
829 if(substring)\r
830 { \r
831 substring+=8; //"sharing-"\r
832 parse_ip(str);\r
833 ip_count++;\r
834 ip->sharing=substring;\r
835 ip->keyword=defaultkeyword; /* settings for default keyword */\r
836 while(*substring && *substring!='\n')\r
837 substring++;\r
838 *substring=0; \r
839 }\r
840 else\r
841 {\r
842 //Do we have to create new QoS class for this IP ?\r
843\r
844 find(keyword,keywords,(substring=strstr(str,keyword->key)))\r
845 {\r
846 parse_ip(str);\r
847 ip_count++;\r
848 ip->keyword=keyword;\r
849 keyword->ip_count++;\r
850 ip->prio=keyword->default_prio;\r
851 substring+=strlen(keyword->key)+1;\r
852 ptr=substring;\r
853 while(*ptr && *ptr!='-')\r
854 ptr++;\r
855 if(*ptr=='-')\r
856 {\r
857 *ptr=0;\r
858 ip->max=ip->desired=atoi(ptr+1);\r
859 }\r
860 ip->min=atoi(substring);\r
861 if(ip->min<=0)\r
862 {\r
312ac2c1 863 printf(" %s: Illegal value of minimum bandwidth 0 kbps, using %d kbps\n",str,free_min);\r
c312f6a9 864 ip->min=free_min;\r
007c44c5 865 }\r
866 if(ip->max<=ip->min)\r
867 {\r
868 ip->fixedprio=1;\r
869 ip->max=ip->min+ip->keyword->reserve_min;\r
870 }\r
871 else \r
872 {\r
873 ip->max-=ip->keyword->reserve_max;\r
874\r
875/*\r
876 if(ip->keyword->divide_max>1)\r
877 ip->max=ip->min+(ip->max-ip->min)/ip->keyword->divide_max;\r
878 if(ip->keyword->htb_ceil_bonus_divide>0)\r
879 ip->max+=ip->max/ip->keyword->htb_ceil_bonus_divide;\r
880*/\r
881 if(ip->max<ip->min)\r
882 ip->max=ip->min;\r
883 }\r
43e07280 884 ip->mark=FIRSTIPCLASS+1+class_count++;\r
007c44c5 885\r
886 find(group,groups,group->min==ip->min) \r
887 { \r
888 group->count++; \r
889 group->desired+=ip->min;\r
890 ip->group = group->id; \r
891 }\r
892 else\r
893 {\r
894 create(group,Group);\r
895 group->min=ip->min;\r
896 group->id = groupidx++;\r
897 ip->group = group->id;\r
898\r
899 if(group->min<8) group->min=8;\r
900 /* Warning - this is maybe because of primitive tc namespace, can be fixed */\r
901 /* it is because class IDs are derived from min. bandwidth. - xCh */\r
902 //if(group->min>MAX_GUARANTED_KBPS) group->min=MAX_GUARANTED_KBPS;\r
903 \r
904 group->count=1;\r
905 group->desired=ip->min; \r
906 insert(group,groups,desc_order_by,min);\r
907 }\r
908 }//endif keyword-\r
909 }//endif sharing-\r
910 }\r
911 fail\r
912 {\r
913 perror(hosts);\r
914 exit(-1);\r
915 }\r
916 done;\r
917\r
918 /*-----------------------------------------------------------------*/\r
919 /* cll1.h - let's allocate brand new character buffer... */\r
920 /*-----------------------------------------------------------------*/\r
921 string(str,STRLEN); \r
922\r
923 /*-----------------------------------------------------------------*/\r
924 puts("Resolving shared connections ...");\r
925 /*-----------------------------------------------------------------*/\r
926 search(ip,ips,ip->sharing)\r
927 {\r
928 search(sharedip,ips,eq(sharedip->name,ip->sharing))\r
929 {\r
930 sharedip->traffic+=ip->traffic;\r
931 ip->traffic=0;\r
932 ip->mark=sharedip->mark; \r
933 break;\r
934 }\r
935 if(!sharedip)\r
936 printf("Unresolved shared connection: %s %s sharing-%s\n",ip->addr,ip->name,ip->sharing);\r
937 }\r
938\r
939 if(enable_credit && just_flush<9)\r
940 {\r
941 /*-----------------------------------------------------------------*/\r
942 printf("Parsing credit file %s ...\n", credit);\r
943 /*-----------------------------------------------------------------*/\r
944 parse(credit)\r
945 {\r
946 ptr=parse_datafile_line(_);\r
947 if(ptr)\r
948 {\r
949 find(ip,ips,eq(ip->addr,_))\r
950 sscanf(ptr,"%Lu",&(ip->credit));\r
951 }\r
952 }\r
953 done;\r
954 }\r
955\r
956 if(!just_preview)\r
957 {\r
958 /*-----------------------------------------------------------------*/\r
959 puts("Initializing iptables and tc classes ...");\r
960 /*-----------------------------------------------------------------*/\r
961 \r
962 iptables_file=fopen(iptablesfile,"w");\r
963 if (iptables_file == NULL) {\r
964 puts("Cannot open iptablesfile!");\r
965 exit(-1);\r
966 }\r
967 \r
968 log_file=fopen(cmdlog,"w");\r
969 if (log_file == NULL) {\r
970 puts("Cannot open logfile!");\r
971 exit(-1);\r
972 }\r
973 \r
974 save_line(iptablespreamble);\r
975 run_restore();\r
976 \r
977 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
978 safe_run(str);\r
979\r
980 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
981 safe_run(str);\r
982 \r
983 iptables_file=fopen(iptablesfile,"w");\r
984 save_line(iptablespreamble);\r
985\r
986 if(qos_free_zone && *qos_free_zone!='0')\r
987 {\r
988 char *chain;\r
989 \r
990 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
991 save_line(str);\r
992 \r
993 if(qos_proxy)\r
994 {\r
995 save_line(":post_noproxy - [0:0]");\r
996 sprintf(str,"-A POSTROUTING -p ! tcp -o %s -j post_noproxy", lan);\r
997 save_line(str); \r
998 sprintf(str,"-A POSTROUTING -s ! %s -o %s -j post_noproxy", proxy_ip, lan);\r
999 save_line(str); \r
1000 sprintf(str,"-A POSTROUTING -s %s -p tcp --sport ! %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
1001 save_line(str); \r
1002\r
1003 chain="post_noproxy"; \r
1004 }\r
1005 else\r
1006 chain="POSTROUTING";\r
1007 \r
1008 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
1009 save_line(str);\r
1010 }\r
1011 \r
1012 if(ip_count>idxtable_treshold1 && !just_flush)\r
1013 {\r
1014 int idxcount=0, bitmask=32-idxtable_bitmask1; /* default net mask: 255.255.255.240 */\r
e0161edb 1015 char *subnet, *buf;\r
007c44c5 1016 /*-----------------------------------------------------------------*/\r
1017 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
1018 /*-----------------------------------------------------------------*/\r
1019\r
1020 save_line(":post_common - [0:0]");\r
1021 save_line(":forw_common - [0:0]");\r
1022\r
1023 search(ip,ips,ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0"))\r
1024 {\r
1025 buf=hash_id(ip->addr,bitmask);\r
1026 find(idx,idxs,eq(idx->id,buf))\r
1027 idx->children++;\r
1028 else\r
1029 {\r
1030 create(idx,Index);\r
1031 idx->addr=ip->addr;\r
1032 idx->id=buf;\r
1033 idx->bitmask=bitmask;\r
1034 idx->parent=NULL;\r
1035 idx->children=0;\r
1036 idxcount++;\r
1037 push(idx,idxs);\r
1038 }\r
1039 }\r
1040\r
1041 /* brutal perfomance optimalization */\r
1042 while(idxcount>idxtable_treshold2 && bitmask>2*idxtable_bitmask2)\r
1043 {\r
1044 bitmask-=idxtable_bitmask2;\r
1045 idxcount=0;\r
1046 search(idx,idxs,idx->parent==NULL)\r
1047 {\r
1048 buf=hash_id(idx->addr,bitmask);\r
1049 find(metaindex,idxs,eq(metaindex->id,buf))\r
1050 metaindex->children++; \r
1051 else\r
1052 {\r
1053 create(metaindex,Index);\r
1054 metaindex->addr=idx->addr;\r
1055 metaindex->id=buf;\r
1056 metaindex->bitmask=bitmask;\r
1057 metaindex->parent=NULL;\r
1058 metaindex->children=0;\r
1059 idxcount++;\r
1060 push(metaindex,idxs);\r
1061 }\r
1062 idx->parent=metaindex;\r
1063 }\r
1064 }\r
1065\r
1066 /* this should slightly optimize throughout ... */\r
1067 sort(idx,idxs,desc_order_by,children);\r
1068 sort(idx,idxs,order_by,bitmask);\r
1069\r
1070 i=0;\r
1071 every(idx,idxs)\r
1072 {\r
1073 subnet=subnet_id(idx->addr,idx->bitmask);\r
1074 printf("%d: %s/%d\n",++i,subnet,idx->bitmask);\r
1075 \r
1076 sprintf(str,":post_%s - [0:0]", idx->id);\r
1077 save_line(str);\r
1078\r
1079 sprintf(str,":forw_%s - [0:0]", idx->id);\r
1080 save_line(str);\r
1081\r
1082 if(idx->parent)\r
1083 {\r
1084 string(buf,strlen(idx->parent->id)+6);\r
1085 sprintf(buf,"post_%s",idx->parent->id);\r
1086 }\r
1087 else\r
1088 buf="POSTROUTING";\r
1089\r
1090 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
1091 save_line(str);\r
1092\r
1093 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
1094 save_line(str);\r
1095\r
1096 if(idx->parent)\r
1097 {\r
1098 string(buf,strlen(idx->parent->id)+6);\r
1099 sprintf(buf,"forw_%s",idx->parent->id);\r
1100 }\r
1101 else\r
1102 buf="FORWARD";\r
1103\r
1104 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
1105 save_line(str);\r
1106\r
1107 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
1108 save_line(str);\r
1109 }\r
1110 printf("Total indexed iptables chains created: %d\n", i);\r
1111\r
1112 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
1113 save_line(str);\r
1114 \r
1115 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
1116 save_line(str);\r
1117 }\r
1118 \r
1119 }\r
1120\r
1121 if(just_flush)\r
1122 {\r
1123 fclose(iptables_file);\r
1124 if (log_file) fclose(log_file);\r
1125 puts("Just flushed iptables and tc classes - now exiting ...");\r
1126 exit(0);\r
1127 }\r
1128\r
1129 if(!just_preview)\r
1130 {\r
1131 if(!dry_run && !nodelay && qos_free_delay)\r
1132 {\r
1133 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
1134 sleep(qos_free_delay);\r
1135 }\r
1136\r
1137 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,lan,htb_r2q);\r
1138 safe_run(str);\r
1139\r
1140 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
1141 safe_run(str);\r
1142\r
1143 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
1144 safe_run(str);\r
1145\r
1146 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
1147 safe_run(str);\r
1148\r
1149 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
1150 safe_run(str);\r
1151\r
1152 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
1153 safe_run(str);\r
1154 }\r
1155\r
1156 /*-----------------------------------------------------------------*/\r
1157 puts("Locating suckers and generating root classes ...");\r
1158 /*-----------------------------------------------------------------*/\r
1159 sort(ip,ips,desc_order_by,traffic);\r
1160 \r
1161\r
1162 /*-----------------------------------------------------------------*/\r
1163 /* sub-scope - local variables */ \r
1164 {\r
1165 long long int rate=line;\r
1166 long long int max=line;\r
1167 int group_count=0;\r
1168 FILE *credit_file=NULL;\r
1169 \r
1170 if(!just_preview && !dry_run && enable_credit) credit_file=fopen(credit,"w");\r
1171 \r
1172 every(group,groups)\r
1173 {\r
1174 if(!just_preview)\r
1175 {\r
1176 \r
1177 //download\r
1178 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
1179 tc, lan, parent, group->id, rate, max, burst_group, group->desired);\r
1180 safe_run(str);\r
1181 \r
1182 //upload\r
1183 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
1184 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, group->desired);\r
1185 safe_run(str);\r
1186 }\r
1187 \r
1188 if(group_count++<max_nesting) parent=group->id;\r
1189 \r
1190 rate-=digital_divide*group->min;\r
1191 if(rate<group->min)rate=group->min;\r
1192 \r
1193 /*shaping of aggresive downloaders, with credit file support */\r
1194 if(use_credit)\r
1195 {\r
1196 int group_rate=group->min, priority_sequence=magic_priorities+1;\r
1197 \r
1198 search(ip, ips, ip->min==group->min && ip->max>ip->min)\r
1199 {\r
99127c70 1200 if( ip->keyword->data_limit && !ip->fixedprio &&\r
007c44c5 1201 ip->traffic>ip->credit+\r
99127c70 1202 (ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20)) )\r
007c44c5 1203 {\r
1204 if(group_rate<ip->max) ip->max=group_rate;\r
1205 group_rate+=magic_treshold;\r
1206 ip->prio=magic_priorities+2;\r
1207 if(ip->prio<3) ip->prio=3;\r
1208 }\r
1209 else\r
1210 {\r
abe9b855 1211 if( ip->keyword->data_prio && !ip->fixedprio &&\r
99127c70 1212 ip->traffic>ip->credit+\r
1213 (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20)) )\r
007c44c5 1214 {\r
1215 ip->prio=priority_sequence--;\r
1216 if(ip->prio<2) ip->prio=2;\r
1217 }\r
1218 \r
1219 if(credit_file)\r
1220 {\r
1221 unsigned long long lcredit=0;\r
99127c70 1222 \r
007c44c5 1223 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic) \r
1224 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1225 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1226 }\r
1227 }\r
1228 }\r
1229 \r
1230 }\r
1231 }\r
1232 if(credit_file)fclose(credit_file);\r
1233 }\r
1234\r
1235 if(just_preview)\r
1236 {\r
1237 f=fopen(preview,"w");\r
1238 ptr=preview; \r
1239 }\r
1240 else if(!dry_run && !just_flush)\r
1241 {\r
1242 /*-----------------------------------------------------------------*/\r
1243 printf("Writing data transfer database ...\n");\r
1244 /*-----------------------------------------------------------------*/\r
1245 f=fopen("/var/run/prometheus.previous","w");\r
1246 if(f)\r
1247 {\r
1248 search(ip,ips,ip->traffic || ip->direct || ip->proxy ||ip->upload)\r
1249 fprintf(f,"%s %Lu %Lu %Lu %Lu\n",ip->addr,ip->traffic,ip->direct,ip->proxy,ip->upload);\r
1250 fclose(f);\r
1251 }\r
1252\r
1253 f=fopen(html,"w");\r
1254 ptr=html;\r
1255 }\r
1256\r
1257 if(f)\r
1258 {\r
1259 int total=0;\r
1260 int count=1;\r
1261 i=0;\r
1262\r
1263 /*-----------------------------------------------------------------*/\r
1264 printf("Sorting data and generating statistics page %s ...\n",ptr);\r
1265 /*-----------------------------------------------------------------*/\r
1266\r
1267 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
1268 fprintf(f,"<th colspan=\"%d\">data limits</th>\n",keywordcount);\r
1269 fputs("</tr>\n",f);\r
1270 every(group,groups) \r
1271 { \r
1272#ifdef DEBUG\r
1273 printf("%d k group: %d bandwidth requested: %d k\n",group->min,group->count,group->desired);\r
1274#endif\r
1275 fprintf(f,"<tr><td align=\"right\">%d</td><td align=\"right\">%d k</td>",count,group->min);\r
1276 fprintf(f,"<td align=\"right\">%d</td><td align=\"right\">%d k</td>",group->count,group->desired);\r
1277\r
1278 every(keyword,keywords)\r
1279 fprintf(f,"<td align=\"right\"><font color=\"#%s\">%d M</font></td>",keyword->html_color,group->min*keyword->data_limit); \r
1280 \r
1281 i+=group->desired; \r
1282 total+=group->count;\r
1283 count++; \r
1284 }\r
1285#ifdef DEBUG\r
1286 printf("Total groups: %d Total bandwidth requested: %d k\nAGGREGATION: 1/%d\n",count,i,i/line);\r
1287#endif\r
e0161edb 1288 fprintf(f,"<tr><th colspan=\"2\" align=\"left\">Line %Ld k</td>",line);\r
007c44c5 1289 fprintf(f,"<th align=\"right\">%d</td><th align=\"right\">%d k</td>",total,i);\r
1290\r
1291 every(keyword,keywords)\r
1292 fprintf(f,"<th align=\"right\">%d IPs</th>",keyword->ip_count); \r
1293\r
1294 fprintf(f,"</tr><tr><th colspan=\"4\">Aggregation 1/%d</th>\n",(int)(0.5+i/line));\r
1295 fprintf(f,"<th colspan=\"%d\">%d traffic classes</th></tr>\n",keywordcount,total);\r
1296\r
1297 fputs("</table>\n",f);\r
1298 }\r
1299 else if(!dry_run && !just_flush) \r
1300 perror(html);\r
1301\r
1302 i=1;\r
1303 if(f)\r
1304 {\r
1305 unsigned long long total=0, total_direct=0, total_proxy=0, total_upload=0, tmp_sum=0;\r
1306 int active_classes=0;\r
1307 int colspan;\r
1308 FILE *iplog;\r
1309 struct Sum {unsigned long long l; int i; list(Sum);} *sum,*sums=NULL;\r
1310\r
1311 if(qos_proxy)\r
1312 colspan=12;\r
1313 else \r
1314 colspan=11;\r
1315 \r
1316 fprintf(f,"<p><table border>\n<tr><th colspan=\"%d\">%s",colspan,title);\r
1317 fprintf(f," (%s)</th></tr>\n", d);\r
1318 fputs("<tr><td align=\"right\">#</td><td>hostname</td>\\r
1319 <td align=\"right\">credit</td>\\r
1320 <td align=\"right\">limit</td>\\r
1321 <td align=\"right\">total</td>\\r
1322 <td align=\"right\">direct</td>\n",f);\r
1323 if(qos_proxy)\r
1324 fputs("<td align=\"right\">proxy</td>\n",f);\r
1325 fputs("<td align=\"right\">upload</td>\\r
1326 <td align=\"right\">minimum</td>\\r
1327 <td align=\"right\">desired</td>\\r
1328 <td align=\"right\">maximum</td>\\r
1329 <td>prio</td></tr>\n",f); \r
1330\r
1331 every(ip,ips)\r
1332 {\r
1333 char *f1="", *f2="";\r
1334 if(ip->max<ip->desired)\r
1335 {\r
1336 f1="<font color=\"red\">";\r
1337 f2="</font>";\r
1338 }\r
1339 else if(ip->prio>1)\r
1340 {\r
1341 f1="<font color=\"brown\">";\r
1342 f2="</font>";\r
1343 }\r
1344\r
1345#ifdef DEBUG\r
1346 printf("%03d. %-22s %10Lu (%d/%d)\n",i ,ip->name, ip->traffic, ip->min, ip->max); \r
1347#endif\r
1348 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
1349 ip->name, i, log_url, ip->name, ip->name, ip->credit);\r
1350 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
1351 fprintf(f,"<td align=\"right\">%s%Lu M%s</td><td align=\"right\">%Lu M</td>\n", f1, ip->traffic, f2, ip->direct);\r
1352 if(qos_proxy)\r
1353 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->proxy);\r
1354 fprintf(f,"<td align=\"right\">%Lu M</td>\n", ip->upload);\r
1355 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
1356 total+=ip->traffic;\r
1357 total_direct+=ip->direct;\r
1358 total_proxy+=ip->proxy;\r
1359 total_upload+=ip->upload;\r
1360 if(ip->traffic>0)\r
1361 {\r
1362 active_classes++;\r
1363 tmp_sum+=ip->traffic;\r
1364 create(sum,Sum);\r
1365 sum->l=tmp_sum;\r
1366 sum->i=active_classes;\r
1367 insert(sum,sums,order_by,i);\r
1368 }\r
1369 \r
1370 i++;\r
1371 \r
1372 if(!just_preview)\r
1373 {\r
5b902402 1374 sprintf(str,"%s/%s.log",log_dir,ip->name);\r
007c44c5 1375 iplog=fopen(str,"a");\r
1376 if(iplog)\r
1377 {\r
c0718973 1378 fprintf(iplog,"%ld\t%s\t%Lu\t%Lu\t%Lu\t%Lu\t%d\t%d\t%d\t%s",\r
1379 time(NULL),ip->name,ip->traffic,ip->direct,ip->proxy,ip->upload,ip->min,ip->max,ip->desired,d); /* d = date*/\r
007c44c5 1380 fclose(iplog);\r
1381 }\r
1382 }\r
1383\r
1384 }\r
1385 fprintf(f,"<tr><th colspan=\"4 \"align=\"left\">SUMMARY:</td>");\r
1386 fprintf(f,"<th align=\"right\">%Lu M</th>\\r
1387 <th align=\"right\">%Lu M</th>\n", total, total_direct);\r
1388 if(qos_proxy)\r
1389 fprintf(f,"<th align=\"right\">%Lu M</th>\n", total_proxy);\r
1390 fprintf(f,"<th align=\"right\">%Lu M</th>", total_upload);\r
1391 fputs("<td colspan=\"4\"></td></th>\n</table>\n",f);\r
1392\r
1393 if(active_classes>10)\r
c9012978 1394 {\r
1395 fputs("<a name=\"erp\"></a><p><table border><tr><th colspan=\"5\">Enterprise Research and Planning (ERP)</th></tr>\n",f);\r
1396 fputs("<tr><td>Analytic category</td>\n",f);\r
1397 fputs("<td colspan=\"2\" align=\"center\">Active Classes</td><td colspan=\"2\" align=\"center\">Data transfers</td></tr>\n",f);\r
1398\r
1399 find(sum,sums,sum->l>=total/4)\r
1400 {\r
1401 fprintf(f,"<tr><td>Top 25%% of traffic</td>\n");\r
1402 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
1403 }\r
1404 \r
1405 find(sum,sums,sum->i==10)\r
1406 {\r
1407 fprintf(f,"<tr><td>Top 10 downloaders</td>\n");\r
1408 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
1409 }\r
1410\r
1411 find(sum,sums,sum->l>=total/2)\r
1412 {\r
1413 fprintf(f,"<tr><td>Top 50%% of traffic</td>\n");\r
1414 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
1415 }\r
1416\r
1417 find(sum,sums,sum->l>=4*total/5)\r
1418 {\r
1419 fprintf(f,"<tr><td>Top 80%% of traffic</td>\n");\r
1420 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
1421 }\r
1422\r
1423 find (sum,sums,sum->i>=(active_classes+1)/5)\r
1424 {\r
1425 fprintf(f,"<tr><td>Top 20%% downloaders</td>\n");\r
1426 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
1427 }\r
1428\r
1429 find(sum,sums,sum->i>=(active_classes+1)/4)\r
1430 {\r
1431 fprintf(f,"<tr><td>Top 25%% downloaders</td>\n");\r
1432 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
1433 }\r
1434\r
1435 find(sum,sums,sum->i>=(active_classes+1)/2)\r
1436 {\r
1437 fprintf(f,"<tr><td>Top 50%% downloaders</td>\n");\r
1438 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
1439 }\r
1440\r
1441 find(sum,sums,sum->i>=4*(active_classes+1)/5)\r
1442 {\r
1443 fprintf(f,"<tr><td>Top 80%% downloaders</td>\n");\r
1444 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
1445 }\r
1446\r
1447 fprintf(f,"<tr><td>All users, all traffic</td>\n");\r
1448 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
1449 fputs("</table>\n",f);\r
1450 }\r
ab85aff7 1451 fprintf(f,"<small>Statistics generated by Prometheus QoS version %s<br>GPL+Copyright(C)2005-2008 Michael Polak, <a href=\"http://www.arachne.cz/\">Arachne Labs</a></small>\n",version);\r
007c44c5 1452 fclose(f);\r
1453 }\r
1454\r
1455 if(just_preview)\r
1456 {\r
1457 puts("Statistics preview generated (-p switch) - now exiting ...");\r
1458 exit(0);\r
1459 }\r
1460 \r
1461 /*-----------------------------------------------------------------*/\r
1462 puts("Generating iptables and tc classes ...");\r
1463 /*-----------------------------------------------------------------*/\r
1464\r
1465 i=0;\r
1466 printf("%-22s %-15s mark\n","name","ip");\r
1467 search(ip,ips,ip->mark>0)\r
1468 { \r
1469 \r
1470 if(idxs)\r
1471 {\r
1472 char *buf;\r
1473 duplicate(ip->addr,buf);\r
1474 buf=hash_id(ip->addr,32-idxtable_bitmask1); \r
1475 \r
1476 string(chain_forward,6+strlen(buf));\r
1477 strcpy(chain_forward,"forw_");\r
1478 strcat(chain_forward,buf);\r
1479\r
1480 string(chain_postrouting,6+strlen(buf));\r
1481 strcpy(chain_postrouting,"post_");\r
1482 strcat(chain_postrouting,buf);\r
1483 \r
1484 free(buf);\r
1485 }\r
1486 else\r
1487 {\r
1488 chain_forward="FORWARD";\r
1489 chain_postrouting="POSTROUTING";\r
1490 }\r
1491\r
1492 printf("%-22s %-16s %04d ", ip->name, ip->addr, ip->mark); \r
1493\r
1494 /* -------------------------------------------------------- mark download */\r
1495 \r
1496 sprintf(str,"-A %s -d %s/32 -o %s -j %s%d",chain_postrouting,ip->addr,lan,mark_iptables,ip->mark);\r
1497 /*sprintf(str,"-A %s -d %s/32 -o %s -j MARK --set-mark %d",chain_postrouting,ip->addr,lan,ip->mark);*/\r
1498 /* -m limit --limit 1/s */ \r
1499 save_line(str);\r
1500\r
1501 if(qos_proxy)\r
1502 {\r
1503 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
1504 /*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
1505 save_line(str);\r
1506 }\r
1507\r
1508 sprintf(str,"-A %s -d %s/32 -o %s -j ACCEPT",chain_postrouting,ip->addr,lan);\r
1509 save_line(str);\r
1510\r
1511 /* -------------------------------------------------------- mark upload */\r
1512 sprintf(str,"-A %s -s %s/32 -o %s -j %s%d",chain_forward,ip->addr,wan,mark_iptables,ip->mark);\r
1513 /* sprintf(str,"-A %s -s %s/32 -o %s -j MARK --set-mark %d",chain_forward,ip->addr,wan,ip->mark);*/\r
1514 save_line(str);\r
1515\r
1516 sprintf(str,"-A %s -s %s/32 -o %s -j ACCEPT",chain_forward,ip->addr,wan);\r
1517 save_line(str);\r
1518\r
1519 if(ip->min)\r
1520 {\r
1521 /* -------------------------------------------------------- download class */\r
1522 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1523\r
1524 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
1525 safe_run(str);\r
1526\r
1527 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1528 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
1529 safe_run(str);\r
1530 }\r
1531 \r
1532 if (filter_type == 1){\r
1533 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
1534 safe_run(str);\r
1535 }\r
1536\r
1537 /* -------------------------------------------------------- upload class */\r
1538 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1539 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1540\r
1541 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1542 tc, wan, ip->group, ip->mark,\r
1543 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1544 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1545 safe_run(str);\r
1546 \r
1547 if (strcmpi(ip->keyword->leaf_discipline, "none")){\r
1548 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
1549 safe_run(str);\r
1550 }\r
1551 \r
1552 if (filter_type == 1){\r
1553 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
1554 safe_run(str);\r
1555 }\r
1556 }\r
1557 else\r
1558 printf("(sharing %s)\n", ip->sharing);\r
1559 i++;\r
1560 }\r
1561\r
1562\r
1563 if(idxs)\r
1564 {\r
1565 chain_forward="forw_common";\r
1566 chain_postrouting="post_common";\r
1567 }\r
1568 else\r
1569 {\r
1570 chain_forward="FORWARD";\r
1571 chain_postrouting="POSTROUTING";\r
1572 }\r
1573\r
1574 /* -------------------------------------------------------- mark download */\r
1575\r
1576 if(qos_proxy)\r
1577 {\r
c9012978 1578 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
007c44c5 1579 save_line(str);\r
1580 sprintf(str,"-A %s -s %s -p tcp --sport %d -o %s -j ACCEPT",chain_postrouting,proxy_ip,proxy_port,lan);\r
1581 save_line(str);\r
1582 }\r
c9012978 1583 sprintf(str,"-A %s -o %s -j %s%d",chain_postrouting,lan,mark_iptables,3);\r
007c44c5 1584 save_line(str);\r
1585 sprintf(str,"-A %s -o %s -j ACCEPT",chain_postrouting,lan);\r
1586 save_line(str);\r
1587\r
1588 /* -------------------------------------------------------- mark upload */\r
c9012978 1589 sprintf(str,"-A %s -o %s -j %s%d",chain_forward,wan,mark_iptables,3);\r
007c44c5 1590 save_line(str);\r
1591 sprintf(str,"-A %s -o %s -j ACCEPT",chain_forward,wan);\r
1592 save_line(str);\r
1593\r
1594 printf("Total IP count: %d\n", i);\r
1595\r
abe9b855 1596 /*-----------------------------------------------------------------*/\r
1597 puts("Generating free bandwith classes ...");\r
1598 /*-----------------------------------------------------------------*/\r
1599\r
007c44c5 1600 /* ---------------------------------------- tc - free bandwith shared class */\r
1601 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
1602 safe_run(str);\r
1603\r
1604 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
1605 safe_run(str);\r
1606\r
1607 /* tc SFQ */\r
1608 if (strcmpi(qos_leaf, "none")){\r
1609 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,lan,qos_leaf);\r
1610 safe_run(str);\r
1611 \r
1612 sprintf(str,"%s qdisc add dev %s parent 1:3 handle 3 %s",tc,wan,qos_leaf);\r
1613 safe_run(str);\r
1614 }\r
1615 \r
1616 /* tc handle 1 fw flowid */\r
1617 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,lan);\r
1618 safe_run(str);\r
1619\r
1620 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle 3 fw flowid 1:3",tc,wan);\r
1621 safe_run(str);\r
abe9b855 1622\r
007c44c5 1623 run_restore();\r
1624 \r
1625 if (log_file) fclose(log_file);\r
1626 return 0;\r
1627\r
1628 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1629 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1630}\r
This page took 1.350635 seconds and 4 git commands to generate.