digital-divide, total avg.speed was nonsense
[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, 20160622\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-e";\r
33\r
34/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\r
35/* Versions: 0.8.5 is development release, 0.8.6 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 ioption("digital-divide-weirdness-ratio",digital_divide);\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 sharedip->traffic_down += ip->direct;\r
609 sharedip->traffic_up += ip->upload;\r
610 ip->traffic = 0;\r
611 ip->mark = sharedip->mark; \r
612 ip->lmsid = sharedip->lmsid;\r
613 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
614\r
615 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
616 ptr = strchr(ip->addr, '+');\r
617 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
618 {\r
619 *(--ptr) = 0;\r
620 concatenate(ip->addr, sharedip->addr, ptr);\r
621 ip->name = ip->addr = ptr;\r
622 ptr = strchr(ip->addr, '.');\r
623 while(ptr && *ptr)\r
624 {\r
625 *ptr = ':';\r
626 ptr = strchr(ptr, '.');\r
627 }\r
628 ip->mask += 64;\r
629 }\r
630\r
631 break;\r
632 }\r
633 if(not sharedip)\r
634 {\r
635 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
636 ip->addr, ip->name, ip->sharing);\r
637 }\r
638 }\r
639\r
640 if(enable_credit && just_flush<9)\r
641 {\r
642 /*-----------------------------------------------------------------*/\r
643 printf("Parsing credit file %s ...\n", credit);\r
644 /*-----------------------------------------------------------------*/\r
645 parse(credit)\r
646 {\r
647 ptr = parse_datafile_line(_);\r
648 if(ptr)\r
649 {\r
650 if_exists(ip,ips,eq(ip->addr,_))\r
651 {\r
652 sscanf(ptr,"%Lu",&(ip->credit));\r
653 }\r
654 }\r
655 }\r
656 done; /* ugly macro end */\r
657 }\r
658\r
659\r
660 if(!just_preview)\r
661 {\r
662 /*-----------------------------------------------------------------*/\r
663 puts("Initializing iptables and tc classes ...");\r
664 /*-----------------------------------------------------------------*/\r
665 \r
666 iptables_file = fopen(iptablesfile, "w");\r
667 if(iptables_file == NULL)\r
668 {\r
669 perror(iptablesfile);\r
670 exit(-1);\r
671 }\r
672 iptables_save_line(iptablespreamble, FALSE);\r
673\r
674 if(ip6prefix)\r
675 {\r
676 ip6tables_file = fopen(ip6tablesfile, "w");\r
677 if(ip6tables_file == NULL)\r
678 {\r
679 perror(ip6tablesfile);\r
680 exit(-1);\r
681 }\r
682 iptables_save_line(iptablespreamble, TRUE);\r
683 iptables_save_line(ip6preamble, TRUE);\r
684 }\r
685\r
686 run_iptables_restore();\r
687 \r
688 log_file = fopen(cmdlog, "w");\r
689 if(log_file == NULL) \r
690 {\r
691 perror(cmdlog);\r
692 exit(-1);\r
693 } \r
694 \r
695 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,lan);\r
696 safe_run(str);\r
697\r
698 sprintf(str,"%s qdisc del dev %s root 2>/dev/null",tc,wan);\r
699 safe_run(str);\r
700 \r
701 iptables_file=fopen(iptablesfile,"w");\r
702 iptables_save_line(iptablespreamble, FALSE);\r
703 if(ip6prefix)\r
704 {\r
705 ip6tables_file=fopen(ip6tablesfile,"w");\r
706 iptables_save_line(iptablespreamble, TRUE);\r
707 iptables_save_line(ip6preamble, TRUE);\r
708 }\r
709\r
710 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */\r
711 {\r
712 char *chain;\r
713 \r
714 sprintf(str,"-A FORWARD -d %s -o %s -j ACCEPT", qos_free_zone, wan);\r
715 iptables_save_line(str, FALSE); /* this is currently supported only for IPv4 */\r
716 \r
717/*\r
718 if(qos_proxy)\r
719 {\r
720 iptables_save_line(":post_noproxy - [0:0]", FALSE);\r
721 sprintf(str,"-A POSTROUTING ! -p tcp -o %s -j post_noproxy", lan);\r
722 iptables_save_line(str , FALSE);\r
723 sprintf(str,"-A POSTROUTING ! -s %s -o %s -j post_noproxy", proxy_ip, lan);\r
724 iptables_save_line(str, FALSE);\r
725 sprintf(str,"-A POSTROUTING -s %s -p tcp ! --sport %d -o %s -j post_noproxy", proxy_ip, proxy_port, lan);\r
726 iptables_save_line(str, FALSE);\r
727\r
728 chain="post_noproxy"; \r
729 }\r
730\r
731 else\r
732 {\r
733*/\r
734 chain = "POSTROUTING";\r
735// }\r
736 \r
737 sprintf(str,"-A %s -s %s -o %s -j ACCEPT", chain, qos_free_zone, lan);\r
738 iptables_save_line(str, FALSE);\r
739 }\r
740 \r
741 if(ip_count > idxtable_treshold1 && !just_flush)\r
742 {\r
743 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
744 char *subnet, *buf;\r
745 /*-----------------------------------------------------------------*/\r
746 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
747 /*-----------------------------------------------------------------*/\r
748\r
749 iptables_save_line(":post_common - [0:0]", FALSE);\r
750 iptables_save_line(":forw_common - [0:0]", FALSE);\r
751 if(ip6prefix)\r
752 {\r
753 iptables_save_line(":post_common - [0:0]", TRUE);\r
754 iptables_save_line(":forw_common - [0:0]", TRUE);\r
755 }\r
756\r
757 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
758 {\r
759 if(ip->v6)\r
760 {\r
761 buf=index6_id(ip->addr,bitmask+32);\r
762 }\r
763 else\r
764 {\r
765 buf=index_id(ip->addr, bitmask);\r
766 }\r
767 \r
768 if_exists(idx,idxs,eq(idx->id,buf))\r
769 {\r
770 idx->children++;\r
771 }\r
772 else\r
773 {\r
774 create(idx,Index);\r
775 idx->addr = ip->addr;\r
776 idx->id = buf;\r
777 idx->bitmask = bitmask+32*ip->v6;\r
778 idx->parent = NULL;\r
779 idx->children = 0;\r
780 idx->ipv6 = ip->v6;\r
781 idxcount++;\r
782 push(idx,idxs);\r
783 }\r
784 }\r
785\r
786 /* brutal perfomance optimalization */\r
787 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
788 {\r
789 bitmask -= idxtable_bitmask2;\r
790 idxcount = 0;\r
791\r
792 for_each(idx,idxs) if(idx->parent == NULL)\r
793 {\r
794 if(idx->ipv6)\r
795 {\r
796 buf = index6_id(idx->addr, bitmask+32);\r
797 }\r
798 else\r
799 {\r
800 buf = index_id(idx->addr, bitmask);\r
801 }\r
802 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
803 {\r
804 metaindex->children++;\r
805 }\r
806 else\r
807 {\r
808 create(metaindex,Index);\r
809 metaindex->addr = idx->addr;\r
810 metaindex->id = buf;\r
811 metaindex->bitmask = bitmask+32*idx->ipv6;\r
812 metaindex->parent = NULL;\r
813 metaindex->children = 0;\r
814 metaindex->ipv6 = idx->ipv6;\r
815 idxcount++;\r
816 push(metaindex,idxs);\r
817 }\r
818 idx->parent=metaindex;\r
819 }\r
820 }\r
821\r
822 /* this should slightly optimize throughput ... */\r
823 sort(idx,idxs,desc_order_by,children);\r
824 sort(idx,idxs,order_by,bitmask);\r
825\r
826 i=0;\r
827 for_each(idx,idxs)\r
828 {\r
829 if(idx->ipv6)\r
830 {\r
831 subnet=subnet6_id(idx->addr, idx->bitmask);\r
832 }\r
833 else\r
834 {\r
835 subnet=subnet_id(idx->addr, idx->bitmask);\r
836 }\r
837 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
838 \r
839 sprintf(str,":post_%s - [0:0]", idx->id);\r
840 iptables_save_line(str, idx->ipv6);\r
841\r
842 sprintf(str,":forw_%s - [0:0]", idx->id);\r
843 iptables_save_line(str, idx->ipv6);\r
844\r
845 if(idx->parent)\r
846 {\r
847 string(buf,strlen(idx->parent->id)+6);\r
848 sprintf(buf,"post_%s", idx->parent->id);\r
849 }\r
850 else\r
851 {\r
852 buf="POSTROUTING";\r
853 }\r
854\r
855 sprintf(str,"-A %s -d %s/%d -o %s -j post_%s", buf, subnet, idx->bitmask, lan, idx->id);\r
856 iptables_save_line(str, idx->ipv6);\r
857\r
858 sprintf(str,"-A %s -d %s/%d -o %s -j post_common", buf, subnet, idx->bitmask, lan);\r
859 iptables_save_line(str, idx->ipv6);\r
860\r
861 if(idx->parent)\r
862 {\r
863 string(buf,strlen(idx->parent->id)+6);\r
864 sprintf(buf,"forw_%s",idx->parent->id);\r
865 }\r
866 else\r
867 {\r
868 buf="FORWARD";\r
869 }\r
870\r
871 sprintf(str,"-A %s -s %s/%d -o %s -j forw_%s", buf, subnet, idx->bitmask, wan, idx->id);\r
872 iptables_save_line(str, idx->ipv6);\r
873\r
874 sprintf(str,"-A %s -s %s/%d -o %s -j forw_common", buf, subnet, idx->bitmask, wan);\r
875 iptables_save_line(str, idx->ipv6);\r
876 }\r
877 printf("Total indexed iptables chains created: %d\n", i);\r
878\r
879 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
880 iptables_save_line(str, FALSE);\r
881 \r
882 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
883 iptables_save_line(str, FALSE);\r
884\r
885 if(ip6prefix)\r
886 {\r
887 sprintf(str,"-A FORWARD -o %s -j forw_common", wan);\r
888 iptables_save_line(str, TRUE);\r
889 \r
890 sprintf(str,"-A POSTROUTING -o %s -j post_common", lan);\r
891 iptables_save_line(str, TRUE);\r
892 }\r
893 }\r
894 }\r
895\r
896 if(just_flush)\r
897 {\r
898 fclose(iptables_file);\r
899 if(log_file)\r
900 { \r
901 fclose(log_file);\r
902 }\r
903 puts("Just flushed iptables and tc classes - now exiting ...");\r
904 exit(0);\r
905 }\r
906\r
907 if(!just_preview)\r
908 {\r
909 if(!dry_run && !nodelay && qos_free_delay)\r
910 {\r
911 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n",qos_free_delay);\r
912 sleep(qos_free_delay);\r
913 }\r
914\r
915 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
916 tc,lan,htb_r2q);\r
917 safe_run(str);\r
918\r
919 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
920 tc,lan,lan_medium,lan_medium,burst_main,highest_priority);\r
921 safe_run(str);\r
922\r
923 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
924 tc,lan,line,line,burst_main,highest_priority);\r
925 safe_run(str);\r
926\r
927 sprintf(str,"%s qdisc add dev %s root handle 1: htb r2q %d default 1",tc,wan,htb_r2q);\r
928 safe_run(str);\r
929\r
930 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
931 tc,wan,wan_medium,wan_medium,burst_main,highest_priority);\r
932 safe_run(str);\r
933\r
934 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
935 tc,wan,up,up,burst_main,highest_priority);\r
936 safe_run(str);\r
937 }\r
938\r
939 /*-----------------------------------------------------------------*/\r
940 puts("Locating heavy downloaders and generating root classes ...");\r
941 /*-----------------------------------------------------------------*/\r
942 sort(ip,ips,desc_order_by,traffic); \r
943\r
944 /*-----------------------------------------------------------------*/\r
945 /* sub-scope - local variables */ \r
946 {\r
947 long long int rate = line;\r
948 long long int max = line;\r
949 int group_count = 0;\r
950 FILE *credit_file = NULL;\r
951 \r
952 if(!just_preview && !dry_run && enable_credit)\r
953 {\r
954 credit_file = fopen(credit,"w");\r
955 }\r
956 \r
957 for_each(group,groups)\r
958 {\r
959 if(!just_preview)\r
960 {\r
961 //download\r
962 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
963 tc, lan, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
964 safe_run(str);\r
965 \r
966 //upload\r
967 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
968 tc, wan, parent, group->id, rate*up/line, max*up/line, burst_group, highest_priority+1, group->desired);\r
969 safe_run(str);\r
970 }\r
971 \r
972 if(group_count++ < max_nesting)\r
973 {\r
974 parent = group->id;\r
975 }\r
976 \r
977 rate -= digital_divide*group->min;\r
978 if(rate < group->min)\r
979 {\r
980 rate = group->min;\r
981 }\r
982 \r
983 /*shaping of aggresive downloaders, with credit file support */\r
984 if(use_credit)\r
985 {\r
986 int group_rate = group->min, priority_sequence = lowest_priority;\r
987 \r
988 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
989 {\r
990 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
991 if( ip->keyword->data_limit \r
992 and not ip->fixedprio \r
993 and ip->traffic > ip->realquota )\r
994 {\r
995 if(group_rate < ip->max)\r
996 {\r
997 ip->max = group_rate;\r
998 }\r
999 group_rate+=magic_treshold;\r
1000 ip->prio=lowest_priority;\r
1001 if(ip->prio<highest_priority+2)\r
1002 {\r
1003 ip->prio=highest_priority+2;\r
1004 }\r
1005 }\r
1006 else\r
1007 {\r
1008 if( ip->keyword->data_prio \r
1009 && !ip->fixedprio \r
1010 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
1011 {\r
1012 ip->prio=priority_sequence--;\r
1013 if(ip->prio<highest_priority+1)\r
1014 {\r
1015 ip->prio=highest_priority+1;\r
1016 }\r
1017 }\r
1018 \r
1019 if(credit_file)\r
1020 {\r
1021 unsigned long long lcredit=0;\r
1022 \r
1023 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1024 {\r
1025 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
1026 }\r
1027 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1028 }\r
1029 }\r
1030 } \r
1031 }\r
1032 }\r
1033 if(credit_file)\r
1034 {\r
1035 fclose(credit_file);\r
1036 }\r
1037 }\r
1038\r
1039 if(just_preview)\r
1040 {\r
1041 if(start_shaping || stop_shaping || reduce_ceil)\r
1042 {\r
1043 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1044 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1045 \r
1046 parse(classmap)\r
1047 {\r
1048 ptr=strchr(_,' ');\r
1049 if(ptr)\r
1050 {\r
1051 *ptr=0;\r
1052 ptr++;\r
1053 if_exists(ip,ips,eq(ip->addr,_))\r
1054 {\r
1055 int unshape_this_ip = 0;\r
1056 long avg_mbps_down = ip->traffic_down * 8 / how_much_seconds; \r
1057 long avg_mbps_up = ip->traffic_up * 8 / how_much_seconds;\r
1058 int agreg = 1, print_stats = 1;\r
1059 \r
1060 if(ip->keyword->download_aggregation)\r
1061 {\r
1062 int min_mbps = (ip->min/ip->keyword->download_aggregation)>>10;\r
1063 if(min_mbps < 1)\r
1064 {\r
1065 min_mbps = 1;\r
1066 }\r
1067 \r
1068 if(min_mbps <= avg_mbps_down)\r
1069 {\r
1070 unshape_this_ip = 0;\r
1071 agreg = (int)((float)(avg_mbps_down+1)/min_mbps+.5);\r
1072 ip->max /= agreg;\r
1073 ip->pps_limit /= agreg;\r
1074 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
1075 }\r
1076 else\r
1077 {\r
1078 unshape_this_ip = 1;\r
1079 }\r
1080 }\r
1081 else if(ip->keyword->upload_aggregation)\r
1082 {\r
1083 int min_mbps = (ip->min/ip->keyword->upload_aggregation)>>10;\r
1084 if(min_mbps < 1)\r
1085 {\r
1086 min_mbps = 1;\r
1087 }\r
1088\r
1089 if(min_mbps <= avg_mbps_up)\r
1090 {\r
1091 unshape_this_ip = 0;\r
1092 agreg = (int)((float)(avg_mbps_up+1)/min_mbps+.5);\r
1093 ip->max /= agreg;\r
1094 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
1095 }\r
1096 else\r
1097 {\r
1098 unshape_this_ip = 1;\r
1099 }\r
1100 }\r
1101 if(stop_shaping)\r
1102 {\r
1103 unshape_this_ip = 1;\r
1104 }\r
1105 ip->aggregated = agreg; \r
1106 ip->mark = atoi(ptr);\r
1107 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
1108 {\r
1109 if(unshape_this_ip)\r
1110 {\r
1111 ip->max = ip->desired;\r
1112 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1113 {\r
1114 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1115 }\r
1116 else\r
1117 {\r
1118 print_stats = 0;\r
1119 }\r
1120 }\r
1121 else\r
1122 {\r
1123 printf("Applying limit for %s (%s) ", ip->name, ip->addr);\r
1124 if(reduce_ceil)\r
1125 {\r
1126 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1127 }\r
1128 else if(ip->max < ip->min)\r
1129 {\r
1130 ip->max = ip->min;\r
1131 } \r
1132 }\r
1133 if(print_stats)\r
1134 {\r
1135 printf("(down: %dk-%dk wants %dk, ", ip->min, ip->max, ip->desired);\r
1136 }\r
1137 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1138 tc, lan, ip->group, ip->mark,ip->min,ip->max, burst, ip->prio);\r
1139 safe_run(str);\r
1140 if(print_stats)\r
1141 {\r
1142 printf("up: %dk-%dk wants %dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1143 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1144 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1145 }\r
1146 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1147 tc, wan, ip->group, ip->mark,\r
1148 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1149 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1150 safe_run(str);\r
1151 }\r
1152 }\r
1153 }\r
1154 }\r
1155 fail\r
1156 { \r
1157 perror(classmap);\r
1158 puts("Warning - classmap file not fund, just generating preview ...");\r
1159 start_shaping=FALSE;\r
1160 stop_shaping=FALSE;\r
1161 }\r
1162 done; /* ugly macro end */\r
1163 }\r
1164 html=preview;\r
1165 json_traffic=json_preview;\r
1166 }\r
1167\r
1168 if(!dry_run && !just_flush)\r
1169 {\r
1170 /*-----------------------------------------------------------------*/\r
1171 printf("Writing json traffic overview %s ... ", json_traffic);\r
1172 /*-----------------------------------------------------------------*/\r
1173 write_json_traffic(json_traffic);\r
1174\r
1175 /*-----------------------------------------------------------------*/\r
1176 printf("Writing statistics into HTML page %s ...\n", html);\r
1177 /*-----------------------------------------------------------------*/\r
1178 write_htmlandlogs(html, d, total, just_preview);\r
1179 }\r
1180\r
1181 if(just_preview)\r
1182 {\r
1183 char swchar='p';\r
1184 if(start_shaping)\r
1185 {\r
1186 swchar='s';\r
1187 }\r
1188 else if(reduce_ceil)\r
1189 {\r
1190 swchar='0'+reduce_ceil; /* -2, -4 */\r
1191 }\r
1192 else if(stop_shaping)\r
1193 {\r
1194 swchar='q';\r
1195 }\r
1196\r
1197 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
1198 exit(0);\r
1199 } \r
1200\r
1201 i=0;\r
1202#ifdef DEBUG\r
1203 printf("%-22s %-15s mark\n","name","ip");\r
1204#endif\r
1205\r
1206 printf("Writing %s", classmap); \r
1207 f = fopen(classmap, "w"); \r
1208 if(f < 0)\r
1209 {\r
1210 perror(classmap);\r
1211 }\r
1212\r
1213 /*-----------------------------------------------------------------*/\r
1214 printf(" + generating iptables and tc classes ... ");\r
1215 /*-----------------------------------------------------------------*/\r
1216\r
1217 for_each(ip, ips) if(ip->mark > 0) /* works only for IPv4 so far */\r
1218 {\r
1219 if(idxs)\r
1220 {\r
1221 char *buf;\r
1222 duplicate(ip->addr,buf);\r
1223 if(ip->v6)\r
1224 {\r
1225 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1226 }\r
1227 else\r
1228 {\r
1229 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1230 }\r
1231 \r
1232 string(chain_forward,6+strlen(buf));\r
1233 strcpy(chain_forward,"forw_");\r
1234 strcat(chain_forward,buf);\r
1235\r
1236 string(chain_postrouting,6+strlen(buf));\r
1237 strcpy(chain_postrouting,"post_");\r
1238 strcat(chain_postrouting,buf);\r
1239 \r
1240 free(buf);\r
1241 }\r
1242 else\r
1243 {\r
1244 chain_forward="FORWARD";\r
1245 chain_postrouting="POSTROUTING";\r
1246 }\r
1247\r
1248 /* packet limits - this will be optional in future */\r
1249 if(ip->pps_limit)\r
1250 {\r
1251 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1252 ip->pps_limit, ip->pps_limit);\r
1253 }\r
1254 else\r
1255 {\r
1256 *limit_pkts = 0;\r
1257 } \r
1258\r
1259#ifdef DEBUG\r
1260 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1261#endif\r
1262\r
1263 /* -------------------------------------------------------- mark download */ \r
1264 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1265 chain_postrouting, ip->addr, ip->mask,\r
1266 lan, mark_iptables, ip->mark);\r
1267 iptables_save_line(str, ip->v6);\r
1268\r
1269/*\r
1270 if(qos_proxy)\r
1271 {\r
1272 sprintf(str, "-A %s -s %s -p tcp --sport %d -d %s/%d -o %s -j %s%d",\r
1273 chain_postrouting, proxy_ip, proxy_port, ip->addr,\r
1274 ip->mask, lan, mark_iptables, ip->mark);\r
1275 iptables_save_line(str, ip->v6);\r
1276 }\r
1277*/\r
1278 sprintf(str, "-A %s -d %s/%d -o %s %s-j ACCEPT",\r
1279 chain_postrouting, ip->addr, ip->mask, lan, limit_pkts);\r
1280 iptables_save_line(str, ip->v6);\r
1281\r
1282 /* classify overlimit packets to separate overlimit class */\r
1283 sprintf(str, "-A %s -d %s/%d -o %s -j %s%d",\r
1284 chain_postrouting, ip->addr, ip->mask,\r
1285 lan, mark_iptables, OVERLIMIT_CLASS);\r
1286 iptables_save_line(str, ip->v6);\r
1287\r
1288 sprintf(str, "-A %s -d %s/%d -o %s -j ACCEPT",\r
1289 chain_postrouting, ip->addr, ip->mask, lan);\r
1290 iptables_save_line(str, ip->v6);\r
1291\r
1292 /* -------------------------------------------------------- mark upload */\r
1293 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1294 chain_forward, ip->addr, ip->mask, wan, mark_iptables, ip->mark);\r
1295 iptables_save_line(str, ip->v6);\r
1296\r
1297 sprintf(str, "-A %s -s %s/%d -o %s %s-j ACCEPT",\r
1298 chain_forward, ip->addr, ip->mask, wan, limit_pkts);\r
1299 iptables_save_line(str, ip->v6);\r
1300\r
1301 /* classify overlimit packets to separate overlimit class */\r
1302 sprintf(str, "-A %s -s %s/%d -o %s -j %s%d", \r
1303 chain_forward, ip->addr, ip->mask, wan, mark_iptables, OVERLIMIT_CLASS);\r
1304 iptables_save_line(str, ip->v6);\r
1305\r
1306 sprintf(str, "-A %s -s %s/%d -o %s -j ACCEPT",\r
1307 chain_forward, ip->addr, ip->mask, wan);\r
1308 iptables_save_line(str, ip->v6);\r
1309\r
1310 if(ip->min)\r
1311 {\r
1312 /* -------------------------------------------------------- download class */\r
1313#ifdef DEBUG\r
1314 printf("(down: %dk-%dk ", ip->min, ip->max); \r
1315#endif\r
1316\r
1317 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1318 tc, lan, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
1319 safe_run(str);\r
1320\r
1321 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1322 {\r
1323 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1324 tc, lan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1325 safe_run(str);\r
1326 }\r
1327\r
1328 if(filter_type == 1)\r
1329 {\r
1330 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1331 tc, lan, ip->mark, ip->mark);\r
1332 safe_run(str);\r
1333 }\r
1334\r
1335 /* -------------------------------------------------------- upload class */\r
1336#ifdef DEBUG\r
1337 printf("up: %dk-%dk)\n", (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1338 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1339#endif\r
1340\r
1341 sprintf(str,"%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1342 tc, wan, ip->group, ip->mark,\r
1343 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1344 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1345 safe_run(str);\r
1346 \r
1347 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1348 {\r
1349 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s",\r
1350 tc, wan, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1351 safe_run(str);\r
1352 } \r
1353\r
1354 if(filter_type == 1)\r
1355 {\r
1356 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1357 tc, wan, ip->mark, ip->mark);\r
1358 safe_run(str);\r
1359 }\r
1360 \r
1361 if(f > 0)\r
1362 {\r
1363 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
1364 }\r
1365 }\r
1366 else\r
1367 {\r
1368#ifdef DEBUG\r
1369 printf("(sharing %s)\n", ip->sharing);\r
1370#endif\r
1371 }\r
1372 i++;\r
1373 }\r
1374 if(f > 0)\r
1375 {\r
1376 puts("done.");\r
1377 fclose(f);\r
1378 }\r
1379 \r
1380 if(idxs)\r
1381 {\r
1382 chain_forward = "forw_common";\r
1383 chain_postrouting = "post_common";\r
1384 }\r
1385 else\r
1386 {\r
1387 chain_forward = "FORWARD";\r
1388 chain_postrouting = "POSTROUTING";\r
1389 }\r
1390\r
1391 if(free_min)\r
1392 {\r
1393 final_chain = "ACCEPT";\r
1394 }\r
1395\r
1396/*\r
1397 if(qos_proxy)\r
1398 {\r
1399 if(free_min) \r
1400 {\r
1401 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s%d",\r
1402 chain_postrouting,proxy_ip,proxy_port,lan,mark_iptables, 3);\r
1403 iptables_save_line(str, FALSE); // only for IPv4\r
1404 }\r
1405 sprintf(str, "-A %s -s %s -p tcp --sport %d -o %s -j %s",\r
1406 chain_postrouting,proxy_ip,proxy_port,lan,final_chain);\r
1407 iptables_save_line(str, FALSE); // only for IPv4\r
1408 }\r
1409*/\r
1410\r
1411 if(free_min)\r
1412 {\r
1413 sprintf(str, "-A %s -o %s -j %s%d",\r
1414 chain_postrouting, lan, 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_postrouting, lan, 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)\r
1427 {\r
1428 sprintf(str,"-A %s -o %s -j %s%d", chain_forward, wan, mark_iptables, FREE_CLASS);\r
1429 iptables_save_line(str, FALSE); /* only for IPv4 */\r
1430 }\r
1431\r
1432 sprintf(str,"-A %s -o %s -j %s", chain_forward, wan, final_chain);\r
1433 iptables_save_line(str, FALSE);\r
1434 if(ip6prefix)\r
1435 {\r
1436 sprintf(str,"-A %s -o %s -j %s", chain_postrouting, lan, final_chain);\r
1437 iptables_save_line(str, TRUE);\r
1438 }\r
1439\r
1440 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1441 {\r
1442 /*-----------------------------------------------------------------*/\r
1443 puts("Generating free bandwith class ...");\r
1444 /*-----------------------------------------------------------------*/\r
1445 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1446 tc, lan, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority);\r
1447 safe_run(str);\r
1448 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1449 tc, wan, parent, FREE_CLASS, free_min, free_max, burst, lowest_priority);\r
1450 safe_run(str);\r
1451 /* tc SFQ */\r
1452 if(strcmpi(qos_leaf, "none"))\r
1453 {\r
1454 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, lan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1455 safe_run(str);\r
1456 \r
1457 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, wan, FREE_CLASS, FREE_CLASS, qos_leaf);\r
1458 safe_run(str);\r
1459 } \r
1460 /* tc handle 1 fw flowid */\r
1461 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
1462 safe_run(str);\r
1463\r
1464 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
1465 safe_run(str);\r
1466\r
1467 /*-----------------------------------------------------------------*/\r
1468 puts("Generating bandwith class for overlimit packets...");\r
1469 /*-----------------------------------------------------------------*/\r
1470 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1471 tc, lan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1472 safe_run(str);\r
1473 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1474 tc, wan, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1475 safe_run(str);\r
1476 }\r
1477 printf("Total IP count: %d\n", i);\r
1478 run_iptables_restore();\r
1479 if(log_file)\r
1480 {\r
1481 fclose(log_file);\r
1482 }\r
1483 return 0;\r
1484 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1485 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1486}\r
This page took 0.259496 seconds and 4 git commands to generate.