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