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