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