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