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