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
	foreach ($array as $sub) {
121
		$cmp[] = $sub[$field];
122
	}
123
	$unique = array_unique(array_reverse($cmp, true));
124
	foreach ($unique as $k => $rien) {
125
		$new[] = $array[$k];
126
	}
127
	return $new;
128
}
129

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

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

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

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

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

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

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

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

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

    
343
<br/>
344

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

    
426
		echo "<a href=\"services_wol_edit.php?if={$data['if']}&amp;mac={$data['mac']}&amp;descr={$data['hostname']}\">";
427
		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";
428

    
429
		/* Only show the button for offline dynamic leases */
430
		if (($data['type'] == "dynamic") && ($data['online'] != "online")) {
431
			echo "<a href=\"status_dhcp_leases.php?deleteip={$data['ip']}&amp;all=" . htmlspecialchars($_GET['all']) . "\">";
432
			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";
433
		}
434
	echo "</td></tr>\n";
435
	}
436
}
437

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

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