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