Project

General

Profile

Download (14.8 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
		return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
111
	} else
112
		return $dt;
113
}
114

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

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

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

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

    
264
/* remove duplicate items by mac address */
265
if(count($leases) > 0) {
266
	$leases = remove_duplicate($leases,"ip");
267
}
268

    
269
if(count($pools) > 0) {
270
	$pools = remove_duplicate($pools,"name");
271
	asort($pools);
272
}
273

    
274
foreach($config['interfaces'] as $ifname => $ifarr) {
275
	if (is_array($config['dhcpd'][$ifname]) &&
276
		is_array($config['dhcpd'][$ifname]['staticmap'])) {
277
		foreach($config['dhcpd'][$ifname]['staticmap'] as $static) {
278
			$slease = array();
279
			$slease['ip'] = $static['ipaddr'];
280
			$slease['type'] = "static";
281
			$slease['mac'] = $static['mac'];
282
			$slease['start'] = "";
283
			$slease['end'] = "";
284
			$slease['hostname'] = htmlentities($static['hostname']);
285
			$slease['act'] = "static";
286
			$slease['online'] = in_array(strtolower($slease['mac']), $arpdata_mac) ? 'online' : 'offline';
287
			$leases[] = $slease;
288
		}
289
	}
290
}
291

    
292
if ($_GET['order'])
293
	usort($leases, "leasecmp");
294

    
295
/* only print pool status when we have one */
296
if(count($pools) > 0) {
297
?>
298
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0" summary="dhcp leases">
299
  <tr>
300
    <td class="listhdrr"><?=gettext("Failover Group"); ?></a></td>
301
    <td class="listhdrr"><?=gettext("My State"); ?></a></td>
302
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
303
    <td class="listhdrr"><?=gettext("Peer State"); ?></a></td>
304
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
305
  </tr>
306
<?php
307
foreach ($pools as $data) {
308
	echo "<tr>\n";
309
	echo "<td class=\"listlr\">{$fspans}{$data['name']}{$fspane}</td>\n";
310
	echo "<td class=\"listr\">{$fspans}{$data['mystate']}{$fspane}</td>\n";
311
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['mydate']) . "{$fspane}</td>\n";
312
	echo "<td class=\"listr\">{$fspans}{$data['peerstate']}{$fspane}</td>\n";
313
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['peerdate']) . "{$fspane}</td>\n";
314
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
315
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
316
	echo "</tr>\n";
317
}
318

    
319
?>
320
</table>
321

    
322
<?php
323
/* only print pool status when we have one */
324
}
325
?>
326

    
327
<br/>
328

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

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

    
417
		/* Only show the button for offline dynamic leases */
418
		if (($data['type'] == "dynamic") && ($data['online'] != "online")) {
419
			echo "<a href=\"status_dhcp_leases.php?deleteip={$data['ip']}&amp;all=" . htmlspecialchars($_GET['all']) . "\">";
420
			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";
421
		}
422
	echo "</td></tr>\n";
423
	}
424
}
425

    
426
?>
427
</table>
428
<br/>
429
<form action="status_dhcp_leases.php" method="get">
430
<input type="hidden" name="order" value="<?=htmlspecialchars($_GET['order']);?>" />
431
<?php if ($_GET['all']): ?>
432
<input type="hidden" name="all" value="0" />
433
<input type="submit" class="formbtn" value="<?=gettext("Show active and static leases only"); ?>" />
434
<?php else: ?>
435
<input type="hidden" name="all" value="1" />
436
<input type="submit" class="formbtn" value="<?=gettext("Show all configured leases"); ?>" />
437
<?php endif; ?>
438
</form>
439
<?php if($leases == 0): ?>
440
<p><strong><?=gettext("No leases file found. Is the DHCP server active"); ?>?</strong></p>
441
<?php endif; ?>
442

    
443
<?php include("fend.inc"); ?>
444
</body>
445
</html>
(185-185/256)