code readability
[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
1a2ab32b 398#define IPv4 FALSE\r
399#define IPv6 TRUE\r
400\r
401\r
0b9c3c19 402void run_iptables_restore(void)\r
007c44c5 403{\r
5da44508 404 char *restor;\r
9f552e96 405 string(restor, STRLEN);\r
abe9b855 406\r
407 /*-----------------------------------------------------------------*/\r
1c004f15 408 printf("Running %s <%s ...\n", iptablesrestore, iptablesfile);\r
abe9b855 409 /*-----------------------------------------------------------------*/\r
0b9c3c19 410\r
1a2ab32b 411 iptables_save_line("COMMIT", IPv4);\r
007c44c5 412 fclose(iptables_file);\r
ae776b10 413 if(dry_run) \r
414 {\r
a1d21464 415 parse(iptablesfile)\r
416 {\r
417 printf("%s\n",_);\r
418 }\r
8e29188a 419 done; /* ugly macro end */\r
ae776b10 420 }\r
421\r
422 sprintf(restor,"%s <%s",iptablesrestore, iptablesfile);\r
423 safe_run(restor);\r
0b9c3c19 424\r
425 if(ip6prefix)\r
426 {\r
427 /*-----------------------------------------------------------------*/\r
428 printf("Running %s <%s ...\n", ip6tablesrestore, ip6tablesfile);\r
429 /*-----------------------------------------------------------------*/\r
1a2ab32b 430 iptables_save_line("COMMIT", IPv6);\r
0b9c3c19 431 fclose(ip6tables_file);\r
432 if(dry_run) \r
433 {\r
434 parse(ip6tablesfile)\r
435 {\r
436 printf("%s\n",_);\r
437 }\r
438 done; /* ugly macro end */\r
439 }\r
440 sprintf(restor,"%s <%s",ip6tablesrestore, ip6tablesfile);\r
441 safe_run(restor);\r
442 }\r
007c44c5 443 free(restor);\r
444}\r
445\r
dccb3227 446/**/\r
007c44c5 447\r
dccb3227 448char *parse_datafile_line(char *str);\r
449time_t get_mtime(const char *path);\r
5b902402 450\r
007c44c5 451/*-----------------------------------------------------------------*/\r
493e1ccd 452/* Are you looking for int main(int argc, char **argv) ? :-)) */\r
007c44c5 453/*-----------------------------------------------------------------*/\r
454\r
455program\r
456{\r
8e29188a 457 int i=0; /* just plain old Fortran style integer :-) */\r
458 FILE *f=NULL; /* everything is just stream of bytes... */\r
459 char *str, *ptr, *d; /* LET A$=B$ :-) */\r
c38473c1 460 char *substring, *limit_pkts;\r
1c9cae56 461\r
9a56ab25 462 int parent = 1;\r
af37be1d 463 int just_networks = FALSE; \r
9a56ab25 464 int just_flush = FALSE; /* deactivates all previous actions */\r
465 int nodelay = FALSE;\r
466 int just_preview = FALSE; /* preview - generate just stats */\r
467 int start_shaping = FALSE; /* apply FUP - requires classmap file */\r
62b118c2 468 int stop_shaping = FALSE; /* lift FUP - requires classmap file */\r
469 int reduce_ceil = 0; /* allow only rate+(ceil-rate)/2, /4, etc. */\r
9a56ab25 470 int just_logs = FALSE; /* just parse logs */\r
471 int run = FALSE;\r
472 int total = 0;\r
33ec95ab 473 \r
007c44c5 474 char *althosts=NULL;\r
475 \r
476 printf("\n\\r
477Prometheus QoS - \"fair-per-IP\" Quality of Service setup utility.\n\\r
33c2a33d 478Version %s - Copyright (C)2005-2017 Michael Polak, Arachne Labs\n\\r
43cde5c3 479iptables-restore & burst tunning & classify modification by Ludva\n\\r
0d5026c6 480Credit: CZFree.Net, Martin Devera, Netdave, Aquarius, Gandalf\n\n",version);\r
007c44c5 481\r
8e29188a 482 /*----- Boring... we have to check command line options first: ----*/ \r
007c44c5 483 arguments\r
484 {\r
485 argument("-c") { nextargument(config); }\r
486 argument("-h") { nextargument(althosts);}\r
208112af 487 argument("-d") { run=TRUE; dry_run=TRUE; }\r
488 argument("-f") { run=TRUE; just_flush=TRUE; }\r
489 argument("-9") { run=TRUE; just_flush=9; }\r
490 argument("-p") { run=TRUE; just_preview=TRUE; }\r
3f76726a 491 argument("-q") { run=TRUE; just_preview=TRUE; stop_shaping=TRUE; }\r
62b118c2 492 argument("-2") { run=TRUE; just_preview=TRUE; reduce_ceil=2; }\r
493 argument("-4") { run=TRUE; just_preview=TRUE; reduce_ceil=4; }\r
8e29188a 494 argument("-s") { run=TRUE; just_preview=TRUE; start_shaping=TRUE; }\r
208112af 495 argument("-r") { run=TRUE; }\r
496 argument("-n") { run=TRUE; nodelay=TRUE; }\r
af37be1d 497 argument("-a") { run=TRUE; just_networks=TRUE; }\r
208112af 498 argument("-l") { just_logs=TRUE; }\r
499 argument("-m") { just_logs=TRUE; }\r
500 argument("-y") { just_logs=TRUE; }\r
007c44c5 501 argument("-?") { help(); exit(0); }\r
502 argument("--help") { help(); exit(0); }\r
503 argument("-v") { exit(0); } \r
504 argument("--version") { exit(0); } \r
505 }\r
208112af 506 \r
007c44c5 507 if(dry_run)\r
208112af 508 {\r
007c44c5 509 puts("*** THIS IS JUST DRY RUN ! ***\n");\r
208112af 510 }\r
007c44c5 511\r
208112af 512 date(d); /* this is typical cll1.h macro - prints current date */\r
007c44c5 513\r
514 /*-----------------------------------------------------------------*/\r
515 printf("Parsing configuration file %s ...\n", config);\r
516 /*-----------------------------------------------------------------*/\r
517 get_config(config);\r
9f552e96 518 /*-----------------------------------------------------------------*/\r
519 printf("Parsing upstream interfaces list %s ...\n", upstreamfile);\r
520 /*-----------------------------------------------------------------*/\r
521 parse(upstreamfile)\r
522 {\r
523 ptr = parse_datafile_line(_);\r
524 if(ptr)\r
525 {\r
526 create(interface, Interface);\r
527 interface->name = _;\r
528 interface->speed = (long long)atol(ptr);\r
529 /* is supplied value meaningful ?*/\r
530 if(interface->speed <= 0)\r
531 {\r
532 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
533 reject_config_and_exit(upstreamfile);\r
534 }\r
535 interface->is_upstream = TRUE;\r
536 interface->chain = "FORWARD";\r
537 interface->idxprefix = "forw";\r
538 push(interface, interfaces);\r
539 printf("Upstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
540 }\r
541 }\r
542 done; /* ugly macro end */\r
543\r
544 /*-----------------------------------------------------------------*/\r
545 printf("Parsing downstream interfaces list %s ...\n", downstreamfile);\r
546 /*-----------------------------------------------------------------*/\r
00e9928c 547 parse(downstreamfile)\r
9f552e96 548 {\r
549 ptr = parse_datafile_line(_);\r
550 if(ptr)\r
551 {\r
552 create(interface, Interface);\r
553 interface->name = _;\r
554 interface->speed = (long long)atol(ptr);\r
555 /* is supplied value meaningful ?*/\r
556 if(interface->speed <= 0)\r
557 {\r
558 printf("Illegal value of %s interface bandwidth.\n", interface->name);\r
559 reject_config_and_exit(downstreamfile);\r
560 }\r
561 interface->is_upstream = FALSE;\r
562 interface->chain = "POSTROUTING";\r
563 interface->idxprefix = "post";\r
564 push(interface, interfaces);\r
57cbdd52 565 printf("Downstream interface %s: medium %s capacity %ld kbps\n", interface->name, medium, interface->speed);\r
9f552e96 566 }\r
567 }\r
568 done; /* ugly macro end */\r
569\r
c9012978 570 \r
33ec95ab 571 if(just_logs)\r
c9012978 572 {\r
208112af 573 parse_ip_log(argc,argv);\r
574 exit(0);\r
575 }\r
576 else if(not run)\r
577 {\r
578 help();\r
579 exit(0);\r
c9012978 580 }\r
007c44c5 581\r
208112af 582 if(althosts)\r
583 {\r
af37be1d 584 hosts = althosts;\r
208112af 585 }\r
007c44c5 586\r
587 if(just_flush<9)\r
588 {\r
589 /*-----------------------------------------------------------------*/\r
590 puts("Parsing iptables verbose output ...");\r
591 /*-----------------------------------------------------------------*/\r
d7357b63 592 get_traffic_statistics(iptables, FALSE);\r
0b9c3c19 593 if(ip6prefix)\r
594 {\r
595 /*-----------------------------------------------------------------*/\r
596 puts("Parsing ip6tables verbose output ...");\r
597 /*-----------------------------------------------------------------*/ \r
d7357b63 598 get_traffic_statistics(ip6tables, TRUE);\r
0b9c3c19 599 }\r
007c44c5 600 }\r
601\r
602 /*-----------------------------------------------------------------*/\r
af37be1d 603 /* cll1.h - let's allocate brand new character buffer... */\r
007c44c5 604 /*-----------------------------------------------------------------*/\r
c38473c1 605 string(str, STRLEN); \r
606 string(limit_pkts, STRLEN);\r
007c44c5 607\r
8dcd2b4c 608 /*-----------------------------------------------------------------*/\r
609 printf("Parsing macro definition file %s ...\n", macrosfile);\r
610 /*-----------------------------------------------------------------*/\r
611 parse(macrosfile)\r
612 {\r
613 ptr = parse_datafile_line(_);\r
614 if(ptr)\r
615 {\r
616 create(macro, Macro);\r
617 macro->rewrite_from = _;\r
618 macro->rewrite_to = ptr;\r
619 push(macro, macros);\r
620 printf("%s -> %s\n", macro->rewrite_from, macro->rewrite_to);\r
621 }\r
622 }\r
623 done; /* ugly macro end */\r
624\r
9f552e96 625\r
626\r
007c44c5 627 /*-----------------------------------------------------------------*/\r
af37be1d 628 printf("Parsing class defintion file %s ...\n", hosts);\r
007c44c5 629 /*-----------------------------------------------------------------*/\r
af37be1d 630 parse_hosts(hosts);\r
9f552e96 631/*\r
632 //this was pretty dumb idea anyway...\r
af37be1d 633 if(just_networks)\r
634 {\r
635 analyse_topology("/usr/sbin/traceroute -n -m 10 -w 2 %s.%d");\r
636 exit(-1); \r
637 }\r
9f552e96 638*/\r
007c44c5 639\r
640 /*-----------------------------------------------------------------*/\r
641 puts("Resolving shared connections ...");\r
642 /*-----------------------------------------------------------------*/\r
af37be1d 643 for_each(ip, ips) if(ip->sharing)\r
007c44c5 644 {\r
af37be1d 645 for_each(sharedip, ips) if(eq(sharedip->name, ip->sharing))\r
007c44c5 646 {\r
b1a5c883 647 sharedip->traffic += ip->traffic;\r
bf59a20b 648 sharedip->traffic_down += ip->direct;\r
649 sharedip->traffic_up += ip->upload;\r
b1a5c883 650 ip->traffic = 0;\r
651 ip->mark = sharedip->mark; \r
652 ip->lmsid = sharedip->lmsid;\r
c38473c1 653 ip->pps_limit = sharedip->pps_limit; /* no other way to do this */\r
64b2d125 654\r
655 /* Ugly hack: append IPv4 addresses of sharedip to IPv6 uplinks */\r
656 ptr = strchr(ip->addr, '+');\r
657 if(ptr && ptr-ip->addr > 1 && !sharedip->v6)\r
658 {\r
659 *(--ptr) = 0;\r
660 concatenate(ip->addr, sharedip->addr, ptr);\r
661 ip->name = ip->addr = ptr;\r
662 ptr = strchr(ip->addr, '.');\r
663 while(ptr && *ptr)\r
664 {\r
665 *ptr = ':';\r
666 ptr = strchr(ptr, '.');\r
667 }\r
668 ip->mask += 64;\r
669 }\r
670\r
007c44c5 671 break;\r
672 }\r
1c9cae56 673 if(not sharedip)\r
bb9e11ee 674 {\r
260c2719 675 printf("Unresolved shared connection: %s %s sharing-%s\n",\r
676 ip->addr, ip->name, ip->sharing);\r
bb9e11ee 677 }\r
007c44c5 678 }\r
679\r
680 if(enable_credit && just_flush<9)\r
681 {\r
682 /*-----------------------------------------------------------------*/\r
683 printf("Parsing credit file %s ...\n", credit);\r
684 /*-----------------------------------------------------------------*/\r
685 parse(credit)\r
686 {\r
bb5e7385 687 ptr = parse_datafile_line(_);\r
007c44c5 688 if(ptr)\r
689 {\r
208112af 690 if_exists(ip,ips,eq(ip->addr,_))\r
691 {\r
007c44c5 692 sscanf(ptr,"%Lu",&(ip->credit));\r
208112af 693 }\r
007c44c5 694 }\r
695 }\r
8e29188a 696 done; /* ugly macro end */\r
007c44c5 697 }\r
698\r
bb5e7385 699\r
007c44c5 700 if(!just_preview)\r
701 {\r
702 /*-----------------------------------------------------------------*/\r
703 puts("Initializing iptables and tc classes ...");\r
704 /*-----------------------------------------------------------------*/\r
705 \r
f64d5431 706 iptables_file = fopen(iptablesfile, "w");\r
260c2719 707 if(iptables_file == NULL)\r
bb9e11ee 708 {\r
f64d5431 709 perror(iptablesfile);\r
007c44c5 710 exit(-1);\r
711 }\r
1a2ab32b 712 iptables_save_line(iptablespreamble, IPv4);\r
0b9c3c19 713\r
714 if(ip6prefix)\r
715 {\r
716 ip6tables_file = fopen(ip6tablesfile, "w");\r
717 if(ip6tables_file == NULL)\r
718 {\r
719 perror(ip6tablesfile);\r
720 exit(-1);\r
721 }\r
1a2ab32b 722 iptables_save_line(iptablespreamble, IPv6);\r
723 iptables_save_line(ip6preamble, IPv6);\r
0b9c3c19 724 }\r
725\r
726 run_iptables_restore();\r
007c44c5 727 \r
f64d5431 728 log_file = fopen(cmdlog, "w");\r
260c2719 729 if(log_file == NULL) \r
bb9e11ee 730 {\r
f64d5431 731 perror(cmdlog);\r
007c44c5 732 exit(-1);\r
ca6f7e80 733 } \r
007c44c5 734 \r
9f552e96 735 for_each(interface, interfaces)\r
736 {\r
737 sprintf(str,"%s qdisc del dev %s root 2>/dev/null", tc, interface->name);\r
738 safe_run(str);\r
739 }\r
007c44c5 740 \r
741 iptables_file=fopen(iptablesfile,"w");\r
1a2ab32b 742 iptables_save_line(iptablespreamble, IPv4);\r
0b9c3c19 743 if(ip6prefix)\r
744 {\r
745 ip6tables_file=fopen(ip6tablesfile,"w");\r
1a2ab32b 746 iptables_save_line(iptablespreamble, IPv6);\r
747 iptables_save_line(ip6preamble, IPv6);\r
0b9c3c19 748 }\r
007c44c5 749\r
0b9c3c19 750 if(qos_free_zone && *qos_free_zone!='0') /* this is currently supported only for IPv4 */\r
007c44c5 751 {\r
9f552e96 752 for_each(interface, interfaces)\r
007c44c5 753 {\r
c5a58cd4 754 sprintf(str,"-A %s -%c %s -o %s -j ACCEPT", interface->chain, (interface->is_upstream?'d':'s'), qos_free_zone, interface->name);\r
1a2ab32b 755 iptables_save_line(str, IPv4);\r
007c44c5 756 }\r
007c44c5 757 }\r
758 \r
f64d5431 759 if(ip_count > idxtable_treshold1 && !just_flush)\r
007c44c5 760 {\r
0b9c3c19 761 int idxcount=0, bitmask=32-idxtable_bitmask1;\r
e0161edb 762 char *subnet, *buf;\r
007c44c5 763 /*-----------------------------------------------------------------*/\r
764 printf("Detected %d addresses - indexing iptables rules to improve performance...\n",ip_count);\r
765 /*-----------------------------------------------------------------*/\r
766\r
1a2ab32b 767 iptables_save_line(":post_common - [0:0]", IPv4);\r
768 iptables_save_line(":forw_common - [0:0]", IPv4);\r
0b9c3c19 769 if(ip6prefix)\r
770 {\r
1a2ab32b 771 iptables_save_line(":post_common - [0:0]", IPv6);\r
772 iptables_save_line(":forw_common - [0:0]", IPv6);\r
0b9c3c19 773 }\r
007c44c5 774\r
0b9c3c19 775 for_each(ip,ips) if(ip->addr && *(ip->addr) && !eq(ip->addr,"0.0.0.0/0")) \r
007c44c5 776 {\r
0b9c3c19 777 if(ip->v6)\r
778 {\r
779 buf=index6_id(ip->addr,bitmask+32);\r
780 }\r
781 else\r
782 {\r
783 buf=index_id(ip->addr, bitmask);\r
784 }\r
785 \r
208112af 786 if_exists(idx,idxs,eq(idx->id,buf))\r
787 {\r
007c44c5 788 idx->children++;\r
208112af 789 }\r
007c44c5 790 else\r
791 {\r
792 create(idx,Index);\r
0b9c3c19 793 idx->addr = ip->addr;\r
794 idx->id = buf;\r
795 idx->bitmask = bitmask+32*ip->v6;\r
796 idx->parent = NULL;\r
797 idx->children = 0;\r
798 idx->ipv6 = ip->v6;\r
007c44c5 799 idxcount++;\r
800 push(idx,idxs);\r
801 }\r
802 }\r
803\r
804 /* brutal perfomance optimalization */\r
f64d5431 805 while(idxcount > idxtable_treshold2 && bitmask > 2*idxtable_bitmask2)\r
007c44c5 806 {\r
f64d5431 807 bitmask -= idxtable_bitmask2;\r
808 idxcount = 0;\r
208112af 809\r
6cc38f96 810 for_each(idx,idxs) if(idx->parent == NULL)\r
007c44c5 811 {\r
0b9c3c19 812 if(idx->ipv6)\r
813 {\r
814 buf = index6_id(idx->addr, bitmask+32);\r
815 }\r
816 else\r
817 {\r
818 buf = index_id(idx->addr, bitmask);\r
819 }\r
208112af 820 if_exists(metaindex,idxs,eq(metaindex->id,buf))\r
821 {\r
822 metaindex->children++;\r
823 }\r
007c44c5 824 else\r
825 {\r
826 create(metaindex,Index);\r
0b9c3c19 827 metaindex->addr = idx->addr;\r
828 metaindex->id = buf;\r
829 metaindex->bitmask = bitmask+32*idx->ipv6;\r
830 metaindex->parent = NULL;\r
831 metaindex->children = 0;\r
832 metaindex->ipv6 = idx->ipv6;\r
007c44c5 833 idxcount++;\r
834 push(metaindex,idxs);\r
835 }\r
836 idx->parent=metaindex;\r
837 }\r
838 }\r
839\r
f64d5431 840 /* this should slightly optimize throughput ... */\r
007c44c5 841 sort(idx,idxs,desc_order_by,children);\r
842 sort(idx,idxs,order_by,bitmask);\r
843\r
844 i=0;\r
9f552e96 845 for_each(idx, idxs)\r
007c44c5 846 {\r
0b9c3c19 847 if(idx->ipv6)\r
848 {\r
849 subnet=subnet6_id(idx->addr, idx->bitmask);\r
850 }\r
851 else\r
852 {\r
853 subnet=subnet_id(idx->addr, idx->bitmask);\r
854 }\r
855 printf("%d: %s/%d\n", ++i, subnet, idx->bitmask);\r
007c44c5 856 \r
857 sprintf(str,":post_%s - [0:0]", idx->id);\r
0b9c3c19 858 iptables_save_line(str, idx->ipv6);\r
007c44c5 859\r
860 sprintf(str,":forw_%s - [0:0]", idx->id);\r
0b9c3c19 861 iptables_save_line(str, idx->ipv6);\r
007c44c5 862\r
9f552e96 863 for_each(interface, interfaces)\r
bb9e11ee 864 {\r
9f552e96 865 if(idx->parent)\r
866 {\r
867 string(buf, strlen(idx->parent->id)+6);\r
868 sprintf(buf, "%s_%s", interface->idxprefix, idx->parent->id);\r
869 }\r
870 else\r
871 {\r
872 buf = interface->chain;\r
873 }\r
007c44c5 874\r
c5a58cd4 875 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_%s", \r
876 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix, idx->id);\r
9f552e96 877 iptables_save_line(str, idx->ipv6);\r
007c44c5 878\r
c5a58cd4 879 sprintf(str, "-A %s -%c %s/%d -o %s -j %s_common",\r
880 buf, (interface->is_upstream?'s':'d'), subnet, idx->bitmask, interface->name, interface->idxprefix);\r
9f552e96 881 iptables_save_line(str, idx->ipv6);\r
bb9e11ee 882 }\r
007c44c5 883 }\r
884 printf("Total indexed iptables chains created: %d\n", i);\r
885\r
9f552e96 886 for_each(interface, interfaces)\r
0b9c3c19 887 {\r
9f552e96 888 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
1a2ab32b 889 iptables_save_line(str, IPv4);\r
9f552e96 890 if(ip6prefix)\r
891 {\r
892 sprintf(str,"-A %s -o %s -j %s_common", interface->chain, interface->name, interface->idxprefix);\r
1a2ab32b 893 iptables_save_line(str, IPv6);\r
9f552e96 894 }\r
0b9c3c19 895 }\r
007c44c5 896 }\r
007c44c5 897 }\r
898\r
899 if(just_flush)\r
900 {\r
901 fclose(iptables_file);\r
add90548 902 if(log_file)\r
903 { \r
904 fclose(log_file);\r
905 }\r
007c44c5 906 puts("Just flushed iptables and tc classes - now exiting ...");\r
907 exit(0);\r
908 }\r
909\r
910 if(!just_preview)\r
911 {\r
912 if(!dry_run && !nodelay && qos_free_delay)\r
913 {\r
9f552e96 914 printf("Flushed iptables and tc classes - now sleeping for %d seconds...\n", qos_free_delay);\r
007c44c5 915 sleep(qos_free_delay);\r
916 }\r
917\r
9f552e96 918 for_each(interface, interfaces)\r
919 {\r
920 sprintf(str, "%s qdisc add dev %s root handle 1: htb r2q %d default 1",\r
921 tc, interface->name, htb_r2q);\r
922 safe_run(str);\r
007c44c5 923\r
9f552e96 924 sprintf(str, "%s class add dev %s parent 1: classid 1:2 htb rate %s ceil %s burst %dk prio %d",\r
925 tc, interface->name, medium, medium, burst_main, highest_priority);\r
926 safe_run(str);\r
007c44c5 927\r
9f552e96 928 sprintf(str, "%s class add dev %s parent 1:2 classid 1:1 htb rate %Ldkbit ceil %Ldkbit burst %dk prio %d",\r
929 tc, interface->name, interface->speed, interface->speed, burst_main, highest_priority);\r
930 safe_run(str);\r
931 }\r
007c44c5 932 }\r
933\r
934 /*-----------------------------------------------------------------*/\r
208112af 935 puts("Locating heavy downloaders and generating root classes ...");\r
007c44c5 936 /*-----------------------------------------------------------------*/\r
bb9e11ee 937 sort(ip,ips,desc_order_by,traffic); \r
007c44c5 938\r
939 /*-----------------------------------------------------------------*/\r
9f552e96 940 for_each(interface, interfaces)\r
007c44c5 941 {\r
9f552e96 942 long long int rate = interface->speed;\r
943 long long int max = interface->speed;\r
6cc38f96 944 int group_count = 0;\r
9f552e96 945 //obsolete: FILE *credit_file = NULL;\r
007c44c5 946 \r
9f552e96 947 //obsolete: if(!just_preview && !dry_run && enable_credit)\r
948 //obsolete: {\r
949 //obsolete: credit_file = fopen(credit,"w");\r
950 //obsolete: }\r
951\r
208112af 952 for_each(group,groups)\r
007c44c5 953 {\r
954 if(!just_preview)\r
955 {\r
9f552e96 956 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
957 tc, interface->name, parent, group->id, rate, max, burst_group, highest_priority+1, group->desired);\r
007c44c5 958 safe_run(str);\r
959 }\r
9f552e96 960\r
6cc38f96 961 if(group_count++ < max_nesting)\r
bb9e11ee 962 {\r
6cc38f96 963 parent = group->id;\r
bb9e11ee 964 }\r
9f552e96 965\r
6cc38f96 966 rate -= digital_divide*group->min;\r
967 if(rate < group->min)\r
4358455e 968 {\r
6cc38f96 969 rate = group->min;\r
4358455e 970 }\r
007c44c5 971 \r
972 /*shaping of aggresive downloaders, with credit file support */\r
9f552e96 973 /* obsolete\r
007c44c5 974 if(use_credit)\r
975 {\r
6cc38f96 976 int group_rate = group->min, priority_sequence = lowest_priority;\r
007c44c5 977 \r
6cc38f96 978 for_each(ip, ips) if(ip->min == group->min && ip->max > ip->min)\r
007c44c5 979 {\r
e48d46c9 980 ip->realquota=ip->credit+(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20));\r
981 if( ip->keyword->data_limit \r
982 and not ip->fixedprio \r
983 and ip->traffic > ip->realquota )\r
007c44c5 984 {\r
e48d46c9 985 if(group_rate < ip->max)\r
4358455e 986 {\r
e48d46c9 987 ip->max = group_rate;\r
4358455e 988 }\r
007c44c5 989 group_rate+=magic_treshold;\r
208112af 990 ip->prio=lowest_priority;\r
4358455e 991 if(ip->prio<highest_priority+2)\r
992 {\r
993 ip->prio=highest_priority+2;\r
994 }\r
007c44c5 995 }\r
996 else\r
997 {\r
6cc38f96 998 if( ip->keyword->data_prio \r
999 && !ip->fixedprio \r
f71cfa3b 1000 && ( ip->traffic > ip->credit + (ip->min*ip->keyword->data_prio+(ip->keyword->fixed_prio<<20))) )\r
007c44c5 1001 {\r
1002 ip->prio=priority_sequence--;\r
4358455e 1003 if(ip->prio<highest_priority+1)\r
1004 {\r
1005 ip->prio=highest_priority+1;\r
1006 }\r
007c44c5 1007 }\r
1008 \r
1009 if(credit_file)\r
1010 {\r
1011 unsigned long long lcredit=0;\r
99127c70 1012 \r
4358455e 1013 if((ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))>ip->traffic)\r
1014 {\r
007c44c5 1015 lcredit=(ip->min*ip->keyword->data_limit+(ip->keyword->fixed_limit<<20))-ip->traffic;\r
4358455e 1016 }\r
007c44c5 1017 fprintf(credit_file,"%s %Lu\n",ip->addr,lcredit);\r
1018 }\r
1019 }\r
6cc38f96 1020 } \r
9f552e96 1021 } obsolete */\r
007c44c5 1022 }\r
9f552e96 1023 /* obsolete \r
4358455e 1024 if(credit_file)\r
1025 {\r
1026 fclose(credit_file);\r
9f552e96 1027 } obsolete */\r
007c44c5 1028 }\r
1029\r
1030 if(just_preview)\r
1031 {\r
62b118c2 1032 if(start_shaping || stop_shaping || reduce_ceil)\r
8e29188a 1033 {\r
dccb3227 1034 time_t how_much_seconds = time(NULL) - get_mtime(classmap); /* sice start of daily aggregation session */\r
1035 printf("Reading %s (%ld seconds old) and applying Fair Use Policy and Aggregation rules... \n", classmap, how_much_seconds);\r
1036 \r
8e29188a 1037 parse(classmap)\r
1038 {\r
1039 ptr=strchr(_,' ');\r
1040 if(ptr)\r
1041 {\r
1042 *ptr=0;\r
1043 ptr++;\r
1044 if_exists(ip,ips,eq(ip->addr,_))\r
1045 {\r
68184e0d 1046 int unshape_this_ip = 0;\r
bf59a20b 1047 long avg_mbps_down = ip->traffic_down * 8 / how_much_seconds; \r
1048 long avg_mbps_up = ip->traffic_up * 8 / how_much_seconds;\r
dccb3227 1049 int agreg = 1, print_stats = 1;\r
1050 \r
dccb3227 1051 if(ip->keyword->download_aggregation)\r
1052 {\r
3335365b 1053 int min_mbps = (ip->min/ip->keyword->download_aggregation)>>10;\r
1054 if(min_mbps < 1)\r
1055 {\r
1056 min_mbps = 1;\r
1057 }\r
1058 \r
1059 if(min_mbps <= avg_mbps_down)\r
dccb3227 1060 {\r
1061 unshape_this_ip = 0;\r
bf59a20b 1062 agreg = (int)((float)(avg_mbps_down+1)/min_mbps+.5);\r
dccb3227 1063 ip->max /= agreg;\r
9de0d723 1064 ip->pps_limit /= agreg;\r
dccb3227 1065 printf("Download aggregation 1:%d for %s (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_down);\r
1066 }\r
1067 else\r
1068 {\r
1069 unshape_this_ip = 1;\r
1070 }\r
1071 }\r
1072 else if(ip->keyword->upload_aggregation)\r
1073 {\r
3335365b 1074 int min_mbps = (ip->min/ip->keyword->upload_aggregation)>>10;\r
1075 if(min_mbps < 1)\r
1076 {\r
1077 min_mbps = 1;\r
1078 }\r
1079\r
1080 if(min_mbps <= avg_mbps_up)\r
dccb3227 1081 {\r
1082 unshape_this_ip = 0;\r
bf59a20b 1083 agreg = (int)((float)(avg_mbps_up+1)/min_mbps+.5);\r
dccb3227 1084 ip->max /= agreg;\r
1085 printf("Upload aggregation 1:%d for %s: (min: %lu Mbps avg: %ld Mbps)\n", agreg, ip->name, min_mbps, avg_mbps_up);\r
1086 }\r
1087 else\r
1088 {\r
1089 unshape_this_ip = 1;\r
1090 }\r
1091 }\r
3335365b 1092 if(stop_shaping)\r
1093 {\r
1094 unshape_this_ip = 1;\r
1095 }\r
bf59a20b 1096 ip->aggregated = agreg; \r
1097 ip->mark = atoi(ptr);\r
dccb3227 1098 if(ip->max < ip->desired || unshape_this_ip || reduce_ceil) /* apply or disable FUP limit immediately.... */\r
8e29188a 1099 {\r
dccb3227 1100 if(unshape_this_ip)\r
3f76726a 1101 {\r
1102 ip->max = ip->desired;\r
dccb3227 1103 if(stop_shaping) /* all limits removed, but not printed with -s (start_shaping) switch */\r
1104 {\r
1105 printf("Removing limit for %s (%s) ", ip->name, ip->addr);\r
1106 }\r
1107 else\r
1108 {\r
1109 print_stats = 0;\r
1110 }\r
3f76726a 1111 }\r
1112 else\r
1113 {\r
9f552e96 1114 printf("Updating %s (%s) ", ip->name, ip->addr);\r
62b118c2 1115 if(reduce_ceil)\r
1116 {\r
1117 ip->max = ip->min + (ip->desired-ip->min)/reduce_ceil;\r
1118 }\r
dccb3227 1119 else if(ip->max < ip->min)\r
1120 {\r
1121 ip->max = ip->min;\r
1122 } \r
1123 }\r
9f552e96 1124 for_each(interface, interfaces)\r
dccb3227 1125 {\r
9f552e96 1126 if(!interface->is_upstream)\r
1127 {\r
1128 if(print_stats)\r
1129 {\r
1130 printf("[down %s: %dk-%dk wants %d]", interface->name, ip->min, ip->max, ip->desired);\r
1131 }\r
1132 sprintf(str, "%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1133 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
1134 safe_run(str);\r
1135 }\r
1136 else\r
1137 {\r
1138 if(print_stats)\r
1139 {\r
1140 printf("[up %s: %dk-%dk wants %dk]", interface->name, (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), \r
1141 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1142 (int)((ip->desired/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed));\r
1143 }\r
1144 sprintf(str,"%s class change dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1145 tc, interface->name, ip->group, ip->mark,\r
1146 (int)((ip->min/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed),\r
1147 (int)((ip->max/ip->keyword->asymetry_ratio)-ip->keyword->asymetry_fixed), burst, ip->prio);\r
1148 safe_run(str);\r
1149 }\r
3f76726a 1150 }\r
dccb3227 1151 if(print_stats)\r
1152 {\r
9f552e96 1153 printf("\n");\r
dccb3227 1154 }\r
8e29188a 1155 }\r
1156 }\r
1157 }\r
1158 }\r
1159 fail\r
1160 { \r
1161 perror(classmap);\r
1162 puts("Warning - classmap file not fund, just generating preview ...");\r
1163 start_shaping=FALSE;\r
3f76726a 1164 stop_shaping=FALSE;\r
8e29188a 1165 }\r
1166 done; /* ugly macro end */\r
1167 }\r
6fb3c58a 1168 html=preview;\r
1ab008b9 1169 json_traffic=json_preview;\r
007c44c5 1170 }\r
6fb3c58a 1171\r
1172 if(!dry_run && !just_flush)\r
007c44c5 1173 {\r
1174 /*-----------------------------------------------------------------*/\r
1ab008b9 1175 printf("Writing json traffic overview %s ... ", json_traffic);\r
007c44c5 1176 /*-----------------------------------------------------------------*/\r
1ab008b9 1177 write_json_traffic(json_traffic);\r
007c44c5 1178\r
0b9c3c19 1179 /*-----------------------------------------------------------------*/\r
1180 printf("Writing statistics into HTML page %s ...\n", html);\r
1181 /*-----------------------------------------------------------------*/\r
1182 write_htmlandlogs(html, d, total, just_preview);\r
1183 }\r
007c44c5 1184\r
1185 if(just_preview)\r
1186 {\r
8e29188a 1187 char swchar='p';\r
1188 if(start_shaping)\r
1189 {\r
1190 swchar='s';\r
1191 }\r
62b118c2 1192 else if(reduce_ceil)\r
1193 {\r
1194 swchar='0'+reduce_ceil; /* -2, -4 */\r
1195 }\r
3f76726a 1196 else if(stop_shaping)\r
1197 {\r
1198 swchar='q';\r
1199 }\r
1200\r
8e29188a 1201 printf("Statistics preview generated (-%c switch) - now exiting ...\n", swchar);\r
007c44c5 1202 exit(0);\r
be96b71b 1203 } \r
007c44c5 1204\r
1205 i=0;\r
260c2719 1206#ifdef DEBUG\r
007c44c5 1207 printf("%-22s %-15s mark\n","name","ip");\r
260c2719 1208#endif\r
208112af 1209\r
14e28c6f 1210 printf("Writing %s", classmap); \r
be96b71b 1211 f = fopen(classmap, "w"); \r
1212 if(f < 0)\r
1213 {\r
1214 perror(classmap);\r
1215 }\r
1216\r
1217 /*-----------------------------------------------------------------*/\r
0995c4ad 1218 printf(" + generating iptables and tc classes ... ");\r
be96b71b 1219 /*-----------------------------------------------------------------*/\r
1220\r
9f552e96 1221 for_each(ip, ips) if(ip->mark > 0)\r
be96b71b 1222 {\r
9f552e96 1223 for_each(interface, interfaces)\r
007c44c5 1224 {\r
9f552e96 1225 char *chain;\r
1226 if(idxs)\r
0b9c3c19 1227 {\r
9f552e96 1228 char *buf;\r
1229 duplicate(ip->addr,buf);\r
1230 if(ip->v6)\r
1231 {\r
1232 buf=index6_id(ip->addr,64-idxtable_bitmask1);\r
1233 }\r
1234 else\r
1235 {\r
1236 buf=index_id(ip->addr,32-idxtable_bitmask1);\r
1237 }\r
1238 \r
1239 string(chain, 6+strlen(buf));\r
1240 sprintf(chain, "%s_", interface->idxprefix);\r
1241 strcat(chain, buf);\r
1242\r
1243 free(buf);\r
0b9c3c19 1244 }\r
1245 else\r
1246 {\r
9f552e96 1247 chain = interface->chain;\r
0b9c3c19 1248 }\r
007c44c5 1249\r
9f552e96 1250 /* packet limits - this will be optional in future */\r
1251 if(ip->pps_limit)\r
1252 {\r
1253 sprintf(limit_pkts, "-m limit --limit %d/s --limit-burst %d ", \r
1254 ip->pps_limit, ip->pps_limit);\r
1255 }\r
1256 else\r
1257 {\r
1258 *limit_pkts = 0;\r
1259 } \r
007c44c5 1260\r
9f552e96 1261 #ifdef DEBUG\r
1262 printf("%-22s %-16s %04d %d/s\n", ip->name, ip->addr, ip->mark, ip->pps_limit); \r
1263 #endif\r
06733b88 1264\r
9f552e96 1265 /* ------------------------------------------------ iptables classify */\r
c5a58cd4 1266 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1267 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
9f552e96 1268 interface->name, mark_iptables, ip->mark);\r
1269 iptables_save_line(str, ip->v6);\r
007c44c5 1270\r
c5a58cd4 1271 sprintf(str, "-A %s -%c %s/%d -o %s %s-j ACCEPT",\r
1272 chain, (interface->is_upstream?'s':'d'),ip->addr, ip->mask,\r
1273 interface->name, limit_pkts);\r
9f552e96 1274 iptables_save_line(str, ip->v6);\r
007c44c5 1275\r
56f6397e 1276 if(limit_pkts)\r
1277 {\r
1278 /* classify overlimit packets to separate overlimit class */\r
c5a58cd4 1279 sprintf(str, "-A %s -%c %s/%d -o %s -j %s%d",\r
1280 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
56f6397e 1281 interface->name, mark_iptables, OVERLIMIT_CLASS);\r
1282 iptables_save_line(str, ip->v6);\r
1283\r
c5a58cd4 1284 sprintf(str, "-A %s -%c %s/%d -o %s -j ACCEPT",\r
1285 chain, (interface->is_upstream?'s':'d'), ip->addr, ip->mask,\r
1286 interface->name);\r
56f6397e 1287 iptables_save_line(str, ip->v6);\r
1288 }\r
007c44c5 1289\r
9f552e96 1290 if(ip->min)\r
dee5592e 1291 {\r
9f552e96 1292 //TODO - min and max should not exceed interface->speed\r
1293 \r
1294 /* -------------------------------------------------------- tc class */\r
1295 #ifdef DEBUG\r
1296 printf("[down: %dk-%dk]", ip->min, ip->max);\r
1297 #endif\r
be96b71b 1298\r
9f552e96 1299 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d", \r
1300 tc, interface->name, ip->group, ip->mark, ip->min, ip->max, burst, ip->prio);\r
0b9c3c19 1301 safe_run(str);\r
007c44c5 1302\r
9f552e96 1303 if(strcmpi(ip->keyword->leaf_discipline, "none"))\r
1304 {\r
1305 sprintf(str, "%s qdisc add dev %s parent 1:%d handle %d %s", \r
1306 tc, interface->name, ip->mark, ip->mark, ip->keyword->leaf_discipline); /*qos_leaf*/\r
1307 safe_run(str);\r
1308 }\r
be96b71b 1309\r
9f552e96 1310 if(filter_type == 1)\r
1311 {\r
1312 sprintf(str, "%s filter add dev %s parent 1:0 protocol ip handle %d fw flowid 1:%d",\r
1313 tc, interface->name, ip->mark, ip->mark);\r
1314 safe_run(str);\r
1315 }\r
007c44c5 1316 }\r
9f552e96 1317 else\r
be96b71b 1318 {\r
9f552e96 1319 #ifdef DEBUG\r
1320 printf("(sharing %s)\n", ip->sharing);\r
1321 #endif\r
be96b71b 1322 }\r
9f552e96 1323 i++;\r
007c44c5 1324 }\r
9f552e96 1325 if(ip->min && f > 0)\r
260c2719 1326 {\r
9f552e96 1327 fprintf(f, "%s %d\n", ip->addr, ip->mark);\r
260c2719 1328 }\r
007c44c5 1329 }\r
6fb3c58a 1330 if(f > 0)\r
be96b71b 1331 {\r
1332 puts("done.");\r
1333 fclose(f);\r
1334 }\r
0b9c3c19 1335\r
9f552e96 1336 for_each(interface, interfaces)\r
007c44c5 1337 {\r
9f552e96 1338 char *chain;\r
1339 if(idxs)\r
0b9c3c19 1340 {\r
9f552e96 1341 string(chain, STRLEN);\r
1342 sprintf(chain, "%s_common", interface->idxprefix);\r
1343 }\r
1344 else\r
1345 {\r
1346 chain = interface->chain;\r
0b9c3c19 1347 }\r
0b9c3c19 1348\r
9f552e96 1349 if(free_min)\r
1350 {\r
1351 final_chain = "ACCEPT";\r
0b9c3c19 1352\r
9f552e96 1353 sprintf(str, "-A %s -o %s -j %s%d",\r
1354 chain, interface->name, mark_iptables, FREE_CLASS);\r
1a2ab32b 1355 iptables_save_line(str, IPv4); /* only for IPv4 */\r
9f552e96 1356 }\r
0b9c3c19 1357\r
9f552e96 1358 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1a2ab32b 1359 iptables_save_line(str, IPv4);\r
9f552e96 1360 if(ip6prefix)\r
1361 {\r
1362 sprintf(str,"-A %s -o %s -j %s", chain, interface->name, final_chain);\r
1a2ab32b 1363 iptables_save_line(str, IPv6);\r
9f552e96 1364 }\r
abe9b855 1365\r
9f552e96 1366 if(free_min) /* allocate free bandwith if it is not zero... */ \r
1367 {\r
dee5592e 1368 /*-----------------------------------------------------------------*/\r
a25842fa 1369 puts("Generating free bandwith class ...");\r
dee5592e 1370 /*-----------------------------------------------------------------*/\r
a25842fa 1371 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
9f552e96 1372 tc, interface->name, parent, FREE_CLASS, free_min, free_max,burst, lowest_priority);\r
dee5592e 1373 safe_run(str);\r
1374 /* tc SFQ */\r
260c2719 1375 if(strcmpi(qos_leaf, "none"))\r
dee5592e 1376 {\r
9f552e96 1377 sprintf(str,"%s qdisc add dev %s parent 1:%d handle %d %s", tc, interface->name, FREE_CLASS, FREE_CLASS, qos_leaf);\r
dee5592e 1378 safe_run(str);\r
1379 } \r
1380 /* tc handle 1 fw flowid */\r
9f552e96 1381 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 1382 safe_run(str);\r
9f552e96 1383 }\r
57cbdd52 1384 /*-----------------------------------------------------------------*/\r
1385 puts("Generating bandwith class for overlimit packets...");\r
1386 /*-----------------------------------------------------------------*/\r
1387 sprintf(str, "%s class add dev %s parent 1:%d classid 1:%d htb rate %dkbit ceil %dkbit burst %dk prio %d",\r
1388 tc, interface->name, parent, OVERLIMIT_CLASS, overlimit_min, overlimit_max, burst, lowest_priority);\r
1389 safe_run(str);\r
9f552e96 1390 } \r
dee5592e 1391 printf("Total IP count: %d\n", i);\r
0b9c3c19 1392 run_iptables_restore();\r
260c2719 1393 if(log_file)\r
1394 {\r
1395 fclose(log_file);\r
1396 }\r
007c44c5 1397 return 0;\r
007c44c5 1398 /* that's all folks, thank you for reading it all the way up to this point ;-) */\r
1399 /* bad luck C<<1 is not yet finished, I promise no sprintf() next time... */\r
1400}\r
This page took 2.131721 seconds and 4 git commands to generate.