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