Project

General

Profile

Download (12.5 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
// Load MAC-Manufacturer table
89
$mac_man = load_mac_manufacturer_table();
90

    
91
include("head.inc");
92

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

    
97
function adjust_gmt($dt) {
98
	global $config;
99
	$dhcpd = $config['dhcpd'];
100
	foreach ($dhcpd as $dhcpditem) {
101
		$dhcpleaseinlocaltime = $dhcpditem['dhcpleaseinlocaltime'];
102
		if ($dhcpleaseinlocaltime == "yes")
103
			break;
104
	}
105
	if ($dhcpleaseinlocaltime == "yes") {
106
		$ts = strtotime($dt . " GMT");
107
		if ($ts !== false) {
108
			return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
109
		}
110
	}
111
	/* If we did not need to convert to local time or the conversion failed, just return the input. */
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
				if ($data[$f+1] == "never") {
190
					// Quote from dhcpd.leases(5) man page:
191
					// If a lease will never expire, date is never instead of an actual date.
192
					$leases[$l]['end'] = gettext("Never");
193
					$f = $f+1;
194
				} else {
195
					$leases[$l]['end'] = $data[$f+2];
196
					$leases[$l]['end'] .= " " . $data[$f+3];
197
					$f = $f+3;
198
				}
199
				break;
200
			case "tstp":
201
				$f = $f+3;
202
				break;
203
			case "tsfp":
204
				$f = $f+3;
205
				break;
206
			case "atsfp":
207
				$f = $f+3;
208
				break;
209
			case "cltt":
210
				$f = $f+3;
211
				break;
212
			case "binding":
213
				switch($data[$f+2]) {
214
					case "active":
215
						$leases[$l]['act'] = "active";
216
						break;
217
					case "free":
218
						$leases[$l]['act'] = "expired";
219
						$leases[$l]['online'] = "offline";
220
						break;
221
					case "backup":
222
						$leases[$l]['act'] = "reserved";
223
						$leases[$l]['online'] = "offline";
224
						break;
225
				}
226
				$f = $f+1;
227
				break;
228
			case "next":
229
				/* skip the next binding statement */
230
				$f = $f+3;
231
				break;
232
			case "rewind":
233
				/* skip the rewind binding statement */
234
				$f = $f+3;
235
				break;
236
			case "hardware":
237
				$leases[$l]['mac'] = $data[$f+2];
238
				/* check if it's online and the lease is active */
239
				if (in_array($leases[$l]['ip'], $arpdata_ip)) {
240
					$leases[$l]['online'] = 'online';
241
				} else {
242
					$leases[$l]['online'] = 'offline';
243
				}
244
				$f = $f+2;
245
				break;
246
			case "client-hostname":
247
				if($data[$f+1] != "") {
248
					$leases[$l]['hostname'] = preg_replace('/"/','',$data[$f+1]);
249
				} else {
250
					$hostname = gethostbyaddr($leases[$l]['ip']);
251
					if($hostname != "") {
252
						$leases[$l]['hostname'] = $hostname;
253
					}
254
				}
255
				$f = $f+1;
256
				break;
257
			case "uid":
258
				$f = $f+1;
259
				break;
260
		}
261
		$f++;
262
	}
263
	$l++;
264
	$i++;
265
	/* slowly chisel away at the source array */
266
	array_shift($leases_content);
267
}
268
/* remove the old array */
269
unset($lease_content);
270

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

    
276
if(count($pools) > 0) {
277
	$pools = remove_duplicate($pools,"name");
278
	asort($pools);
279
}
280

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

    
303
if ($_GET['order'])
304
	usort($leases, "leasecmp");
305

    
306
/* only print pool status when we have one */
307
if(count($pools) > 0) {
308
?>
309
<div class="panel panel-default">
310
	<div class="panel-heading"><?=gettext('Pool status')?></div>
311
	<div class="panel-body">
312
		<table class="table">
313
		<thead>
314
			<tr>
315
				<th><?=gettext("Failover Group")?></a></th>
316
				<th><?=gettext("My State")?></a></th>
317
				<th><?=gettext("Since")?></a></th>
318
				<th><?=gettext("Peer State")?></a></th>
319
				<th><?=gettext("Since")?></a></th>
320
			</tr>
321
		</thead>
322
		<tbody>
323
<? foreach ($pools as $data):?>
324
			<tr>
325
				<td><?=$data['name']?></td>
326
				<td><?=$data['mystate']?></td>
327
				<td><?=adjust_gmt($data['mydate'])?></td>
328
				<td><?=$data['peerstate']?></td>
329
				<td><?=adjust_gmt($data['peerdate'])?></td>
330
			</tr>
331
<? endforeach?>
332
		</tbody>
333
		</table>
334
	</div>
335
</div>
336
<?php
337
/* only print pool status when we have one */
338
}
339
?>
340
<div class="panel panel-default">
341
	<div class="panel-heading"><?=gettext('Leases')?></div>
342
	<div class="panel-body">
343
		<table class="table">
344
		<thead>
345
			<tr>
346
				<th><!-- icon --></th>
347
				<th><?=gettext("IP address")?></th>
348
				<th><?=gettext("MAC address")?></th>
349
				<th><?=gettext("Hostname")?></th>
350
				<th><?=gettext("Start")?></th>
351
				<th><?=gettext("End")?></th>
352
				<th><?=gettext("Online")?></th>
353
				<th><?=gettext("Lease Type")?></th>
354
			</tr>
355
		</thead>
356
		<tbody>
357
<?php
358
foreach ($leases as $data):
359
	if ($data['act'] != "active" && $data['act'] != "static" && $_GET['all'] != 1)
360
		continue;
361

    
362
	if ($data['act'] == 'active')
363
		$icon = 'icon-ok-circle';
364
	elseif ($data['act'] == 'expired')
365
		$icon = 'icon-ban-circle';
366
	else
367
		$icon = 'icon-remove-circle';
368

    
369
	$lip = ip2ulong($data['ip']);
370
	if ($data['act'] != "static") {
371
		foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
372
			if (!is_array($dhcpifconf['range']))
373
				continue;
374
			if (($lip >= ip2ulong($dhcpifconf['range']['from'])) && ($lip <= ip2ulong($dhcpifconf['range']['to']))) {
375
				$data['if'] = $dhcpif;
376
				break;
377
			}
378
		}
379
	}
380

    
381
	$mac = $data['mac'];
382
	$mac_hi = strtoupper($mac[0] . $mac[1] . $mac[3] . $mac[4] . $mac[6] . $mac[7]);
383
?>
384
			<tr>
385
				<td><i class="icon <?=$icon?>"></i></td>
386
				<td><?=$data['ip']?></td>
387
				<td>
388
					<?=$mac?>
389

    
390
					<? if(isset($mac_man[$mac_hi])):?>
391
						(<?=$mac_man[$mac_hi]?>)
392
					<?endif?>
393
				</td>
394
				<td><?=htmlentities($data['hostname'])?></td>
395
<? if ($data['type'] != "static"):?>
396
				<td><?=adjust_gmt($data['start'])?></td>
397
				<td><?=adjust_gmt($data['end'])?></td>
398
<? else: ?>
399
				<td>n/a</td>
400
				<td>n/a</td>
401
<? endif; ?>
402
				<td><?=$data['online']?></td>
403
				<td><?=$data['act']?></td>
404
				<td>
405
<? if ($data['type'] == "dynamic"): ?>
406
					<a class="btn btn-xs btn-primary" href="services_dhcp_edit.php?if=<?=$data['if']?>&amp;mac=<?=$data['mac']?>&amp;hostname=<?=htmlspecialchars($data['hostname'])?>">
407
						<?=gettext("add static mapping")?>
408
					</a>
409
<? else: ?>
410
					<a class="btn btn-xs btn-primary" href="services_dhcp_edit.php?if=<?=$data['if']?>&amp;id=<?=$data['staticmap_array_index']?>">
411
						<?=gettext("edit static mapping")?>
412
					</a>
413
<? endif; ?>
414

    
415
					<a class="btn btn-xs btn-success" href="services_wol_edit.php?if=<?=$data['if']?>&amp;mac=<?=$data['mac']?>&amp;descr=<?=htmlentities($data['hostname'])?>">
416
						add WOL mapping
417
					</a>
418

    
419
<? if ($data['online'] != "online"):?>
420
					<a class="btn btn-xs btn-warning" href="services_wol.php?if=<?=$data['if']?>&amp;mac=<?=$data['mac']?>">
421
						send WOL packet
422
					</a>
423
<? endif; ?>
424

    
425
<? if ($data['type'] == "dynamic" && $data['online'] != "online"):?>
426
					<a class="btn btn-xs btn-danger" href="status_dhcp_leases.php?deleteip=<?=$data['ip']?>&amp;all=<?=intval($_GET['all'])?>">
427
						delete lease
428
					</a>
429
<? endif?>
430
				</td>
431
<? endforeach; ?>
432
			</tr>
433
		</tbody>
434
		</table>
435
	</div>
436
</div>
437

    
438
<?php if ($_GET['all']): ?>
439
	<a class="btn btn-default" href="status_dhcp_leases.php?all=0"><?=gettext("Show active and static leases only")?></a>
440
<?php else: ?>
441
	<a class="btn btn-default" href="status_dhcp_leases.php?all=1"><?=gettext("Show all configured leases")?></a>
442
<?php endif;
443

    
444
include("foot.inc");
(182-182/252)