almost new release (some aggregation related stuff and more)
[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-2015 Michael Polak, Arachne Aerospace */\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, 20150315\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#include "cll1-0.6.2.h"\r
30#include "ipstruct.h"\r
31\r
32const char *version = "0.8.5-c";\r
33\r
34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
35/* Versions: 0.8.3 is development release, 0.8.4 will be "stable" */\r
36/* Official Trac URL: https://dev.arachne.cz/svn/prometheus */\r
37/* Official SVN URL: https://dev.arachne.cz/repos/prometheus */\r
38/* BTC donations account: 19rriLx8vR19wGefPaMhakqnCYNYwjLvxq */\r
39/* CZK donations account: 2900242944/2010 (transparent account) */\r
40/* Warning: unofficial Github mirror is not supported by author! */\r
41/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
42\r
43const char *stats_html_signature = "<span class=\"small\">Statistics generated by Prometheus QoS version %s<br />GPL+Copyright(C)2005-2015 Michael Polak, <a target=\"_blank\" href=\"http://www.arachne.cz/\">Arachne Labs</a></span>\n";\r
44\r
45#define STRLEN 512\r
46#undef DEBUG\r
47\r
48/* ======= All path names are defined here (for RPM patch) ======= */\r
49\r
50const char *tc = "/sbin/tc"; /* requires tc with HTB support */\r
51const char *iptables = "/sbin/iptables"; /* requires iptables utility */\r
52const char *ip6tables = "/sbin/ip6tables"; /* requires iptables utility */\r
53const char *iptablessave = "/sbin/iptables-save"; /* not yet required */\r
54const char *iptablesrestore = "/sbin/iptables-restore"; /* requires iptables-restore */\r
55const char *ip6tablessave = "/sbin/ip6tables-save"; /* not yet required */\r
56const char *ip6tablesrestore = "/sbin/ip6tables-restore"; /* requires iptables-restore */\r
57const char *ls = "/bin/ls"; /* this is not user configurable :-) */\r
58\r
59char *config = "/etc/prometheus/prometheus.conf"; /* main configuration file */\r
60char *hosts = "/etc/prometheus/hosts"; /* per-IP bandwidth definition file */\r
61char *macrosfile = "/etc/prometheus/prometheus.macros"; /* rewrite rules for most common tariffs */\r
62char *iptablesfile = "/var/spool/prometheus.iptables"; /* temporary file for iptables-restore*/\r
63char *ip6tablesfile = "/var/spool/prometheus.ip6tables"; /* temporary file for ip6tables-restore*/\r
64char *credit = "/var/lib/misc/prometheus.credit"; /* credit log file */\r
65char *classmap = "/var/lib/misc/prometheus.classes"; /* credit log file */\r
66char *html = "/var/www/traffic.html"; /* hall of fame - html version */\r
67char *preview = "/var/www/preview.html"; /* hall of fame preview - html version */\r
68char *json_traffic = "/var/www/logs/traffic.json"; /* hall of fame - json version */\r
69char *json_preview = "/var/www/logs/preview.json"; /* hall of fame preview - json version */\r
70char *cmdlog = "/var/log/prometheuslog"; /* command log filename */\r
71char *log_dir = "/var/www/logs/"; /* log directory pathname, ended with slash */\r
72char *log_url = "/logs/"; /* log directory relative URI prefix (partial URL) */\r
73char *html_log_dir = "/var/www/logs/html/";\r
74\r
75char *jquery_url = "http://code.jquery.com/jquery-latest.js";\r
76char *lms_url = "/lms/?m=customerinfo&amp;id=";\r
77int use_jquery_popups = TRUE;\r
78int row_odd_even = 0; /*<tr class="odd/even"> */\r
79 \r
80/* === Configuraration file values defaults - stored in global variables ==== */\r
81\r
82int filter_type = 1; /*1 mark, 2 classify*/\r
83char *final_chain = "DROP"; /* REJECT would be better, but it is impossible in mangle */\r
84char *mark = "MARK";\r
85char *mark_iptables = "MARK --set-mark ";\r
86int dry_run = FALSE; /* preview - use puts() instead of system() */\r
87char *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
88char *ip6preamble = "-A FORWARD -p ipv6-icmp -j ACCEPT\n-A POSTROUTING -p ipv6-icmp -j ACCEPT\n-A FORWARD -s fe80::/10 -j ACCEPT\n-A FORWARD -d ff00::/8 -j ACCEPT\n-A POSTROUTING -s fe80::/10 -j ACCEPT\n-A POSTROUTING -d ff00::/8 -j ACCEPT";\r
89FILE *iptables_file = NULL;\r
90FILE *ip6tables_file = NULL;\r
91int enable_credit = TRUE; /* enable credit file */\r
92int use_credit = FALSE; /* use credit file (if enabled)*/\r
93char *title = "Hall of Fame - Greatest Suckers"; /* hall of fame title */\r
94int hall_of_fame = TRUE; /* enable hall of fame */\r
95char *lan = "eth0"; /* LAN interface */\r
96char *lan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */\r
97char *wan = "eth1"; /* WAN/ISP interface */\r
98char *ip6prefix = NULL; /* Prefix for global /48 IPv6 subnet */\r
99char *wan_medium = "100Mbit"; /* 10Mbit/100Mbit ethernet */\r
100char *qos_leaf = "sfq perturb 5"; /* leaf discipline */\r
101char *qos_free_zone = NULL; /* QoS free zone */\r
102/* int qos_proxy = TRUE; include proxy port to QoS */\r
103int found_lmsid = FALSE; /* show links to users in LMS information system */\r
104int include_upload = TRUE; /* upload+download=total traffic */\r
105/* char *proxy_ip = "192.168.1.1/32"; our IP with proxy port */\r
106/* int proxy_port = 3128; proxy port number */\r
107long long int line = 1024; /* WAN/ISP download in kbps */\r
108long long int up = 1024; /* WAN/ISP upload in kbps */\r
109int free_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
110int free_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
111int overlimit_min = 256; /* minimum guaranted bandwidth for all undefined hosts */\r
112int overlimit_max = 512; /* maximum allowed bandwidth for all undefined hosts */\r
113int qos_free_delay = 0; /* seconds to sleep before applying new QoS rules */\r
114int digital_divide = 2; /* controls digital divide weirdness ratio, 1...3 */ \r
115int max_nesting = 5; /* /include/uapi/linux/pkt_sched.h: #define TC_HTB_MAXDEPTH 8 [... - 3 parent classes] */\r
116int htb_r2q = 256; /* should work for leaf values 512 kbps to 8 Mbps */\r
117int burst = 8; /* HTB burst (in kbits) */\r
118int burst_main = 64;\r
119int burst_group = 32;\r
120int magic_treshold = 8; /* reduce ceil by X*magic_treshhold kbps (hard shaping) */\r
121int keywordcount = 0;\r
122int class_count = 0;\r
123int ip_count = 0;\r
124FILE *log_file = NULL;\r
125char *kwd = "via-prometheus"; /* /etc/hosts comment, eg. #qos-64-128 */\r
126\r
127const int highest_priority = 0; /* highest HTB priority (HTB built-in value is 0) */\r
128const int lowest_priority = 7; /* lowest HTB priority /include/uapi/linux/pkt_sched.h: #define TC_HTB_NUMPRIO 8 */\r
129const int idxtable_treshold1 = 24; /* this is no longer configurable */\r
130const int idxtable_treshold2 = 12; /* this is no longer configurable */\r
131const int idxtable_bitmask1 = 3; /* this is no longer configurable */\r
132const int idxtable_bitmask2 = 3; /* this is no longer configurable */\r
133\r
134struct IP *ips = NULL, *networks = NULL, *ip, *sharedip;\r
135struct Group *groups = NULL, *group;\r
136struct Keyword *keyword, *defaultkeyword=NULL, *keywords = NULL;\r
137struct Macro *macro, *macros = NULL;\r
138\r
139#define FREE_CLASS 3\r
140#define OVERLIMIT_CLASS 4\r
141\r
142void help(void);\r
143/* implemented in help.c */
144\r
145void get_traffic_statistics(const char *whichiptables, int ipv6);\r
146/* implemented in parseiptables.c */\r
147\r
148void parse_ip_log(int argc, char **argv);\r
149/* implemented in parselog.c */\r
150\r
151void parse_hosts(char *hosts);\r
152/* implemented in parsehosts.c */\r
153\r
154void write_json_traffic(char *json);\r
155/* implemented in json.c */\r
156\r
157void write_htmlandlogs(char *html, char *d, int total, int just_preview);\r
158/* implemented in htmlandlogs.c */\r
159\r
160void analyse_topology(char *traceroute);\r
161/* implemented in networks.c */\r
162\r
163char *parse_datafile_line(char *str);\r
164/* implemented in utils.c */\r
165\r
166time_t get_mtime(const char *path);\r
167/* implemented in utils.c */\r
168\r
169const char *tr_odd_even(void)\r
170{\r
171 row_odd_even = 1 - row_odd_even;\r
172 if(row_odd_even)\r
173 {\r
174 return "<tr class=\"even\">\n";\r
175 }\r
176 else\r
177 {\r
178 return "<tr class=\"odd\">\n";\r
179 }\r
180}\r
181\r
182/* ==== This is C<<1 stuff - learn C<<1 first! https://dev.arachne.cz/svn/cll1h ==== */\r
183/* (except that this code uses obsolete, archaic version of this header file...) */\r
184\r
185struct Index\r
186{\r
187 char *addr;\r
188 char *id;\r
189 struct Index *parent;\r
190 int bitmask;\r
191 int children;\r
192 int ipv6;\r
193 list(Index);\r
194} *idxs=NULL, *idx, *metaindex;\r
195\r
196\r
197/* ====== iptables indexes are used to reduce complexity to log8(N) ===== */\r
198\r
199char *index_id(char *ip, int bitmask);\r
200/* function implemented in ipv4subnets.c */\r
201\r
202char *subnet_id(char *ip, int bitmask);\r
203/* function implemented in ipv4subnets.c */\r
204\r
205char *index6_id(char *ip, int bitmask);\r
206/* function implemented in ipv6subnets.c */\r
207\r
208char *subnet6_id(char *ip, int bitmask);\r
209/* function implemented in ipv6subnets.c */\r
210\r
211/* ================= Let's parse configuration file here ================ */\r
212\r
213void reject_config_and_exit(char *filename)\r
214{\r
215 printf("Configuration file %s rejected - abnormal exit.",filename);\r
216 exit(-1);\r
217}\r
218\r
219void get_config(char *config_filename)\r
220{\r
221 char *cnf="mark";\r
222 \r
223 printf("Configured keywords: ");\r
224 parse(config_filename)\r
225 {\r
226 option("keyword",kwd);\r
227 if(kwd)\r
228 {\r
229 printf("%s ",kwd);\r
230\r
231 create(keyword,Keyword);\r
232 keyword->key = kwd;\r
233 keyword->asymetry_ratio = 1; /* ratio for ADSL-like upload */\r
234 keyword->asymetry_fixed = 0; /* fixed treshold for ADSL-like upload */\r
235 keyword->data_limit = 8; /* hard shaping: apply magic_treshold if max*data_limit MB exceeded */\r
236 keyword->data_prio = 4; /* soft shaping (qos): reduce HTB prio if max*data_prio MB exceeded */\r
237 keyword->fixed_limit = 0; /* fixed data limit for setting lower HTB ceil */\r
238 keyword->fixed_prio = 0; /* fixed data limit for setting lower HTB prio */\r
239 keyword->reserve_min = 8; /* bonus for nominal HTB rate bandwidth (in kbps) */\r
240 keyword->reserve_max = 0; /* malus for nominal HTB ceil (in kbps) */\r
241 keyword->default_prio = highest_priority+1;\r
242 keyword->download_aggregation = keyword->upload_aggregation = 0; /* disable by default */\r
243 keyword->html_color = "000000";\r
244 keyword->ip_count = 0;\r
245 keyword->leaf_discipline = "";\r
246 keyword->allowed_avgmtu = 0;\r
247 keyword->download_aggregation = keyword->upload_aggregation = 1;\r
248\r
249 push(keyword, keywords);\r
250 if(!defaultkeyword)\r
251 {\r
252 defaultkeyword = keyword;\r
253 }\r
254 keywordcount++;\r
255 \r
256 kwd=NULL;\r
257 }\r
258 else\r
259 {\r
260 for_each(keyword,keywords)\r
261 {\r
262 int l=strlen(keyword->key);\r
263\r
264 if(!strncmp(keyword->key,_,l) && strlen(_)>l+2)\r
265 {\r
266 char *tmptr=_; /* <---- l+1 ----> */\r
267 _+=l+1; /* via-prometheus-asymetry-ratio, etc. */\r
268 foption("asymetry-ratio", keyword->asymetry_ratio);\r
269 ioption("asymetry-treshold", keyword->asymetry_fixed);\r
270 ioption("magic-relative-limit", keyword->data_limit);\r
271 ioption("magic-relative-prio", keyword->data_prio);\r
272 loption("magic-fixed-limit", keyword->fixed_limit);\r
273 loption("magic-fixed-prio", keyword->fixed_prio);\r
274 ioption("htb-default-prio", keyword->default_prio);\r
275 ioption("htb-rate-bonus", keyword->reserve_min);\r
276 ioption("htb-ceil-malus", keyword->reserve_max);\r
277 ioption("download-aggregation", keyword->download_aggregation);\r
278 ioption("upload-aggregation", keyword->upload_aggregation);\r
279 option("leaf-discipline", keyword->leaf_discipline);\r
280 option("html-color", keyword->html_color);\r
281 ioption("allowed-avgmtu" ,keyword->allowed_avgmtu);\r
282 _=tmptr;\r
283 \r
284 if(keyword->data_limit || keyword->fixed_limit || \r
285 keyword->data_prio || keyword->fixed_prio)\r
286 {\r
287 use_credit=1; \r
288 }\r
289 }\r
290 }\r
291 }\r
292\r
293 option("tc",tc);\r
294 option("iptables",iptables);\r
295 option("iptables-save",iptablessave);\r
296 option("iptables-restore",iptablesrestore);\r
297 option("ip6tables",ip6tables);\r
298 option("ip6tables-save",ip6tablessave);\r
299 option("ip6tables-restore",ip6tablesrestore);\r
300 option("iptables-in-filename",iptablesfile);\r
301 option("ip6tables-in-filename",ip6tablesfile);\r
302 option("hosts",hosts);\r
303 option("lan-interface",lan);\r
304 option("wan-interface",wan);\r
305 option("ip6-prefix",ip6prefix);\r
306 option("lan-medium",lan_medium);\r
307 option("wan-medium",wan_medium);\r
308 lloption("wan-download",line);\r
309 lloption("wan-upload",up);\r
310 ioption("hall-of-fame-enable",hall_of_fame);\r
311 option("hall-of-fame-title",title);\r
312 option("hall-of-fame-filename",html);\r
313 option("json-filename",json_traffic);\r
314 option("hall-of-fame-preview",preview);\r
315 option("json-preview",json_preview);\r
316 option("log-filename",cmdlog);\r
317 option("credit-filename",credit);\r
318 option("classmap-filename",classmap);\r
319 ioption("credit-enable",enable_credit);\r
320 option("log-traffic-directory",log_dir);\r
321 option("log-traffic-html-directory",html_log_dir);\r
322 option("log-traffic-url-path",log_url);\r
323 option("jquery-url",jquery_url);\r
324 option("lms-url",lms_url);\r
325 ioption("use-jquery-popups",use_jquery_popups);\r
326 option("qos-free-zone",qos_free_zone);\r
327 ioption("qos-free-delay",qos_free_delay);\r
328/* ioption("qos-proxy-enable",qos_proxy); */\r
329/* option("qos-proxy-ip",proxy_ip);*/\r
330 option("htb-leaf-discipline",qos_leaf);\r
331/* ioption("qos-proxy-port",proxy_port); */\r
332 ioption("free-rate",free_min);\r
333 ioption("free-ceil",free_max);\r
334 ioption("overlimit-rate",overlimit_min);\r
335 ioption("overlimit-ceil",overlimit_max);\r
336 ioption("htb-burst",burst);\r
337 ioption("htb-burst-main",burst_main);\r
338 ioption("htb-burst-group",burst_group);\r
339 ioption("htb-nesting-limit",max_nesting);\r
340 ioption("htb-r2q",htb_r2q);\r
341 ioption("magic-include-upload",include_upload);\r
342 ioption("magic-treshold",magic_treshold); \r
343 option("filter-type", cnf); \r
344/* not yet implemented:\r
345 ioption("magic-fixed-packets",fixed_packets);\r
346 ioption("magic-relative-packets",packet_limit);\r
347*/\r
348 }\r
349 fail\r
350 { \r
351 perror(config_filename);\r
352 puts("Warning - using built-in defaults instead ...");\r
353 }\r
354 done; /* ugly macro end */\r
355 printf("\n");\r
356 \r
357 /* leaf discipline for keywords */\r
358 for_each(keyword,keywords)\r
359 {\r
360 if(!strcmpi(keyword->leaf_discipline, ""))\r
361 {\r
362 keyword->leaf_discipline = qos_leaf;\r
363 }\r
364 }\r
365\r
366 if(strcmpi(cnf, "mark"))\r
367 {\r
368 filter_type = 2;\r
369 mark = "CLASSIFY";\r
370 mark_iptables = "CLASSIFY --set-class 1:";\r
371 }\r
372 else\r
373 {\r
374 filter_type = 1;\r
375 mark = "MARK";\r
376 mark_iptables = "MARK --set-mark ";\r
377 }\r
378\r
379 /* are supplied values meaningful ?*/\r
380 if(line<=0 || up<=0)\r
381 {\r
382 puts("Illegal value of LAN or WAN bandwidth: 0 kbps.");\r
383 reject_config_and_exit(config_filename);\r
384 }\r
385}\r
386\r
387 \r
388/* ========== This function executes, logs OR ALSO prints command ========== */\r
389\r
390void safe_run(char *cmd)\r
391{\r
392 if(dry_run)\r
393 {\r
394 printf("\n=>%s\n",cmd);\r
395 }\r
396 else\r
397 {\r
398 system(cmd);\r
399 }\r
400 if(log_file)\r
401 {\r
402 fprintf(log_file,"%s\n",cmd);\r
403 }\r
404}\r
405\r
406void iptables_save_line(char *line, int ipv6)\r
407{\r
408 if(ipv6)\r
409 {\r
410 fprintf(ip6tables_file,"%s\n",line);\r
411 }\r
412 else\r
413 {\r
414 fprintf(iptables_file,"%s\n",line);\r
415 }\r
416}\r
417\r
418void run_iptables_restore(void)\r
419{\r
420 char *restor;\r
421 string(restor,STRLEN);\r
422\r
423 /*-----------------------------------------------------------------*/\r
424 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
425 /*-----------------------------------------------------------------*/\r
426\r
427 iptables_save_line("COMMIT", FALSE);\r
428 fclose(iptables_file);\r
429 if(dry_run) \r
430 {\r
431 parse(iptablesfile)\r
432 {\r
433 printf("%s\n",_);\r
434 }\r
435 done; /* ugly macro end */\r
436 }\r
437\r
438 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
439 safe_run(restor);\r
440\r
441 if(ip6prefix)\r
442 {\r
443 /*-----------------------------------------------------------------*/\r
444 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
445 /*-----------------------------------------------------------------*/\r
446 iptables_save_line("COMMIT", TRUE);\r
447 fclose(ip6tables_file);\r
448 if(dry_run) \r
449 {\r
450 parse(ip6tablesfile)\r
451 {\r
452 printf("%s\n",_);\r
453 }\r
454 done; /* ugly macro end */\r
455 }\r
456 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
457 safe_run(restor);\r
458 }\r
459 free(restor);\r
460}\r
461\r
462/**/\r
463\r
464char *parse_datafile_line(char *str);\r
465time_t get_mtime(const char *path);\r
466\r
467/*-----------------------------------------------------------------*/\r
468/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
469/*-----------------------------------------------------------------*/\r
470\r
471program\r
472{\r
473 int i=0; /* just plain old Fortran style integer :-) */\r
474 FILE *f=NULL; /* everything is just stream of bytes... */\r
475 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
476 char *substring, *limit_pkts;\r
477\r
478 int parent = 1;\r
479 int just_networks = FALSE; \r
480 int just_flush = FALSE; /* deactivates all previous actions */\r
481 int nodelay = FALSE;\r
482 int just_preview = FALSE; /* preview - generate just stats */\r
483 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
484 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
485 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
486 int just_logs = FALSE; /* just parse logs */\r
487 int run = FALSE;\r
488 int total = 0;\r
489 \r
490 char *chain_forward, *chain_postrouting;\r
491 char *althosts=NULL;\r
492 \r
493 printf("\n\\r
494Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
495Version %s - Copyright (C)2005-2015 Michael Polak, Arachne Labs\n\\r
496iptables-restore & burst tunning & classify modification by Ludva\n\\r
497Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
498\r
499 /*----- Boring... we have to check command line options first: ----*/ \r
500 arguments\r
501 {\r
502 argument("-c") { nextargument(config); }\r
503 argument("-h") { nextargument(althosts);}\r
504 argument("-d") { run=TRUE; dry_run=TRUE; }\r
505 argument("-f") { run=TRUE; just_flush=TRUE; }\r
506 argument("-9") { run=TRUE; just_flush=9; }\r
507 argument("-p") { run=TRUE; just_preview=TRUE; }\r
508 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
509 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
510 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
511 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
512 argument("-r") { run=TRUE; }\r
513 argument("-n") { run=TRUE; nodelay=TRUE; }\r
514 argument("-a") { run=TRUE; just_networks=TRUE; }\r
515 argument("-l") { just_logs=TRUE; }\r
516 argument("-m") { just_logs=TRUE; }\r
517 argument("-y") { just_logs=TRUE; }\r
518 argument("-?") { help(); exit(0); }\r
519 argument("--help") { help(); exit(0); }\r
520 argument("-v") { exit(0); } \r
521 argument("--version") { exit(0); } \r
522 }\r
523 \r
524 if(dry_run)\r
525 {\r
526 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
527 }\r
528\r
529 date(d); /* this is typical cll1.h macro - prints current date */\r
530\r
531 /*-----------------------------------------------------------------*/\r
532 printf("Parsing configuration file %s ...\n", config);\r
533 /*-----------------------------------------------------------------*/\r
534 get_config(config);\r
535 \r
536 if(just_logs)\r
537 {\r
538 parse_ip_log(argc,argv);\r
539 exit(0);\r
540 }\r
541 else if(not run)\r
542 {\r
543 help();\r
544 exit(0);\r
545 }\r
546\r
547 if(althosts)\r
548 {\r
549 hosts = althosts;\r
550 }\r
551\r
552 if(just_flush<9)\r
553 {\r
554 /*-----------------------------------------------------------------*/\r
555 puts("Parsing iptables verbose output ...");\r
556 /*-----------------------------------------------------------------*/\r
557 get_traffic_statistics(iptables, FALSE);\r
558 if(ip6prefix)\r
559 {\r
560 /*-----------------------------------------------------------------*/\r
561 puts("Parsing ip6tables verbose output ...");\r
562 /*-----------------------------------------------------------------*/ \r
563 get_traffic_statistics(ip6tables, TRUE);\r
564 }\r
565 }\r
566\r
567 /*-----------------------------------------------------------------*/\r
568 /* cll1.h - let's allocate brand new character buffer... */\r
569 /*-----------------------------------------------------------------*/\r
570 string(str, STRLEN); \r
571 string(limit_pkts, STRLEN);\r
572\r
573 /*-----------------------------------------------------------------*/\r
574 printf("Parsing macro definition file %s ...\n", macrosfile);\r
575 /*-----------------------------------------------------------------*/\r
576 parse(macrosfile)\r
577 {\r
578 ptr = parse_datafile_line(_);\r
579 if(ptr)\r
580 {\r
581 create(macro, Macro);\r
582 macro->rewrite_from = _;\r
583 macro->rewrite_to = ptr;\r
584 push(macro, macros);\r
585 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
586 }\r
587 }\r
588 done; /* ugly macro end */\r
589\r
590 /*-----------------------------------------------------------------*/\r
591 printf("Parsing class defintion file %s ...\n", hosts);\r
592 /*-----------------------------------------------------------------*/\r
593 parse_hosts(hosts);\r
594 if(just_networks)\r
595 {\r
596 analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d");\r
597 exit(-1); \r
598 }\r
599\r
600 /*-----------------------------------------------------------------*/\r
601 puts("Resolving shared connections ...");\r
602 /*-----------------------------------------------------------------*/\r
603 for_each(ip, ips) if(ip->sharing)\r
604 {\r
605 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
606 {\r
607 sharedip->traffic += ip->traffic;\r
608 ip->traffic = 0;\r
609 ip->mark = sharedip->mark; \r
610 ip->lmsid = sharedip->lmsid;\r
611 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
612\r
613 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
614 ptr = strchr(ip->addr, '+');\r
615 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
616 {\r
617 *(--ptr) = 0;\r
618 concatenate(ip->addr, sharedip->addr, ptr);\r
619 ip->name = ip->addr = ptr;\r
620 ptr = strchr(ip->addr, '.');\r
621 while(ptr && *ptr)\r
622 {\r
623 *ptr = ':';\r
624 ptr = strchr(ptr, '.');\r
625 }\r
626 ip->mask += 64;\r
627 }\r
628\r
629 break;\r
630 }\r
631 if(not sharedip)\r
632 {\r
633 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
634 ip->addr, ip->name, ip->sharing);\r
635 }\r
636 }\r
637\r
638 if(enable_credit && just_flush<9)\r
639 {\r
640 /*-----------------------------------------------------------------*/\r
641 printf("Parsing credit file %s ...\n", credit);\r
642 /*-----------------------------------------------------------------*/\r
643 parse(credit)\r
644 {\r
645 ptr = parse_datafile_line(_);\r
646 if(ptr)\r
647 {\r
648 if_exists(ip,ips,eq(ip->addr,_))\r
649 {\r
650 sscanf(ptr,"%Lu",&(ip->credit));\r
651 }\r
652 }\r
653 }\r
654 done; /* ugly macro end */\r
655 }\r
656\r
657\r
658 if(!just_preview)\r
659 {\r
660 /*-----------------------------------------------------------------*/\r
661 puts("Initializing iptables and tc classes ...");\r
662 /*-----------------------------------------------------------------*/\r
663 \r
664 iptables_file = fopen(iptablesfile, "w");\r
665 if(iptables_file == NULL)\r
666 {\r
667 perror(iptablesfile);\r
668 exit(-1);\r
669 }\r
670 iptables_save_line(iptablespreamble, FALSE);\r
671\r
672 if(ip6prefix)\r
673 {\r
674 ip6tables_file = fopen(ip6tablesfile, "w");\r
675 if(ip6tables_file == NULL)\r
676 {\r
677 perror(ip6tablesfile);\r
678 exit(-1);\r
679 }\r
680 iptables_save_line(iptablespreamble, TRUE);\r
681 iptables_save_line(ip6preamble, TRUE);\r
682 }\r
683\r
684 run_iptables_restore();\r
685 \r
686 log_file = fopen(cmdlog, "w");\r
687 if(log_file == NULL) \r
688 {\r
689 perror(cmdlog);\r
690 exit(-1);\r
691 } \r
692 \r
693 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
694 safe_run(str);\r
695\r
696 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
697 safe_run(str);\r
698 \r
699 iptables_file=fopen(iptablesfile,"w");\r
700 iptables_save_line(iptablespreamble, FALSE);\r
701 if(ip6prefix)\r
702 {\r
703 ip6tables_file=fopen(ip6tablesfile,"w");\r
704 iptables_save_line(iptablespreamble, TRUE);\r
705 iptables_save_line(ip6preamble, TRUE);\r
706 }\r
707\r
708 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */\r
709 {\r
710 char *chain;\r
711 \r
712 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
713 iptables_save_line(str, FALSE); /* this is currently supported only for IPv4 */\r
714 \r
715/*\r
716 if(qos_proxy)\r
717 {\r
718 iptables_save_line(":post_noproxy - [0:0]", FALSE);\r
719 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);\r
720 iptables_save_line(str , FALSE);\r
721 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);\r
722 iptables_save_line(str, FALSE);\r
723 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
724 iptables_save_line(str, FALSE);\r
725\r
726 chain="post_noproxy"; \r
727 }\r
728\r
729 else\r
730 {\r
731*/\r
732 chain = "POSTROUTING";\r
733// }\r
734 \r
735 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
736 iptables_save_line(str, FALSE);\r
737 }\r
738 \r
739 if(ip_count > idxtable_treshold1 && !just_flush)\r
740 {\r
741 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
742 char *subnet, *buf;\r
743 /*-----------------------------------------------------------------*/\r
744 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
745 /*-----------------------------------------------------------------*/\r
746\r
747 iptables_save_line(":post_common - [0:0]", FALSE);\r
748 iptables_save_line(":forw_common - [0:0]", FALSE);\r
749 if(ip6prefix)\r
750 {\r
751 iptables_save_line(":post_common - [0:0]", TRUE);\r
752 iptables_save_line(":forw_common - [0:0]", TRUE);\r
753 }\r
754\r
755 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
756 {\r
757 if(ip->v6)\r
758 {\r
759 buf=index6_id(ip->addr,bitmask+32);\r
760 }\r
761 else\r
762 {\r
763 buf=index_id(ip->addr, bitmask);\r
764 }\r
765 \r
766 if_exists(idx,idxs,eq(idx->id,buf))\r
767 {\r
768 idx->children++;\r
769 }\r
770 else\r
771 {\r
772 create(idx,Index);\r
773 idx->addr = ip->addr;\r
774 idx->id = buf;\r
775 idx->bitmask = bitmask+32*ip->v6;\r
776 idx->parent = NULL;\r
777 idx->children = 0;\r
778 idx->ipv6 = ip->v6;\r
779 idxcount++;\r
780 push(idx,idxs);\r
781 }\r
782 }\r
783\r
784 /* brutal perfomance optimalization */\r
785 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
786 {\r
787 bitmask -= idxtable_bitmask2;\r
788 idxcount = 0;\r
789\r
790 for_each(idx,idxs) if(idx->parent == NULL)\r
791 {\r
792 if(idx->ipv6)\r
793 {\r
794 buf = index6_id(idx->addr, bitmask+32);\r
795 }\r
796 else\r
797 {\r
798 buf = index_id(idx->addr, bitmask);\r
799 }\r
800 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
801 {\r
802 metaindex->children++;\r
803 }\r
804 else\r
805 {\r
806 create(metaindex,Index);\r
807 metaindex->addr = idx->addr;\r
808 metaindex->id = buf;\r
809 metaindex->bitmask = bitmask+32*idx->ipv6;\r
810 metaindex->parent = NULL;\r
811 metaindex->children = 0;\r
812 metaindex->ipv6 = idx->ipv6;\r
813 idxcount++;\r
814 push(metaindex,idxs);\r
815 }\r
816 idx->parent=metaindex;\r
817 }\r
818 }\r
819\r
820 /* this should slightly optimize throughput ... */\r
821 sort(idx,idxs,desc_order_by,children);\r
822 sort(idx,idxs,order_by,bitmask);\r
823\r
824 i=0;\r
825 for_each(idx,idxs)\r
826 {\r
827 if(idx->ipv6)\r
828 {\r
829 subnet=subnet6_id(idx->addr, idx->bitmask);\r
830 }\r
831 else\r
832 {\r
833 subnet=subnet_id(idx->addr, idx->bitmask);\r
834 }\r
835 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
836 \r
837 sprintf(str,":post_%s - [0:0]", idx->id);\r
838 iptables_save_line(str, idx->ipv6);\r
839\r
840 sprintf(str,":forw_%s - [0:0]", idx->id);\r
841 iptables_save_line(str, idx->ipv6);\r
842\r
843 if(idx->parent)\r
844 {\r
845 string(buf,strlen(idx->parent->id)+6);\r
846 sprintf(buf,"post_%s", idx->parent->id);\r
847 }\r
848 else\r
849 {\r
850 buf="POSTROUTING";\r
851 }\r
852\r
853 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
854 iptables_save_line(str, idx->ipv6);\r
855\r
856 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
857 iptables_save_line(str, idx->ipv6);\r
858\r
859 if(idx->parent)\r
860 {\r
861 string(buf,strlen(idx->parent->id)+6);\r
862 sprintf(buf,"forw_%s",idx->parent->id);\r
863 }\r
864 else\r
865 {\r
866 buf="FORWARD";\r
867 }\r
868\r
869 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
870 iptables_save_line(str, idx->ipv6);\r
871\r
872 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
873 iptables_save_line(str, idx->ipv6);\r
874 }\r
875 printf("Total indexed iptables chains created: %d\n", i);\r
876\r
877 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
878 iptables_save_line(str, FALSE);\r
879 \r
880 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
881 iptables_save_line(str, FALSE);\r
882\r
883 if(ip6prefix)\r
884 {\r
885 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
886 iptables_save_line(str, TRUE);\r
887 \r
888 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
889 iptables_save_line(str, TRUE);\r
890 }\r
891 }\r
892 }\r
893\r
894 if(just_flush)\r
895 {\r
896 fclose(iptables_file);\r
897 if(log_file)\r
898 { \r
899 fclose(log_file);\r
900 }\r
901 puts("Just flushed iptables and tc classes - now exiting ...");\r
902 exit(0);\r
903 }\r
904\r
905 if(!just_preview)\r
906 {\r
907 if(!dry_run && !nodelay && qos_free_delay)\r
908 {\r
909 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
910 sleep(qos_free_delay);\r
911 }\r
912\r
913 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
914 tc,lan,htb_r2q);\r
915 safe_run(str);\r
916\r
917 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
918 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);\r
919 safe_run(str);\r
920\r
921 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
922 tc,lan,line,line,burst_main,highest_priority);\r
923 safe_run(str);\r
924\r
925 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
926 safe_run(str);\r
927\r
928 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
929 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);\r
930 safe_run(str);\r
931\r
932 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
933 tc,wan,up,up,burst_main,highest_priority);\r
934 safe_run(str);\r
935 }\r
936\r
937 /*-----------------------------------------------------------------*/\r
938 puts("Locating heavy downloaders and generating root classes ...");\r
939 /*-----------------------------------------------------------------*/\r
940 sort(ip,ips,desc_order_by,traffic); \r
941\r
942 /*-----------------------------------------------------------------*/\r
943 /* sub-scope - local variables */ \r
944 {\r
945 long long int rate = line;\r
946 long long int max = line;\r
947 int group_count = 0;\r
948 FILE *credit_file = NULL;\r
949 \r
950 if(!just_preview && !dry_run && enable_credit)\r
951 {\r
952 credit_file = fopen(credit,"w");\r
953 }\r
954 \r
955 for_each(group,groups)\r
956 {\r
957 if(!just_preview)\r
958 {\r
959 //download\r
960 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
961 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
962 safe_run(str);\r
963 \r
964 //upload\r
965 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
966 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);\r
967 safe_run(str);\r
968 }\r
969 \r
970 if(group_count++ < max_nesting)\r
971 {\r
972 parent = group->id;\r
973 }\r
974 \r
975 rate -= digital_divide*group->min;\r
976 if(rate < group->min)\r
977 {\r
978 rate = group->min;\r
979 }\r
980 \r
981 /*shaping of aggresive downloaders, with credit file support */\r
982 if(use_credit)\r
983 {\r
984 int group_rate = group->min, priority_sequence = lowest_priority;\r
985 \r
986 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
987 {\r
988 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
989 if( ip->keyword->data_limit \r
990 and not ip->fixedprio \r
991 and ip->traffic > ip->realquota )\r
992 {\r
993 if(group_rate < ip->max)\r
994 {\r
995 ip->max = group_rate;\r
996 }\r
997 group_rate+=magic_treshold;\r
998 ip->prio=lowest_priority;\r
999 if(ip->prio<highest_priority+2)\r
1000 {\r
1001 ip->prio=highest_priority+2;\r
1002 }\r
1003 }\r
1004 else\r
1005 {\r
1006 if( ip->keyword->data_prio \r
1007 && !ip->fixedprio \r
1008 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
1009 {\r
1010 ip->prio=priority_sequence--;\r
1011 if(ip->prio<highest_priority+1)\r
1012 {\r
1013 ip->prio=highest_priority+1;\r
1014 }\r
1015 }\r
1016 \r
1017 if(credit_file)\r
1018 {\r
1019 unsigned long long lcredit=0;\r
1020 \r
1021 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1022 {\r
1023 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1024 }\r
1025 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1026 }\r
1027 }\r
1028 } \r
1029 }\r
1030 }\r
1031 if(credit_file)\r
1032 {\r
1033 fclose(credit_file);\r
1034 }\r
1035 }\r
1036\r
1037 if(just_preview)\r
1038 {\r
1039 if(start_shaping || stop_shaping || reduce_ceil)\r
1040 {\r
1041 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1042 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1043 \r
1044 parse(classmap)\r
1045 {\r
1046 ptr=strchr(_,' ');\r
1047 if(ptr)\r
1048 {\r
1049 *ptr=0;\r
1050 ptr++;\r
1051 if_exists(ip,ips,eq(ip->addr,_))\r
1052 {\r
1053 int unshape_this_ip = stop_shaping;\r
1054 long avg_mbps_down = ip->direct * 8 / how_much_seconds;\r
1055 long avg_mbps_up = ip->upload * 8 / how_much_seconds;\r
1056 int min_mbps = ip->min>>10;\r
1057 int agreg = 1, print_stats = 1;\r
1058 \r
1059 if(min_mbps < 1)\r
1060 {\r
1061 min_mbps = 1;\r
1062 }\r
1063 \r
1064 if(ip->keyword->download_aggregation)\r
1065 {\r
1066 if(min_mbps <= avg_mbps_down)\r
1067 {\r
1068 unshape_this_ip = 0;\r
1069 agreg = (avg_mbps_down+1)/min_mbps;\r
1070 ip->max /= agreg;\r
1071 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
1072 }\r
1073 else\r
1074 {\r
1075 unshape_this_ip = 1;\r
1076 }\r
1077 }\r
1078 else if(ip->keyword->upload_aggregation)\r
1079 {\r
1080 if(min_mbps <= avg_mbps_up)\r
1081 {\r
1082 unshape_this_ip = 0;\r
1083 agreg = (avg_mbps_up+1)/min_mbps;\r
1084 ip->max /= agreg;\r
1085 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
1086 }\r
1087 else\r
1088 {\r
1089 unshape_this_ip = 1;\r
1090 }\r
1091 }\r
1092 ip->mark=atoi(ptr);\r
1093 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
1094 {\r
1095 if(unshape_this_ip)\r
1096 {\r
1097 ip->max = ip->desired;\r
1098 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1099 {\r
1100 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1101 }\r
1102 else\r
1103 {\r
1104 print_stats = 0;\r
1105 }\r
1106 }\r
1107 else\r
1108 {\r
1109 printf("Applying limit for %s (%s) ", ip->name, ip->addr);\r
1110 if(reduce_ceil)\r
1111 {\r
1112 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1113 }\r
1114 else if(ip->max < ip->min)\r
1115 {\r
1116 ip->max = ip->min;\r
1117 } \r
1118 }\r
1119 if(print_stats)\r
1120 {\r
1121 printf("(down: %dk-%dk wants %dk, ", ip->min, ip->max, ip->desired);\r
1122 }\r
1123 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1124 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);\r
1125 safe_run(str);\r
1126 if(print_stats)\r
1127 {\r
1128 printf("up: %dk-%dk wants %dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1129 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1130 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1131 }\r
1132 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1133 tc, wan, ip->group, ip->mark,\r
1134 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1135 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1136 safe_run(str);\r
1137 }\r
1138 }\r
1139 }\r
1140 }\r
1141 fail\r
1142 { \r
1143 perror(classmap);\r
1144 puts("Warning - classmap file not fund, just generating preview ...");\r
1145 start_shaping=FALSE;\r
1146 stop_shaping=FALSE;\r
1147 }\r
1148 done; /* ugly macro end */\r
1149 }\r
1150 html=preview;\r
1151 json_traffic=json_preview;\r
1152 }\r
1153\r
1154 if(!dry_run && !just_flush)\r
1155 {\r
1156 /*-----------------------------------------------------------------*/\r
1157 printf("Writing json traffic overview %s ... ", json_traffic);\r
1158 /*-----------------------------------------------------------------*/\r
1159 write_json_traffic(json_traffic);\r
1160\r
1161 /*-----------------------------------------------------------------*/\r
1162 printf("Writing statistics into HTML page %s ...\n", html);\r
1163 /*-----------------------------------------------------------------*/\r
1164 write_htmlandlogs(html, d, total, just_preview);\r
1165 }\r
1166\r
1167 if(just_preview)\r
1168 {\r
1169 char swchar='p';\r
1170 if(start_shaping)\r
1171 {\r
1172 swchar='s';\r
1173 }\r
1174 else if(reduce_ceil)\r
1175 {\r
1176 swchar='0'+reduce_ceil; /* -2, -4 */\r
1177 }\r
1178 else if(stop_shaping)\r
1179 {\r
1180 swchar='q';\r
1181 }\r
1182\r
1183 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
1184 exit(0);\r
1185 } \r
1186\r
1187 i=0;\r
1188#ifdef DEBUG\r
1189 printf("%-22s %-15s mark\n","name","ip");\r
1190#endif\r
1191\r
1192 printf("Writing %s", classmap); \r
1193 f = fopen(classmap, "w"); \r
1194 if(f < 0)\r
1195 {\r
1196 perror(classmap);\r
1197 }\r
1198\r
1199 /*-----------------------------------------------------------------*/\r
1200 printf(" + generating iptables and tc classes ... ");\r
1201 /*-----------------------------------------------------------------*/\r
1202\r
1203 for_each(ip, ips) if(ip->mark > 0) /* works only for IPv4 so far */\r
1204 {\r
1205 if(idxs)\r
1206 {\r
1207 char *buf;\r
1208 duplicate(ip->addr,buf);\r
1209 if(ip->v6)\r
1210 {\r
1211 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1212 }\r
1213 else\r
1214 {\r
1215 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1216 }\r
1217 \r
1218 string(chain_forward,6+strlen(buf));\r
1219 strcpy(chain_forward,"forw_");\r
1220 strcat(chain_forward,buf);\r
1221\r
1222 string(chain_postrouting,6+strlen(buf));\r
1223 strcpy(chain_postrouting,"post_");\r
1224 strcat(chain_postrouting,buf);\r
1225 \r
1226 free(buf);\r
1227 }\r
1228 else\r
1229 {\r
1230 chain_forward="FORWARD";\r
1231 chain_postrouting="POSTROUTING";\r
1232 }\r
1233\r
1234 /* packet limits - this will be optional in future */\r
1235 if(ip->pps_limit)\r
1236 {\r
1237 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1238 ip->pps_limit, ip->pps_limit);\r
1239 }\r
1240 else\r
1241 {\r
1242 *limit_pkts = 0;\r
1243 } \r
1244\r
1245#ifdef DEBUG\r
1246 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1247#endif\r
1248\r
1249 /* -------------------------------------------------------- mark download */ \r
1250 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1251 chain_postrouting, ip->addr, ip->mask,\r
1252 lan, mark_iptables, ip->mark);\r
1253 iptables_save_line(str, ip->v6);\r
1254\r
1255/*\r
1256 if(qos_proxy)\r
1257 {\r
1258 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/%d -o %s -j %s%d",\r
1259 chain_postrouting, proxy_ip, proxy_port, ip->addr,\r
1260 ip->mask, lan, mark_iptables, ip->mark);\r
1261 iptables_save_line(str, ip->v6);\r
1262 }\r
1263*/\r
1264 sprintf(str, "-A %s -d %s/%d -o %s %s-j ACCEPT",\r
1265 chain_postrouting, ip->addr, ip->mask, lan, limit_pkts);\r
1266 iptables_save_line(str, ip->v6);\r
1267\r
1268 /* classify overlimit packets to separate overlimit class */\r
1269 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1270 chain_postrouting, ip->addr, ip->mask,\r
1271 lan, mark_iptables, OVERLIMIT_CLASS);\r
1272 iptables_save_line(str, ip->v6);\r
1273\r
1274 sprintf(str, "-A %s -d %s/%d -o %s -j ACCEPT",\r
1275 chain_postrouting, ip->addr, ip->mask, lan);\r
1276 iptables_save_line(str, ip->v6);\r
1277\r
1278 /* -------------------------------------------------------- mark upload */\r
1279 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1280 chain_forward, ip->addr, ip->mask, wan, mark_iptables, ip->mark);\r
1281 iptables_save_line(str, ip->v6);\r
1282\r
1283 sprintf(str, "-A %s -s %s/%d -o %s %s-j ACCEPT",\r
1284 chain_forward, ip->addr, ip->mask, wan, limit_pkts);\r
1285 iptables_save_line(str, ip->v6);\r
1286\r
1287 /* classify overlimit packets to separate overlimit class */\r
1288 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1289 chain_forward, ip->addr, ip->mask, wan, mark_iptables, OVERLIMIT_CLASS);\r
1290 iptables_save_line(str, ip->v6);\r
1291\r
1292 sprintf(str, "-A %s -s %s/%d -o %s -j ACCEPT",\r
1293 chain_forward, ip->addr, ip->mask, wan);\r
1294 iptables_save_line(str, ip->v6);\r
1295\r
1296 if(ip->min)\r
1297 {\r
1298 /* -------------------------------------------------------- download class */\r
1299#ifdef DEBUG\r
1300 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1301#endif\r
1302\r
1303 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1304 tc, lan, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
1305 safe_run(str);\r
1306\r
1307 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1308 {\r
1309 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1310 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1311 safe_run(str);\r
1312 }\r
1313\r
1314 if(filter_type == 1)\r
1315 {\r
1316 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1317 tc, lan, ip->mark, ip->mark);\r
1318 safe_run(str);\r
1319 }\r
1320\r
1321 /* -------------------------------------------------------- upload class */\r
1322#ifdef DEBUG\r
1323 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1324 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1325#endif\r
1326\r
1327 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1328 tc, wan, ip->group, ip->mark,\r
1329 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1330 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1331 safe_run(str);\r
1332 \r
1333 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1334 {\r
1335 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",\r
1336 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1337 safe_run(str);\r
1338 } \r
1339\r
1340 if(filter_type == 1)\r
1341 {\r
1342 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1343 tc, wan, ip->mark, ip->mark);\r
1344 safe_run(str);\r
1345 }\r
1346 \r
1347 if(f > 0)\r
1348 {\r
1349 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
1350 }\r
1351 }\r
1352 else\r
1353 {\r
1354#ifdef DEBUG\r
1355 printf("(sharing %s)\n", ip->sharing);\r
1356#endif\r
1357 }\r
1358 i++;\r
1359 }\r
1360 if(f > 0)\r
1361 {\r
1362 puts("done.");\r
1363 fclose(f);\r
1364 }\r
1365 \r
1366 if(idxs)\r
1367 {\r
1368 chain_forward = "forw_common";\r
1369 chain_postrouting = "post_common";\r
1370 }\r
1371 else\r
1372 {\r
1373 chain_forward = "FORWARD";\r
1374 chain_postrouting = "POSTROUTING";\r
1375 }\r
1376\r
1377 if(free_min)\r
1378 {\r
1379 final_chain = "ACCEPT";\r
1380 }\r
1381\r
1382/*\r
1383 if(qos_proxy)\r
1384 {\r
1385 if(free_min) \r
1386 {\r
1387 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s%d",\r
1388 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables, 3);\r
1389 iptables_save_line(str, FALSE); // only for IPv4\r
1390 }\r
1391 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s",\r
1392 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);\r
1393 iptables_save_line(str, FALSE); // only for IPv4\r
1394 }\r
1395*/\r
1396\r
1397 if(free_min)\r
1398 {\r
1399 sprintf(str, "-A %s -o %s -j %s%d",\r
1400 chain_postrouting, lan, mark_iptables, FREE_CLASS);\r
1401 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1402 }\r
1403\r
1404 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1405 iptables_save_line(str, FALSE);\r
1406 if(ip6prefix)\r
1407 {\r
1408 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1409 iptables_save_line(str, TRUE);\r
1410 }\r
1411\r
1412 if(free_min)\r
1413 {\r
1414 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, FREE_CLASS);\r
1415 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1416 }\r
1417\r
1418 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);\r
1419 iptables_save_line(str, FALSE);\r
1420 if(ip6prefix)\r
1421 {\r
1422 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1423 iptables_save_line(str, TRUE);\r
1424 }\r
1425\r
1426 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1427 {\r
1428 /*-----------------------------------------------------------------*/\r
1429 puts("Generating free bandwith class ...");\r
1430 /*-----------------------------------------------------------------*/\r
1431 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1432 tc, lan, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority);\r
1433 safe_run(str);\r
1434 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1435 tc, wan, parent, FREE_CLASS, free_min, free_max, burst, lowest_priority);\r
1436 safe_run(str);\r
1437 /* tc SFQ */\r
1438 if(strcmpi(qos_leaf, "none"))\r
1439 {\r
1440 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1441 safe_run(str);\r
1442 \r
1443 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, wan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1444 safe_run(str);\r
1445 } \r
1446 /* tc handle 1 fw flowid */\r
1447 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, lan, FREE_CLASS, FREE_CLASS);\r
1448 safe_run(str);\r
1449\r
1450 sprintf(str,"%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d", tc, wan, FREE_CLASS, FREE_CLASS);\r
1451 safe_run(str);\r
1452\r
1453 /*-----------------------------------------------------------------*/\r
1454 puts("Generating bandwith class for overlimit packets...");\r
1455 /*-----------------------------------------------------------------*/\r
1456 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1457 tc, lan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1458 safe_run(str);\r
1459 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1460 tc, wan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1461 safe_run(str);\r
1462 }\r
1463 printf("Total IP count: %d\n", i);\r
1464 run_iptables_restore();\r
1465 if(log_file)\r
1466 {\r
1467 fclose(log_file);\r
1468 }\r
1469 return 0;\r
1470 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1471 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1472}\r
This page took 0.257805 seconds and 4 git commands to generate.