Project

General

Profile

Download (15.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
	status_dhcp_leases.php
5
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
6
	Copyright (C) 2004-2009 Scott Ullrich
7
	All rights reserved.
8

    
9
	originally 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/arp	/usr/bin/wc	/usr/bin/grep
37
	pfSense_MODULE:	dhcpserver
38
*/
39

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

    
47
require("guiconfig.inc");
48
require_once("config.inc");
49

    
50
$pgtitle = array(gettext("Status"),gettext("DHCP leases"));
51
$shortcut_section = "dhcp";
52

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

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

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

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

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

    
88
include("head.inc");
89

    
90
?>
91

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

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

    
100
function adjust_gmt($dt) {
101
	global $config;
102
	$dhcpd = $config['dhcpd'];
103
	foreach ($dhcpd as $dhcpditem) {
104
		$dhcpleaseinlocaltime = $dhcpditem['dhcpleaseinlocaltime'];
105
		if ($dhcpleaseinlocaltime == "yes") {
106
			break;
107
		}
108
	}
109
	if ($dhcpleaseinlocaltime == "yes") {
110
		$ts = strtotime($dt . " GMT");
111
		if ($ts !== false) {
112
			return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
113
		}
114
	}
115
	/* If we did not need to convert to local time or the conversion failed, just return the input. */
116
	return $dt;
117
}
118

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

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

    
137
/* stuff the leases file in a proper format into a array by line */
138
exec("/bin/cat {$leasesfile} | {$awk} {$cleanpattern} | {$awk} {$splitpattern}", $leases_content);
139
$leases_count = count($leases_content);
140
exec("/usr/sbin/arp -an", $rawdata);
141
$arpdata_ip = array();
142
$arpdata_mac = array();
143
foreach ($rawdata as $line) {
144
	$elements = explode(' ',$line);
145
	if ($elements[3] != "(incomplete)") {
146
		$arpent = array();
147
		$arpdata_ip[] = trim(str_replace(array('(',')'),'',$elements[1]));
148
		$arpdata_mac[] = strtolower(trim($elements[3]));
149
	}
150
}
151
unset($rawdata);
152
$pools = array();
153
$leases = array();
154
$i = 0;
155
$l = 0;
156
$p = 0;
157

    
158
// Put everything together again
159
foreach ($leases_content as $lease) {
160
	/* split the line by space */
161
	$data = explode(" ", $lease);
162
	/* walk the fields */
163
	$f = 0;
164
	$fcount = count($data);
165
	/* with less than 20 fields there is nothing useful */
166
	if ($fcount < 20) {
167
		$i++;
168
		continue;
169
	}
170
	while($f < $fcount) {
171
		switch ($data[$f]) {
172
			case "failover":
173
				$pools[$p]['name'] = trim($data[$f+2], '"');
174
				$pools[$p]['name'] = "{$pools[$p]['name']} (" . convert_friendly_interface_to_friendly_descr(substr($pools[$p]['name'], 5)) . ")";
175
				$pools[$p]['mystate'] = $data[$f+7];
176
				$pools[$p]['peerstate'] = $data[$f+14];
177
				$pools[$p]['mydate'] = $data[$f+10];
178
				$pools[$p]['mydate'] .= " " . $data[$f+11];
179
				$pools[$p]['peerdate'] = $data[$f+17];
180
				$pools[$p]['peerdate'] .= " " . $data[$f+18];
181
				$p++;
182
				$i++;
183
				continue 3;
184
			case "lease":
185
				$leases[$l]['ip'] = $data[$f+1];
186
				$leases[$l]['type'] = "dynamic";
187
				$f = $f+2;
188
				break;
189
			case "starts":
190
				$leases[$l]['start'] = $data[$f+2];
191
				$leases[$l]['start'] .= " " . $data[$f+3];
192
				$f = $f+3;
193
				break;
194
			case "ends":
195
				if ($data[$f+1] == "never") {
196
					// Quote from dhcpd.leases(5) man page:
197
					// If a lease will never expire, date is never instead of an actual date.
198
					$leases[$l]['end'] = gettext("Never");
199
					$f = $f+1;
200
				} else {
201
					$leases[$l]['end'] = $data[$f+2];
202
					$leases[$l]['end'] .= " " . $data[$f+3];
203
					$f = $f+3;
204
				}
205
				break;
206
			case "tstp":
207
				$f = $f+3;
208
				break;
209
			case "tsfp":
210
				$f = $f+3;
211
				break;
212
			case "atsfp":
213
				$f = $f+3;
214
				break;
215
			case "cltt":
216
				$f = $f+3;
217
				break;
218
			case "binding":
219
				switch ($data[$f+2]) {
220
					case "active":
221
						$leases[$l]['act'] = "active";
222
						break;
223
					case "free":
224
						$leases[$l]['act'] = "expired";
225
						$leases[$l]['online'] = "offline";
226
						break;
227
					case "backup":
228
						$leases[$l]['act'] = "reserved";
229
						$leases[$l]['online'] = "offline";
230
						break;
231
				}
232
				$f = $f+1;
233
				break;
234
			case "next":
235
				/* skip the next binding statement */
236
				$f = $f+3;
237
				break;
238
			case "rewind":
239
				/* skip the rewind binding statement */
240
				$f = $f+3;
241
				break;
242
			case "hardware":
243
				$leases[$l]['mac'] = $data[$f+2];
244
				/* check if it's online and the lease is active */
245
				if (in_array($leases[$l]['ip'], $arpdata_ip)) {
246
					$leases[$l]['online'] = 'online';
247
				} else {
248
					$leases[$l]['online'] = 'offline';
249
				}
250
				$f = $f+2;
251
				break;
252
			case "client-hostname":
253
				if ($data[$f+1] <> "") {
254
					$leases[$l]['hostname'] = preg_replace('/"/','',$data[$f+1]);
255
				} else {
256
					$hostname = gethostbyaddr($leases[$l]['ip']);
257
					if ($hostname <> "") {
258
						$leases[$l]['hostname'] = $hostname;
259
					}
260
				}
261
				$f = $f+1;
262
				break;
263
			case "uid":
264
				$f = $f+1;
265
				break;
266
		}
267
		$f++;
268
	}
269
	$l++;
270
	$i++;
271
	/* slowly chisel away at the source array */
272
	array_shift($leases_content);
273
}
274
/* remove the old array */
275
unset($lease_content);
276

    
277
/* remove duplicate items by mac address */
278
if (count($leases) > 0) {
279
	$leases = remove_duplicate($leases,"ip");
280
}
281

    
282
if (count($pools) > 0) {
283
	$pools = remove_duplicate($pools,"name");
284
	asort($pools);
285
}
286

    
287
foreach ($config['interfaces'] as $ifname => $ifarr) {
288
	if (is_array($config['dhcpd'][$ifname]) &&
289
	    is_array($config['dhcpd'][$ifname]['staticmap'])) {
290
		$staticmap_array_index = 0;
291
		foreach ($config['dhcpd'][$ifname]['staticmap'] as $static) {
292
			$slease = array();
293
			$slease['ip'] = $static['ipaddr'];
294
			$slease['type'] = "static";
295
			$slease['mac'] = $static['mac'];
296
			$slease['if'] = $ifname;
297
			$slease['start'] = "";
298
			$slease['end'] = "";
299
			$slease['hostname'] = htmlentities($static['hostname']);
300
			$slease['act'] = "static";
301
			$slease['online'] = in_array(strtolower($slease['mac']), $arpdata_mac) ? 'online' : 'offline';
302
			$slease['staticmap_array_index'] = $staticmap_array_index;
303
			$leases[] = $slease;
304
			$staticmap_array_index++;
305
		}
306
	}
307
}
308

    
309
if ($_GET['order']) {
310
	usort($leases, "leasecmp");
311
}
312

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

    
339
<?php
340
/* only print pool status when we have one */
341
}
342
?>
343

    
344
<br/>
345

    
346
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0" summary="dhcp leases">
347
	<tr>
348
		<td class="listhdrr"><a href="#"><?=gettext("IP address"); ?></a></td>
349
		<td class="listhdrr"><a href="#"><?=gettext("MAC address"); ?></a></td>
350
		<td class="listhdrr"><a href="#"><?=gettext("Hostname"); ?></a></td>
351
		<td class="listhdrr"><a href="#"><?=gettext("Start"); ?></a></td>
352
		<td class="listhdrr"><a href="#"><?=gettext("End"); ?></a></td>
353
		<td class="listhdrr"><a href="#"><?=gettext("Online"); ?></a></td>
354
		<td class="listhdrr"><a href="#"><?=gettext("Lease Type"); ?></a></td>
355
	</tr>
356
<?php
357
// Load MAC-Manufacturer table
358
$mac_man = load_mac_manufacturer_table();
359
foreach ($leases as $data) {
360
	if (($data['act'] == "active") || ($data['act'] == "static") || ($_GET['all'] == 1)) {
361
		if ($data['act'] != "active" && $data['act'] != "static") {
362
			$fspans = "<span class=\"gray\">";
363
			$fspane = "&nbsp;</span>";
364
		} else {
365
			$fspans = "";
366
			$fspane = "&nbsp;";
367
		}
368
		$lip = ip2ulong($data['ip']);
369
		if ($data['act'] != "static") {
370
			foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
371
				if (!is_array($dhcpifconf['range'])) {
372
					continue;
373
				}
374
				if (($lip >= ip2ulong($dhcpifconf['range']['from'])) && ($lip <= ip2ulong($dhcpifconf['range']['to']))) {
375
					$data['if'] = $dhcpif;
376
					break;
377
				}
378
				// Check if the IP is in the range of any DHCP pools
379
				if (is_array($dhcpifconf['pool'])) {
380
					foreach ($dhcpifconf['pool'] as $dhcppool) {
381
						if (is_array($dhcppool['range'])) {
382
							if (($lip >= ip2ulong($dhcppool['range']['from'])) && ($lip <= ip2ulong($dhcppool['range']['to']))) {
383
								$data['if'] = $dhcpif;
384
								break 2;
385
							}
386
						}
387
					}
388
				}
389
			}
390
		}
391
		echo "<tr>\n";
392
		echo "<td class=\"listlr\">{$fspans}{$data['ip']}{$fspane}</td>\n";
393
		$mac=$data['mac'];
394
		$mac_hi = strtoupper($mac[0] . $mac[1] . $mac[3] . $mac[4] . $mac[6] . $mac[7]);
395
		if ($data['online'] != "online") {
396
			if (isset($mac_man[$mac_hi])) { // Manufacturer for this MAC is defined
397
				echo "<td class=\"listr\">{$fspans}<a href=\"services_wol.php?if={$data['if']}&amp;mac=$mac\" title=\"" . gettext("$mac - send Wake on LAN packet to this MAC address") ."\">{$mac}</a><br /><font size=\"-2\"><i>{$mac_man[$mac_hi]}</i></font>{$fspane}</td>\n";
398
			} else {
399
				echo "<td class=\"listr\">{$fspans}<a href=\"services_wol.php?if={$data['if']}&amp;mac={$data['mac']}\" title=\"" . gettext("send Wake on LAN packet to this MAC address") ."\">{$data['mac']}</a>{$fspane}</td>\n";
400
			}
401
		} else {
402
			if (isset($mac_man[$mac_hi])) { // Manufacturer for this MAC is defined
403
				echo "<td class=\"listr\">{$fspans}{$mac}<br /><font size=\"-2\"><i>{$mac_man[$mac_hi]}</i></font>{$fspane}</td>\n";
404
			} else {
405
				echo "<td class=\"listr\">{$fspans}{$data['mac']}{$fspane}</td>\n";
406
			}
407
		}
408
		echo "<td class=\"listr\">{$fspans}"  . htmlentities($data['hostname']) . "{$fspane}</td>\n";
409
		if ($data['type'] != "static") {
410
			echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['start']) . "{$fspane}</td>\n";
411
			echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['end']) . "{$fspane}</td>\n";
412
		} else {
413
			echo "<td class=\"listr\">{$fspans} n/a {$fspane}</td>\n";
414
			echo "<td class=\"listr\">{$fspans} n/a {$fspane}</td>\n";
415
		}
416
		echo "<td class=\"listr\">{$fspans}{$data['online']}{$fspane}</td>\n";
417
		echo "<td class=\"listr\">{$fspans}{$data['act']}{$fspane}</td>\n";
418
		echo "<td valign=\"middle\">&nbsp;";
419
		if ($data['type'] == "dynamic") {
420
			echo "<a href=\"services_dhcp_edit.php?if={$data['if']}&amp;mac={$data['mac']}&amp;hostname={$data['hostname']}\">";
421
			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") ."\" alt=\"add\" /></a>&nbsp;\n";
422
		} else {
423
			echo "<a href=\"services_dhcp_edit.php?if={$data['if']}&amp;id={$data['staticmap_array_index']}\">";
424
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_e.gif\" width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("edit the static mapping for this entry") ."\" alt=\"add\" />&nbsp;\n";
425
		}
426

    
427
		echo "<a href=\"services_wol_edit.php?if={$data['if']}&amp;mac={$data['mac']}&amp;descr={$data['hostname']}\">";
428
		echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_wol_all.gif\" width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("add a Wake on LAN mapping for this MAC address") ."\" alt=\"add\" /></a>&nbsp;\n";
429

    
430
		/* Only show the button for offline dynamic leases */
431
		if (($data['type'] == "dynamic") && ($data['online'] != "online")) {
432
			echo "<a href=\"status_dhcp_leases.php?deleteip={$data['ip']}&amp;all=" . htmlspecialchars($_GET['all']) . "\">";
433
			echo "<img src=\"/themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"17\" height=\"17\" border=\"0\" title=\"" . gettext("delete this DHCP lease") . "\" alt=\"delete\" /></a>&nbsp;\n";
434
		}
435
	echo "</td></tr>\n";
436
	}
437
}
438

    
439
?>
440
</table>
441
<br/>
442
<form action="status_dhcp_leases.php" method="get">
443
	<input type="hidden" name="order" value="<?=htmlspecialchars($_GET['order']);?>" />
444
<?php if ($_GET['all']): ?>
445
	<input type="hidden" name="all" value="0" />
446
	<input type="submit" class="formbtn" value="<?=gettext("Show active and static leases only"); ?>" />
447
<?php else: ?>
448
	<input type="hidden" name="all" value="1" />
449
	<input type="submit" class="formbtn" value="<?=gettext("Show all configured leases"); ?>" />
450
<?php endif; ?>
451
</form>
452
<?php if ($leases == 0): ?>
453
<p><strong><?=gettext("No leases file found. Is the DHCP server active"); ?>?</strong></p>
454
<?php endif; ?>
455

    
456
<?php include("fend.inc"); ?>
457
</body>
458
</html>
(181-181/252)