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