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