Project

General

Profile

Download (15.2 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
	if ($dhcpleaseinlocaltime == "yes") {
109
		$ts = strtotime($dt . " GMT");
110
		if ($ts !== false) {
111
			return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
112
		}
113
	}
114
	/* If we did not need to convert to local time or the conversion failed, just return the input. */
115
	return $dt;
116
}
117

    
118
function remove_duplicate($array, $field)
119
{
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
$awk = "/usr/bin/awk";
129
/* this pattern sticks comments into a single array item */
130
$cleanpattern = "'{ gsub(\"#.*\", \"\");} { gsub(\";\", \"\"); print;}'";
131
/* We then split the leases file by } */
132
$splitpattern = "'BEGIN { RS=\"}\";} {for (i=1; i<=NF; i++) printf \"%s \", \$i; printf \"}\\n\";}'";
133

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

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

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

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

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

    
306
if ($_GET['order'])
307
	usort($leases, "leasecmp");
308

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

    
333
?>
334
</table>
335

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

    
341
<br/>
342

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

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

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

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

    
452
<?php include("fend.inc"); ?>
453
</body>
454
</html>
(185-185/256)