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