Project

General

Profile

Download (14.7 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
require_once("config.inc");
49

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

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

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

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

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

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

    
86
include("head.inc");
87

    
88
?>
89

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

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

    
98
function adjust_gmt($dt) {
99
	global $config; 
100
	$dhcpdv6 = $config['dhcpdv6'];
101
	foreach ($dhcpdv6 as $dhcpv6leaseinlocaltime) {
102
		$dhcpv6leaseinlocaltime = $dhcpv6leaseinlocaltime['dhcpv6leaseinlocaltime'];
103
		if ($dhcpv6leaseinlocaltime == "yes") 
104
			break;
105
	}
106
        $timezone = $config['system']['timezone'];
107
	$ts = strtotime($dt . " GMT");
108
	if ($dhcpv6leaseinlocaltime == "yes") {
109
		$this_tz = new DateTimeZone($timezone); 
110
		$dhcp_lt = new DateTime(strftime("%I:%M:%S%p", $ts), $this_tz); 
111
		$offset = $this_tz->getOffset($dhcp_lt);
112
		$ts = $ts + $offset;
113
		return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
114
        }
115
	else
116
		return strftime("%Y/%m/%d %H:%M:%S", $ts);
117
}
118

    
119
function remove_duplicate($array, $field) {
120
	foreach ($array as $sub)
121
		$cmp[] = $sub[$field];
122
	$unique = array_unique(array_reverse($cmp,true));
123
	foreach ($unique as $k => $rien)
124
		$new[] = $array[$k];
125
	return $new;
126
}
127

    
128
function parse_duid($duid_string) {
129
	$parsed_duid = array();
130
	for ($i=0; $i < strlen($duid_string); $i++) {
131
		$s = substr($duid_string, $i, 1);
132
		if ($s == '\\') {
133
			$n = substr($duid_string, $i+1, 1);
134
			if (($n == '\\') || ($n == '"')) {
135
				$parsed_duid[] = sprintf("%02x", ord($n));
136
			} elseif (is_numeric($n)) {
137
				$parsed_duid[] = sprintf("%02x", octdec(substr($duid_string, $i+1, 3)));
138
				$i += 3;
139
			}
140
		} else {
141
			$parsed_duid[] = sprintf("%02x", ord($s));
142
		}
143
	}
144
	$iaid = array_slice($parsed_duid, 0, 4);
145
	$duid = array_slice($parsed_duid, 4);
146
	return array($iaid, $duid);
147
}
148

    
149
$awk = "/usr/bin/awk";
150

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

    
156
/* stuff the leases file in a proper format into a array by line */
157
exec("/bin/cat {$leasesfile} | {$awk} {$cleanpattern} | {$awk} {$splitpattern} | /usr/bin/grep '^ia-na'", $leases_content);
158
$leases_count = count($leases_content);
159
exec("/usr/sbin/ndp -an", $rawdata);
160
$ndpdata = array();
161
foreach ($rawdata as $line) {
162
	$elements = preg_split('/\s+/ ',$line);
163
	if ($elements[1] != "(incomplete)") {
164
		$ndpent = array();
165
		$ip = trim(str_replace(array('(',')'),'',$elements[0]));
166
		$ndpent['mac'] = trim($elements[1]);
167
		$ndpent['interface'] = trim($elements[2]);
168
		$ndpdata[$ip] = $ndpent;
169
	}
170
}
171

    
172
$pools = array();
173
$leases = array();
174
$i = 0;
175
$l = 0;
176
$p = 0;
177

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

    
305
if(count($leases) > 0) {
306
	$leases = remove_duplicate($leases,"ip");
307
}
308

    
309
if(count($pools) > 0) {
310
	$pools = remove_duplicate($pools,"name");
311
	asort($pools);
312
}
313

    
314
foreach($config['interfaces'] as $ifname => $ifarr) {
315
	if (is_array($config['dhcpdv6'][$ifname]) && 
316
		is_array($config['dhcpdv6'][$ifname]['staticmap'])) {
317
		foreach($config['dhcpdv6'][$ifname]['staticmap'] as $static) {
318
			$slease = array();
319
			$slease['ip'] = $static['ipaddrv6'];
320
			$slease['type'] = "static";
321
			$slease['duid'] = $static['duid'];
322
			$slease['start'] = "";
323
			$slease['end'] = "";
324
			$slease['hostname'] = htmlentities($static['hostname']);
325
			$slease['act'] = "static";
326
			if (in_array($slease['ip'], array_keys($ndpdata))) {
327
				$slease['online'] = 'online';
328
			} else {
329
				$slease['online'] = 'offline';
330
			}
331

    
332
			$leases[] = $slease;
333
		}
334
	}
335
}
336

    
337
if ($_GET['order'])
338
	usort($leases, "leasecmp");
339

    
340
/* only print pool status when we have one */
341
if(count($pools) > 0) {
342
?>
343
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
344
  <tr>
345
    <td class="listhdrr"><?=gettext("Failover Group"); ?></a></td>
346
    <td class="listhdrr"><?=gettext("My State"); ?></a></td>
347
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
348
    <td class="listhdrr"><?=gettext("Peer State"); ?></a></td>
349
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
350
  </tr>
351
<?php
352
foreach ($pools as $data) {
353
	echo "<tr>\n";
354
	echo "<td class=\"listlr\">{$fspans}{$data['name']}{$fspane}&nbsp;</td>\n";
355
	echo "<td class=\"listr\">{$fspans}{$data['mystate']}{$fspane}&nbsp;</td>\n";
356
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['mydate']) . "{$fspane}&nbsp;</td>\n";
357
	echo "<td class=\"listr\">{$fspans}{$data['peerstate']}{$fspane}&nbsp;</td>\n";
358
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['peerdate']) . "{$fspane}&nbsp;</td>\n";
359
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
360
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
361
	echo "</tr>\n";
362
}
363

    
364
?>
365
</table>
366

    
367
<?php
368
/* only print pool status when we have one */
369
}
370
?>
371

    
372
<p>
373

    
374
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
375
  <tr>
376
    <td class="listhdrr"><a href="#"><?=gettext("IPv6 address"); ?></a></td>
377
    <td class="listhdrr"><a href="#"><?=gettext("IAID"); ?></a></td>
378
    <td class="listhdrr"><a href="#"><?=gettext("DUID"); ?></a></td>
379
    <td class="listhdrr"><a href="#"><?=gettext("Hostname/MAC"); ?></a></td>
380
    <td class="listhdrr"><a href="#"><?=gettext("Start"); ?></a></td>
381
    <td class="listhdrr"><a href="#"><?=gettext("End"); ?></a></td>
382
    <td class="listhdrr"><a href="#"><?=gettext("Online"); ?></a></td>
383
    <td class="listhdrr"><a href="#"><?=gettext("Lease Type"); ?></a></td>
384
	</tr>
385
<?php
386
foreach ($leases as $data) {
387
	if (($data['act'] == "active") || ($data['act'] == "static") || ($_GET['all'] == 1)) {
388
		if ($data['act'] != "active" && $data['act'] != "static") {
389
			$fspans = "<span class=\"gray\">";
390
			$fspane = "</span>";
391
		} else {
392
			$fspans = $fspane = "";
393
		}
394

    
395
		if ($data['act'] == "static") {
396
			foreach ($config['dhcpdv6'] as $dhcpif => $dhcpifconf) {
397
				if(is_array($dhcpifconf['staticmap'])) {
398
					foreach ($dhcpifconf['staticmap'] as $staticent) {
399
						if ($data['ip'] == $staticent['ipaddr']) {
400
							$data['if'] = $dhcpif;
401
							break;
402
						}
403
					}
404
				}
405
				/* exit as soon as we have an interface */
406
				if ($data['if'] != "")
407
					break;
408
			}
409
		} else {
410
			$data['if'] = convert_real_interface_to_friendly_interface_name(guess_interface_from_ip($data['ip']));
411
                }		
412
		echo "<tr>\n";
413
                echo "<td class=\"listlr\">{$fspans}{$data['ip']}{$fspane}&nbsp;</td>\n";
414
		echo "<td class=\"listr\">{$fspans}{$data['iaid']}{$fspane}&nbsp;</td>\n";
415
		echo "<td class=\"listr\">{$fspans}{$data['duid']}{$fspane}&nbsp;</td>\n";
416
		echo "<td class=\"listr\">{$fspans}";
417
		if (!empty($data['hostname'])) {
418
			echo htmlentities($data['hostname']) . "<br/>";
419
		}
420
		echo htmlentities($ndpdata[$data['ip']]['mac']);
421
		echo "{$fspane}&nbsp;</td>\n";
422
				if ($data['type'] != "static") {
423
					echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['start']) . "{$fspane}&nbsp;</td>\n";
424
					echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['end']) . "{$fspane}&nbsp;</td>\n";
425
				} else {
426
					echo "<td class=\"listr\">{$fspans} n/a {$fspane}&nbsp;</td>\n";
427
					echo "<td class=\"listr\">{$fspans} n/a {$fspane}&nbsp;</td>\n";
428
				}
429
                echo "<td class=\"listr\">{$fspans}{$data['online']}{$fspane}&nbsp;</td>\n";
430
                echo "<td class=\"listr\">{$fspans}{$data['act']}{$fspane}&nbsp;</td>\n";
431
		
432
		if ($data['type'] == "dynamic") {
433
			echo "<td valign=\"middle\"><a href=\"services_dhcpv6_edit.php?if={$data['if']}&duid={$data['duid']}&hostname={$data['hostname']}\">";
434
			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";
435
		} else {
436
                	echo "<td class=\"list\" valign=\"middle\">";
437
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_plus_mo.gif\" width=\"17\" height=\"17\" border=\"0\"></td>\n";
438
		}
439

    
440
		/* Only show the button for offline dynamic leases */
441
		if (($data['type'] == "dynamic") && ($data['online'] != "online")) {
442
			echo "<td class=\"list\" valign=\"middle\"><a href=\"status_dhcpv6_leases.php?deleteip={$data['ip']}&all=" . htmlspecialchars($_GET['all']) . "\">";
443
			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";
444
		}
445
                echo "</tr>\n";
446
	}
447
}
448

    
449
?>
450
</table>
451
<p>
452
<form action="status_dhcpv6_leases.php" method="GET">
453
<input type="hidden" name="order" value="<?=htmlspecialchars($_GET['order']);?>">
454
<?php if ($_GET['all']): ?>
455
<input type="hidden" name="all" value="0">
456
<input type="submit" class="formbtn" value="<?=gettext("Show active and static leases only"); ?>">
457
<?php else: ?>
458
<input type="hidden" name="all" value="1">
459
<input type="submit" class="formbtn" value="<?=gettext("Show all configured leases"); ?>">
460
<?php endif; ?>
461
</form>
462
<?php if($leases == 0): ?>
463
<p><strong><?=gettext("No leases file found. Is the DHCP server active"); ?>?</strong></p>
464
<?php endif; ?>
465

    
466
<?php include("fend.inc"); ?>
467
</body>
468
</html>
(173-173/242)