Project

General

Profile

Download (16.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	shaper.inc
5
	Copyright (C) 2004 Scott Ullrich
6
	Copyright (C) 2005 Bill Marquette
7
	All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	this list of conditions and the following disclaimer.
14

    
15
	2. Redistributions in binary form must reproduce the above copyright
16
	notice, this list of conditions and the following disclaimer in the
17
	documentation and/or other materials provided with the distribution.
18

    
19
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
21
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
23
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
	POSSIBILITY OF SUCH DAMAGE.
29

    
30
*/
31

    
32
/* include all configuration functions */
33
require_once("functions.inc");
34
require_once("pkg-utils.inc");
35
require_once("notices.inc");
36

    
37
function find_default_queue($interface) {
38
	global $config, $queue_cache;
39
	$qconfig = $config;
40

    
41
	/* quick return if we've already seen the default queue for this interface */
42
	if (isset($queue_cache['defq'][$interface]))
43
	return $queue_cache['defq'][$interface];
44

    
45
	if (is_array($qconfig['shaper']['queue'])) {
46
		foreach ($qconfig['shaper']['queue'] as $queue) {
47
			if(isset($queue['defaultqueue']) and ($queue['defaultqueue'] <> "")) {
48
				/* If this is a child queue */
49
				if(isset($queue['attachtoqueue'])) {
50
					if(is_subqueue_used_on_interface($queue['attachtoqueue'], $interface)) {
51
						$queue_cache['defq'][$interface] = $queue['name'];
52
						return $queue['name'];
53
					}
54
				} else {
55
					$queue_cache['defq'][$interface] = $queue['name'];
56
					return $queue['name'];
57
				}
58
			}
59
		}
60
	}
61

    
62
	/* unreachable */
63
	return null;
64
}
65

    
66
function get_ack_queue($interface) {
67
	global $config, $queue_cache;
68

    
69
	/* quick return if we've already seen the ack queue for this interface */
70
	if (isset($queue_cache['ackq'][$interface]))
71
	return $queue_cache['ackq'][$interface];
72

    
73
	$qconfig = $config;
74

    
75
	if (is_array($qconfig['shaper']['queue'])) {
76
		foreach ($qconfig['shaper']['queue'] as $queue) {
77
			if(isset($queue['ack']))
78
			if(isset($queue['attachtoqueue']))
79
			if(is_subqueue_used_on_interface($queue['attachtoqueue'], $interface)) {
80
				/* Add to cache */
81
				$queue_cache['ackq'][$interface] = $queue['name'];
82
				return $queue['name'];
83
			}
84
		}
85
	}
86
	/* unreachable */
87
	return null;
88
}
89

    
90
function filter_generate_altq_queues($altq_ints) {
91
	global $config;
92
	$altq_rules = "";
93
	if (is_array($config['shaper']['queue'])) {
94
		foreach ($config['shaper']['queue'] as $rule) {
95
			$options = "";
96
			// check to make sure we're actually using this queue.
97
			//if(stristr($altq_ints, $rule['name']) !== FALSE) {
98
			$altq_rules .= "queue {$rule['name']} ";
99
			if (isset($rule['bandwidth']) and $rule['bandwidth'] <> "")
100
			$altq_rules .= "bandwidth {$rule['bandwidth']}{$rule['bandwidthtype']} ";
101
			if (isset($rule['priority']) and $rule['priority'] <> "")
102
			$altq_rules .= "priority {$rule['priority']} ";
103
			if (isset($rule['qlimit']) and $rule['qlimit'] <> "")
104
			$altq_rules .= "qlimit {$rule['qlimit']} ";
105
			if(isset($rule['red']) and $rule['red'] <> "")
106
			$options .= " red";
107
			if(isset($rule['borrow']) and $rule['borrow'] <> "")
108
			$options .= " borrow";
109
			if(isset($rule['ecn']) and $rule['ecn'] <> "")
110
			$options .= " ecn";
111
			if(isset($rule['rio']) and $rule['rio'] <> "")
112
			$options .= " rio";
113
			if(isset($rule['defaultqueue']) and $rule['defaultqueue'] <> "")
114
			$options .= " default";
115
			if(isset($rule['upperlimit']) and $rule['upperlimit'] <> "") {
116
				$options .= " upperlimit({$rule['upperlimit1']} {$rule['upperlimit2']} {$rule['upperlimit3']})";
117
			}
118
			if(isset($rule['linkshare']) and $rule['linkshare'] <> "") {
119
				$options .= " linkshare({$rule['linkshare1']} {$rule['linkshare2']} {$rule['linkshare3']})";
120
			}
121
			if(isset($rule['realtime']) and $rule['realtime'] <> "") {
122
				$options .= " realtime({$rule['realtime1']} {$rule['realtime2']} {$rule['realtime3']})";
123
			}
124
			$scheduler_type = $config['shaper']['schedulertype'];
125
			$altq_rules .= "{$scheduler_type} ";
126
			if($options)
127
				$altq_rules .= "( {$options} )";
128
			$fsq="";
129
			foreach($config['shaper']['queue'] as $q) {
130
				if($q['attachtoqueue'] == $rule['name']) {
131
					if($fsq == "") {
132
						$altq_rules .= "{ ";
133
					}
134
					else if($fsq == "1") {
135
						$altq_rules .= ", ";
136
					}
137
					$altq_rules .= $q['name'];
138
					$fsq = "1";
139
				}
140
			}
141
			if($fsq == "1")
142
			$altq_rules .= " }";
143
			$altq_rules .= "\n";
144
			//}
145
		}
146
	}
147
	return $altq_rules;
148
}
149

    
150
/* Find a queue that's attached to this one and see if that queue is used on this interface */
151
function is_subqueue_used_on_interface($queuename, $interface) {
152
	global $config;
153
	$qconfig = $config;
154
	if (!is_array($qconfig['shaper']['queue'])) return 0;
155

    
156
	foreach ($qconfig['shaper']['queue'] as $queue) {
157
		if($queue['attachtoqueue'] == $queuename) {
158
			/* recurse if we're a parent queue */
159
			if ($queue['parentqueue'] == "on") {
160
				return is_subqueue_used_on_interface($queue['name'], $interface);
161
			}
162

    
163
			/* If we're not a parent check to see if the queue is used on this interface */
164
			$subqueue_interface = filter_is_queue_being_used_on_interface($queue['name'], $interface);
165
			if ($subqueue_interface != ""){
166
				return 1;
167
			}
168
		}
169
	}
170
	return 0;
171
}
172

    
173
function filter_is_queue_being_used_on_interface($queuename, $interface) {
174
	global $config;
175
	$lconfig = $config;
176

    
177
	if(!is_array($lconfig['shaper']['rule'])) return null;
178
	foreach($lconfig['shaper']['rule'] as $rule) {
179
		if(($rule['inqueue'] == $queuename && $rule['interface'] == $interface))
180
		return $interface;
181
	}
182
	return null;
183
}
184

    
185
function filter_setup_altq_interfaces() {
186
	global $config;
187
	$altq_rules  = "";
188
	$queue_names = "";
189
	$is_first = "";
190

    
191
	if(!is_array($config['shaper']['queue'])) return null;
192

    
193
	$ifdescrs = array('wan', 'lan');
194
	for ($j = 1; isset($config['interfaces']['opt' . $j]); $j++) {
195
		$ifdescrs[] = "opt" . $j;
196
	}
197
	foreach ($ifdescrs as $ifdescr => $ifname) {
198

    
199
		$queue_names = "";
200
		$is_first = "";
201

    
202
		$queue_names = find_root_queue($ifname);
203

    
204
		if($queue_names <> ""){
205
			$altq_rules .= "altq on {$config['interfaces'][$ifname]['if']} ";
206
			$bandwidth_arr = get_queue_bandwidth($queue_names);
207
			$bandwidth = "bandwidth {$bandwidth_arr['bandwidth']}{$bandwidth_arr['bandwidthtype']}";
208
			$altq_rules .= "{$config['shaper']['schedulertype']} {$bandwidth} ";
209
			$altq_rules .= "queue { {$queue_names} }";
210
		}
211
		$altq_rules .= "\n";
212

    
213
	}
214
	return $altq_rules;
215
}
216

    
217

    
218

    
219
/* Find the root queue for an interface */
220
function find_root_queue($ifname) {
221
	global $config;
222

    
223
	foreach ($config['shaper']['queue'] as $queue) {
224
		$rule_interface = "";
225
		$q = $queue;
226
		/* if we're a parentqueue and aren't attached to another queue we're probably a root */
227
		if ((isset($q['parentqueue']) && $q['parentqueue'] <> "") && (!isset($q['attachtoqueue']) || $q['attachtoqueue'] == "")) {
228
			/* Confirm that this is a valid queue for this interface */
229
			$rule_interface = is_subqueue_used_on_interface($q['name'], $ifname);
230
			if ($rule_interface == 1) {
231
				if (strlen($queue_names) > 0)
232
					$queue_names .= " ";
233
				$queue_names .= $q['name'];
234
			}
235
		}
236
	}
237
	return $queue_names;
238
}
239

    
240
function get_queue_bandwidth($name) {
241
	global $config;
242
	foreach ($config['shaper']['queue'] as $queue) {
243
		if ($queue['name'] == $name) {
244
			return array(
245
				'bandwidth' => $queue['bandwidth'],
246
				'bandwidthtype' => $queue['bandwidthtype']
247
			);
248
		}
249
	}
250
}
251

    
252
function is_queue_attached_children($name) {
253
	global $config;
254
	if (!is_array($config['shaper']['queue'])) return 0;
255
	foreach ($config['shaper']['queue'] as $queue) {
256
		if($queue['attachtoqueue'] == $name) return 1;
257
	}
258
	return 0;
259
}
260

    
261
function queue_interface_recursive($queuename) {
262
	global $config;
263
	foreach($config['shaper']['queue'] as $queue) {
264
		if($queue['attachtoqueue'] == $queuename) {
265
			$status = queue_interface_recursive($queue['name']);
266
			if($status <> "") return $status;
267
		}
268
		foreach($config['shaper']['rule'] as $rule) {
269
			if($rule['inqueue'] == $queuename)
270
			return $rule['interface'];
271
		}
272
	}
273

    
274
	/* unreachable */
275
	return null;
276
}
277

    
278
function is_subqueue($name) {
279
	global $config;
280
	$queues = $config['shaper']['queue']; /* must assign to keep from corrupting in memory $config */
281
	if (!is_array($queues)) return 0;
282
	foreach ($queues as $queue) {
283
		if($queue['attachtoqueue'] == $name) return 1;
284
	}
285
	return 0;
286
}
287

    
288
function filter_altq_get_queuename($queuenum) {
289
	global $config;
290
	$x=0;
291
	foreach($config['shaper']['queue'] as $rule) {
292
		if($x == $queuenum)
293
		return $rule['name'];
294
		$x++;
295
	}
296
	/* unreachable */
297
	return null;
298
}
299

    
300
function filter_generate_pf_altq_rules() {
301
	/* I don't think we're in IPFW anymore Toto */
302
	$i = 0;
303
	
304
	global $config, $g, $tcpflags;
305

    
306
	$lancfg = $config['interfaces']['lan'];
307
	$pptpdcfg = $config['pptpd'];
308
	$pppoecfg = $config['pppoe'];
309

    
310
	$lanif = $lancfg['if'];
311
	$wanif = get_real_wan_interface();
312

    
313
	$lansa = gen_subnet($lancfg['ipaddr'], $lancfg['subnet']);
314
	$lansn = $lancfg['subnet'];
315

    
316
	/* optional interfaces */
317
	$optcfg = array();
318
	generate_optcfg_array($optcfg);
319

    
320
	if ($pptpdcfg['mode'] == "server") {
321
		$pptpsa = $pptpdcfg['remoteip'];
322
		$pptpsn = $g['pptp_subnet'];
323
		if($config['pptp']['pptp_subnet'] <> "")
324
		$pptpsn = $config['pptp']['pptp_subnet'];
325
	}
326

    
327
	if ($pppoecfg['mode'] == "server") {
328
		$pppoesa = $pppoecfg['remoteip'];
329
		$pppoesn = $g['pppoe_subnet'];
330
		if($config['pppoe']['pppoe_subnet'] <> "")
331
		$pppoesn = $config['pppoe']['pppoe_subnet'];
332
	}
333

    
334
	/* generate rules */
335
	if (isset($config['shaper']['rule']))
336
	foreach ($config['shaper']['rule'] as $rule) {
337

    
338
		/* don't include disabled rules */
339
		if (isset($rule['disabled'])) {
340
			$i++;
341
			continue;
342
		}
343

    
344
		switch($rule['interface']) {
345
			case "pptp": /* does the rule deal with a PPTP interface? */
346
				if ($pptpdcfg['mode'] != "server") {
347
					if (($rule['source']['network'] == "pptp") ||
348
					($rule['destination']['network'] == "pptp")) {
349
						$i++;
350
						continue;
351
					}
352
				}
353

    
354
				$nif = $g['n_pptp_units'];
355
				if($config['pptp']['n_pptp_units'] <> "")
356
					$nif = $config['pptp']['n_pptp_units'];
357

    
358
				$ispptp = true;
359
				break;
360

    
361
			case "pppoe": /* does the rule deal with a PPPOE interface? */
362
				if ($pppoecfg['mode'] != "server") {
363
					if (($rule['source']['network'] == "pppoe") ||
364
					($rule['destination']['network'] == "pppoe")) {
365
						$i++;
366
						continue;
367
					}
368
				}
369

    
370
				$nif = $g['n_pppoe_units'];
371
				if($config['pppoe']['n_pppoe_units'] <> "")
372
					$nif = $config['pppoe']['n_pppoe_units'];
373

    
374
				$ispppoe = true;
375
				break;
376
			default:
377
				if (strstr($rule['interface'], "opt")) {
378
					if (!array_key_exists($rule['interface'], $optcfg)) {
379
						$i++;
380
						continue;
381
					}
382
				}
383
				$nif = 1;
384
				$ispptp = false;
385
				$ispppoe = false;
386
		}
387

    
388
		if (strstr($rule['source']['network'], "opt")) {
389
			if (!array_key_exists($rule['source']['network'], $optcfg)) {
390
				$i++;
391
				continue;
392
			}
393
		}
394
		if (strstr($rule['destination']['network'], "opt")) {
395
			if (!array_key_exists($rule['destination']['network'], $optcfg)) {
396
				$i++;
397
				continue;
398
			}
399
		}
400

    
401
		/* check for unresolvable aliases */
402
		if ($rule['source']['address'] && !alias_expand($rule['source']['address'])) {
403
			$i++;
404
			continue;
405
		}
406
		if ($rule['destination']['address'] && !alias_expand($rule['destination']['address'])) {
407
			$i++;
408
			continue;
409
		}
410

    
411
		for ($iif = 0; $iif < $nif; $iif++) {
412
			foreach ( array('in', 'out') as $direction) {
413

    
414
				$line = "pass {$direction} on ";
415

    
416
				if ($ispptp) {
417
					$line .= " ng" . ($iif+1);
418
				} else {
419
					if($ispppoe) {
420
						$line .= " ng" . ($iif+1);
421
					} else {
422
						$if = $config['interfaces'][$rule['interface']]['if'];
423
					}
424

    
425
					if ($rule['interface'] == "wan") {
426
						if($direction=="in") {
427
							$if = $wanif;
428
						} else {
429
							$if = $lanif;
430
						}
431
					} else {
432
						if($rule['interface'] == "lan") {
433
							if($direction=="in") {
434
								$if = $lanif;
435
							} else {
436
								$if = $wanif;
437
							}
438
						}
439
					}
440

    
441
					$line .= " {$if} ";
442
				}
443

    
444
				if (isset($rule['protocol'])) {
445
					$line .= "proto {$rule['protocol']} ";
446
				}
447

    
448
				/* source address */
449
				/* Using any for source on 'out' is due to not knowing what
450
				 * the packet looks like after NAT occurs
451
				 */
452
				if (isset($rule['source']['any']) || $direction == "out") {
453
					$src = "any";
454
				} else if ($rule['source']['network']) {
455
					if (strstr($rule['source']['network'], "opt")) {
456
						$src = $optcfg[$rule['source']['network']]['sa'] . "/" .
457
						$optcfg[$rule['source']['network']]['sn'];
458
					} else {
459
						switch ($rule['source']['network']) {
460
							case 'lan':
461
							$src = "$lansa/$lansn";
462
							break;
463
							case 'pptp':
464
							$src = "$pptpsa/$pptpsn";
465
							break;
466
							case 'pppoe':
467
							$src = "$pppoesa/$pppoesn";
468
							break;
469
						}
470
					}
471
				} else if ($rule['source']['address']) {
472
					$src = alias_expand($rule['source']['address']);
473
					if(!$src)
474
						$src = $rule['source']['address'];
475
				}
476

    
477
				if (!$src) {
478
					printf("No source address found in rule $i\n");
479
					break;
480
				}
481

    
482
				if (isset($rule['source']['not'])) {
483
					$line .= "from ! $src ";
484
				} else {
485
					$line .= "from $src ";
486
				}
487

    
488
				if (!isset($rule['protocol']) || in_array($rule['protocol'], array("tcp","udp"))) {
489
					if ($rule['source']['port']) {
490
						/*
491
						* Check to see if port is a alias.  If so grab it and
492
						* enclose it in { } to pass to pf.
493
						*
494
						* Otherwise combine the portrange into one if its only
495
						* one item.
496
						*/
497
						$src = alias_expand($rule['source']['port']);
498
						if($src <> "") {
499
							$line .= "port {$src}";
500
						} else {
501
							$srcport = explode("-", $rule['source']['port']);
502
							if ((!$srcport[1]) || ($srcport[0] == $srcport[1])) {
503
								$line .= "port {$srcport[0]} ";
504
							} else {
505
								$line .= "port {$srcport[0]}:{$srcport[1]} ";
506
							}
507
						}
508
					}
509
				}
510

    
511
				/* destination address */
512
				if (isset($rule['destination']['any'])) {
513
					$dst = "any";
514
				} else if ($rule['destination']['network']) {
515

    
516
					if (strstr($rule['destination']['network'], "opt")) {
517
						$dst = $optcfg[$rule['destination']['network']]['sa'] . "/" .
518
						$optcfg[$rule['destination']['network']]['sn'];
519
					} else {
520
						switch ($rule['destination']['network']) {
521
							case 'lan':
522
							$dst = "$lansa/$lansn";
523
							break;
524
							case 'pptp':
525
							$dst = "$pptpsa/$pptpsn";
526
							break;
527
							case 'pppoe':
528
							$dst = "$pppoesa/$pppoesn";
529
							break;
530
						}
531
					}
532
				} else if ($rule['destination']['address']) {
533
					$dst = alias_expand($rule['destination']['address']);
534
					if(!$dst)
535
						$dst = $rule['destination']['address'];
536
				}
537

    
538
				if (!$dst) {
539
					printf("No destination address found in rule $i\n");
540
					break;
541
				}
542

    
543
				if (isset($rule['destination']['not'])) {
544
					$line .= "to ! $dst ";
545
				} else {
546
					$line .= "to $dst ";
547
				}
548

    
549
				if (!isset($rule['protocol']) || in_array($rule['protocol'], array("tcp","udp"))) {
550
					if ($rule['destination']['port']) {
551
						$dst = alias_expand($rule['destination']['port']);
552
						/*
553
						* Check to see if port is a alias.  If so grab it and
554
						* enclose it in { } to pass to pf.
555
						*
556
						* Otherwise combine the portrange into one if its only
557
						* one item.
558
						*/
559
						if($dst <> "") {
560
							$line .= "port {$dst}";
561
						} else {
562
							$dstport = explode("-", $rule['destination']['port']);
563
							if ((!$dstport[1]) || ($dstport[0] == $dstport[1])) {
564
								$line .= "port {$dstport[0]} ";
565
							} else {
566
								$line .= "port {$dstport[0]}:{$dstport[1]} ";
567
							}
568
						}
569
					}
570
				}
571

    
572
				if ($rule['iptos'])
573
				$line .= "tos {$rule['iptos']} ";
574

    
575
				$inflags = explode(",", $rule['tcpflags']);
576
				$flags = " flags ";
577
				foreach ($tcpflags as $tcpflag) {
578
					if (array_search($tcpflag, $inflags) !== false) {
579
						$flags .= strtoupper(substr($tcpflag, 0, 1));
580
					}
581
				}
582
				if($flags <> " flags ")
583
				$line .= "{$flags}/SAFRPU ";
584

    
585
				$qtag = "{$direction}queue";
586
				$line .= " keep state tagged unshaped tag {$rule[$qtag]} ";
587

    
588
				$line .= "\n";
589
				$shaperrules .= $line;
590
			}
591
		}
592

    
593
		$i++;
594
	}
595

    
596
	return $shaperrules;
597
}
598

    
599
?>
(19-19/27)