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