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