Project

General

Profile

Download (14.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	status_dhcpv6_leases.php
5
	Copyright (C) 2004-2009 Scott Ullrich
6
	Copyright (C) 2011 Seth Mos
7
	All rights reserved.
8

    
9
	originially part of m0n0wall (http://m0n0.ch/wall)
10
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
11
	All rights reserved.
12

    
13
	Redistribution and use in source and binary forms, with or without
14
	modification, are permitted provided that the following conditions are met:
15

    
16
	1. Redistributions of source code must retain the above copyright notice,
17
	   this list of conditions and the following disclaimer.
18

    
19
	2. Redistributions in binary form must reproduce the above copyright
20
	   notice, this list of conditions and the following disclaimer in the
21
	   documentation and/or other materials provided with the distribution.
22

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

    
35
/*
36
	pfSense_BUILDER_BINARIES:	/usr/bin/awk	/bin/cat	/usr/sbin/ndp	/usr/bin/wc	/usr/bin/grep
37
	pfSense_MODULE:	dhcpserver
38
*/
39

    
40
##|+PRIV
41
##|*IDENT=page-status-dhcpv6leases
42
##|*NAME=Status: DHCPv6 leases page
43
##|*DESCR=Allow access to the 'Status: DHCPv6 leases' page.
44
##|*MATCH=status_dhcpv6_leases.php*
45
##|-PRIV
46

    
47
require("guiconfig.inc");
48

    
49
$pgtitle = array(gettext("Status"),gettext("DHCPv6 leases"));
50

    
51
$leasesfile = "{$g['dhcpd_chroot_path']}/var/db/dhcpd6.leases";
52

    
53
if (($_GET['deleteip']) && (is_ipaddr($_GET['deleteip']))) {
54
	/* Stop DHCPD */
55
	killbyname("dhcpd");
56

    
57
	/* Read existing leases */
58
	$leases_contents = explode("\n", file_get_contents($leasesfile));
59
	$newleases_contents = array();
60
	$i=0;
61
	while ($i < count($leases_contents)) {
62
		/* Find the lease(s) we want to delete */
63
		if ($leases_contents[$i] == "lease {$_GET['deleteip']} {") {
64
			/* Skip to the end of the lease declaration */
65
			do {
66
				$i++;
67
			} while ($leases_contents[$i] != "}");
68
		} else {
69
			/* It's a line we want to keep, copy it over. */
70
			$newleases_contents[] = $leases_contents[$i];
71
		}
72
		$i++;
73
	}
74

    
75
	/* Write out the new leases file */
76
	$fd = fopen($leasesfile, 'w');
77
	fwrite($fd, implode("\n", $newleases_contents));
78
	fclose($fd);
79

    
80
	/* Restart DHCP Service */
81
	services_dhcpd_configure();
82
	header("Location: status_dhcpv6_leases.php?all={$_GET['all']}");
83
}
84

    
85
include("head.inc");
86

    
87
?>
88

    
89
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
90
<?php include("fbegin.inc"); ?>
91
<?php
92

    
93
function leasecmp($a, $b) {
94
	return strcmp($a[$_GET['order']], $b[$_GET['order']]);
95
}
96

    
97
function adjust_gmt($dt) {
98
	$ts = strtotime($dt . " GMT");
99
	return strftime("%Y/%m/%d %H:%M:%S", $ts);
100
}
101

    
102
function remove_duplicate($array, $field) {
103
	foreach ($array as $sub)
104
		$cmp[] = $sub[$field];
105
	$unique = array_unique(array_reverse($cmp,true));
106
	foreach ($unique as $k => $rien)
107
		$new[] = $array[$k];
108
	return $new;
109
}
110

    
111
function parse_duid($duid_string) {
112
	$parsed_duid = array();
113
	for ($i=0; $i < strlen($duid_string); $i++) {
114
		$s = substr($duid_string, $i, 1);
115
		if ($s == '\\') {
116
			$n = substr($duid_string, $i+1, 1);
117
			if (($n == '\\') || ($n == '"')) {
118
				$parsed_duid[] = sprintf("%02x", ord($n));
119
			} elseif (is_numeric($n)) {
120
				$parsed_duid[] = sprintf("%02x", octdec(substr($duid_string, $i+1, 3)));
121
				$i += 3;
122
			}
123
		} else {
124
			$parsed_duid[] = sprintf("%02x", ord($s));
125
		}
126
	}
127
	$iaid = array_slice($parsed_duid, 0, 4);
128
	$duid = array_slice($parsed_duid, 4);
129
	return array($iaid, $duid);
130
}
131

    
132
$awk = "/usr/bin/awk";
133

    
134
/* this pattern sticks comments into a single array item */
135
$cleanpattern = "'{ gsub(\"^#.*\", \"\");} { gsub(\"^server-duid.*\", \"\");} { gsub(\";\", \"\"); print;}'";
136
/* We then split the leases file by } */
137
$splitpattern = "'BEGIN { RS=\"}\";} {for (i=1; i<=NF; i++) printf \"%s \", \$i; printf \"}\\n\";}'";
138

    
139
/* stuff the leases file in a proper format into a array by line */
140
exec("/bin/cat {$leasesfile} | {$awk} {$cleanpattern} | {$awk} {$splitpattern} | /usr/bin/grep '^ia-na'", $leases_content);
141
$leases_count = count($leases_content);
142
exec("/usr/sbin/ndp -an", $rawdata);
143
$ndpdata = array();
144
foreach ($rawdata as $line) {
145
	$elements = preg_split('/\s+/ ',$line);
146
	if ($elements[1] != "(incomplete)") {
147
		$ndpent = array();
148
		$ip = trim(str_replace(array('(',')'),'',$elements[0]));
149
		$ndpent['mac'] = trim($elements[1]);
150
		$ndpent['interface'] = trim($elements[2]);
151
		$ndpdata[$ip] = $ndpent;
152
	}
153
}
154

    
155
$pools = array();
156
$leases = array();
157
$i = 0;
158
$l = 0;
159
$p = 0;
160

    
161
// Put everything together again
162
while($i < $leases_count) {
163
	/* split the line by space */
164
	$duid_split = array();
165
	preg_match('/ia-na "(.*)" { (.*)/ ', $leases_content[$i], $duid_split);
166
	if (!empty($duid_split[1])) {
167
		$iaid_duid = parse_duid($duid_split[1]);
168
		$leases[$l]['iaid'] = hexdec(implode("", array_reverse($iaid_duid[0])));
169
		$leases[$l]['duid'] = implode(":", $iaid_duid[1]);
170
		$data = explode(" ", $duid_split[2]);
171
	} else {
172
		$data = explode(" ", $leases_content[$i]);
173
	}
174
	/* walk the fields */
175
	$f = 0;
176
	$fcount = count($data);
177
	/* with less then 12 fields there is nothing useful */
178
	if($fcount < 12) {
179
		$i++;
180
		continue;
181
	}
182
	while($f < $fcount) {
183
		switch($data[$f]) {
184
			case "failover":
185
				$pools[$p]['name'] = $data[$f+2];
186
				$pools[$p]['mystate'] = $data[$f+7];
187
				$pools[$p]['peerstate'] = $data[$f+14];
188
				$pools[$p]['mydate'] = $data[$f+10];
189
				$pools[$p]['mydate'] .= " " . $data[$f+11];
190
				$pools[$p]['peerdate'] = $data[$f+17];
191
				$pools[$p]['peerdate'] .= " " . $data[$f+18];
192
				$p++;
193
				$i++;
194
				continue 3;
195
			case "ia-na":
196
				if ($data[$f+1][0] == '"') {
197
					$duid = "";
198
					/* FIXME: This needs a safety belt to prevent an infinite loop */
199
					while ($data[$f][strlen($data[$f])-1] != '"') {
200
						$duid .= " " . $data[$f+1];
201
						$f++;
202
					}
203
					$leases[$l]['duid'] = $duid;
204
				} else {
205
					$leases[$l]['duid'] = $data[$f+1];
206
				}
207
				$leases[$l]['type'] = "dynamic";
208
				$f = $f+2;
209
				break;
210
			case "iaaddr":
211
				$leases[$l]['ip'] = $data[$f+1];
212
				$leases[$l]['type'] = "dynamic";
213
				if (in_array($leases[$l]['ip'], array_keys($ndpdata))) {
214
					$leases[$l]['online'] = 'online';
215
				} else {
216
					$leases[$l]['online'] = 'offline';
217
				}
218
				$f = $f+2;
219
				break;
220
			case "starts":
221
				$leases[$l]['start'] = $data[$f+2];
222
				$leases[$l]['start'] .= " " . $data[$f+3];
223
				$f = $f+3;
224
				break;
225
			case "ends":
226
				$leases[$l]['end'] = $data[$f+2];
227
				$leases[$l]['end'] .= " " . $data[$f+3];
228
				$f = $f+3;
229
				break;
230
			case "tstp":
231
				$f = $f+3;
232
				break;
233
			case "tsfp":
234
				$f = $f+3;
235
				break;
236
			case "atsfp":
237
				$f = $f+3;
238
				break;
239
			case "cltt":
240
				$leases[$l]['start'] = $data[$f+2];
241
				$leases[$l]['start'] .= " " . $data[$f+3];
242
				$f = $f+3;
243
				break;
244
			case "binding":
245
				switch($data[$f+2]) {
246
					case "active":
247
						$leases[$l]['act'] = "active";
248
						break;
249
					case "free":
250
						$leases[$l]['act'] = "expired";
251
						$leases[$l]['online'] = "offline";
252
						break;
253
					case "backup":
254
						$leases[$l]['act'] = "reserved";
255
						$leases[$l]['online'] = "offline";
256
						break;
257
				}
258
				$f = $f+1;
259
				break;
260
			case "next":
261
				/* skip the next binding statement */
262
				$f = $f+3;
263
				break;
264
			case "hardware":
265
				$f = $f+2;
266
				break;
267
			case "client-hostname":
268
				if($data[$f+1] <> "") {
269
					$leases[$l]['hostname'] = preg_replace('/"/','',$data[$f+1]);
270
				} else {
271
					$hostname = gethostbyaddr($leases[$l]['ip']);
272
					if($hostname <> "") {
273
						$leases[$l]['hostname'] = $hostname;
274
					}
275
				}
276
				$f = $f+1;
277
				break;
278
			case "uid":
279
				$f = $f+1;
280
				break;
281
		}
282
		$f++;
283
	}
284
	$l++;
285
	$i++;
286
}
287

    
288
if(count($leases) > 0) {
289
	$leases = remove_duplicate($leases,"ip");
290
}
291

    
292
if(count($pools) > 0) {
293
	$pools = remove_duplicate($pools,"name");
294
	asort($pools);
295
}
296

    
297
foreach($config['interfaces'] as $ifname => $ifarr) {
298
	if (is_array($config['dhcpdv6'][$ifname]) && 
299
		is_array($config['dhcpdv6'][$ifname]['staticmap'])) {
300
		foreach($config['dhcpdv6'][$ifname]['staticmap'] as $static) {
301
			$slease = array();
302
			$slease['ip'] = $static['ipaddrv6'];
303
			$slease['type'] = "static";
304
			$slease['duid'] = $static['duid'];
305
			$slease['start'] = "";
306
			$slease['end'] = "";
307
			$slease['hostname'] = htmlentities($static['hostname']);
308
			$slease['act'] = "static";
309
			if (in_array($slease['ip'], array_keys($ndpdata))) {
310
				$slease['online'] = 'online';
311
			} else {
312
				$slease['online'] = 'offline';
313
			}
314

    
315
			$leases[] = $slease;
316
		}
317
	}
318
}
319

    
320
if ($_GET['order'])
321
	usort($leases, "leasecmp");
322

    
323
/* only print pool status when we have one */
324
if(count($pools) > 0) {
325
?>
326
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
327
  <tr>
328
    <td class="listhdrr"><?=gettext("Failover Group"); ?></a></td>
329
    <td class="listhdrr"><?=gettext("My State"); ?></a></td>
330
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
331
    <td class="listhdrr"><?=gettext("Peer State"); ?></a></td>
332
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
333
  </tr>
334
<?php
335
foreach ($pools as $data) {
336
	echo "<tr>\n";
337
	echo "<td class=\"listlr\">{$fspans}{$data['name']}{$fspane}&nbsp;</td>\n";
338
	echo "<td class=\"listr\">{$fspans}{$data['mystate']}{$fspane}&nbsp;</td>\n";
339
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['mydate']) . "{$fspane}&nbsp;</td>\n";
340
	echo "<td class=\"listr\">{$fspans}{$data['peerstate']}{$fspane}&nbsp;</td>\n";
341
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['peerdate']) . "{$fspane}&nbsp;</td>\n";
342
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
343
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
344
	echo "</tr>\n";
345
}
346

    
347
?>
348
</table>
349

    
350
<?php
351
/* only print pool status when we have one */
352
}
353
?>
354

    
355
<p>
356

    
357
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
358
  <tr>
359
    <td class="listhdrr"><a href="#"><?=gettext("IPv6 address"); ?></a></td>
360
    <td class="listhdrr"><a href="#"><?=gettext("IAID"); ?></a></td>
361
    <td class="listhdrr"><a href="#"><?=gettext("DUID"); ?></a></td>
362
    <td class="listhdrr"><a href="#"><?=gettext("Hostname/MAC"); ?></a></td>
363
    <td class="listhdrr"><a href="#"><?=gettext("Start"); ?></a></td>
364
    <td class="listhdrr"><a href="#"><?=gettext("End"); ?></a></td>
365
    <td class="listhdrr"><a href="#"><?=gettext("Online"); ?></a></td>
366
    <td class="listhdrr"><a href="#"><?=gettext("Lease Type"); ?></a></td>
367
	</tr>
368
<?php
369
foreach ($leases as $data) {
370
	if (($data['act'] == "active") || ($data['act'] == "static") || ($_GET['all'] == 1)) {
371
		if ($data['act'] != "active" && $data['act'] != "static") {
372
			$fspans = "<span class=\"gray\">";
373
			$fspane = "</span>";
374
		} else {
375
			$fspans = $fspane = "";
376
		}
377

    
378
		if ($data['act'] == "static") {
379
			foreach ($config['dhcpdv6'] as $dhcpif => $dhcpifconf) {
380
				if(is_array($dhcpifconf['staticmap'])) {
381
					foreach ($dhcpifconf['staticmap'] as $staticent) {
382
						if ($data['ip'] == $staticent['ipaddr']) {
383
							$data['if'] = $dhcpif;
384
							break;
385
						}
386
					}
387
				}
388
				/* exit as soon as we have an interface */
389
				if ($data['if'] != "")
390
					break;
391
			}
392
		} else {
393
			$data['if'] = convert_real_interface_to_friendly_interface_name(guess_interface_from_ip($data['ip']));
394
                }		
395
		echo "<tr>\n";
396
                echo "<td class=\"listlr\">{$fspans}{$data['ip']}{$fspane}&nbsp;</td>\n";
397
		echo "<td class=\"listr\">{$fspans}{$data['iaid']}{$fspane}&nbsp;</td>\n";
398
		echo "<td class=\"listr\">{$fspans}{$data['duid']}{$fspane}&nbsp;</td>\n";
399
		echo "<td class=\"listr\">{$fspans}";
400
		if (!empty($data['hostname'])) {
401
			echo htmlentities($data['hostname']) . "<br/>";
402
		}
403
		echo htmlentities($ndpdata[$data['ip']]['mac']);
404
		echo "{$fspane}&nbsp;</td>\n";
405
				if ($data['type'] != "static") {
406
					echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['start']) . "{$fspane}&nbsp;</td>\n";
407
					echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['end']) . "{$fspane}&nbsp;</td>\n";
408
				} else {
409
					echo "<td class=\"listr\">{$fspans} n/a {$fspane}&nbsp;</td>\n";
410
					echo "<td class=\"listr\">{$fspans} n/a {$fspane}&nbsp;</td>\n";
411
				}
412
                echo "<td class=\"listr\">{$fspans}{$data['online']}{$fspane}&nbsp;</td>\n";
413
                echo "<td class=\"listr\">{$fspans}{$data['act']}{$fspane}&nbsp;</td>\n";
414
		
415
		if ($data['type'] == "dynamic") {
416
			echo "<td valign=\"middle\"><a href=\"services_dhcpv6_edit.php?if={$data['if']}&duid={$data['duid']}&hostname={$data['hostname']}\">";
417
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_plus.gif\" width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("add a static mapping for this MAC address") ."\"></a></td>\n";
418
		} else {
419
                	echo "<td class=\"list\" valign=\"middle\">";
420
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_plus_mo.gif\" width=\"17\" height=\"17\" border=\"0\"></td>\n";
421
		}
422

    
423
		/* Only show the button for offline dynamic leases */
424
		if (($data['type'] == "dynamic") && ($data['online'] != "online")) {
425
			echo "<td class=\"list\" valign=\"middle\"><a href=\"status_dhcpv6_leases.php?deleteip={$data['ip']}&all=" . htmlspecialchars($_GET['all']) . "\">";
426
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("delete this DHCP lease") . "\"></a></td>\n";
427
		}
428
                echo "</tr>\n";
429
	}
430
}
431

    
432
?>
433
</table>
434
<p>
435
<form action="status_dhcpv6_leases.php" method="GET">
436
<input type="hidden" name="order" value="<?=htmlspecialchars($_GET['order']);?>">
437
<?php if ($_GET['all']): ?>
438
<input type="hidden" name="all" value="0">
439
<input type="submit" class="formbtn" value="<?=gettext("Show active and static leases only"); ?>">
440
<?php else: ?>
441
<input type="hidden" name="all" value="1">
442
<input type="submit" class="formbtn" value="<?=gettext("Show all configured leases"); ?>">
443
<?php endif; ?>
444
</form>
445
<?php if($leases == 0): ?>
446
<p><strong><?=gettext("No leases file found. Is the DHCP server active"); ?>?</strong></p>
447
<?php endif; ?>
448

    
449
<?php include("fend.inc"); ?>
450
</body>
451
</html>
(171-171/239)