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