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