Project

General

Profile

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

    
8
	originially part of m0n0wall (http://m0n0.ch/wall)
9
	Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>.
10
	All rights reserved.
11

    
12
	Redistribution and use in source and binary forms, with or without
13
	modification, are permitted provided that the following conditions are met:
14

    
15
	1. Redistributions of source code must retain the above copyright notice,
16
	   this list of conditions and the following disclaimer.
17

    
18
	2. Redistributions in binary form must reproduce the above copyright
19
	   notice, this list of conditions and the following disclaimer in the
20
	   documentation and/or other materials provided with the distribution.
21

    
22
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
	POSSIBILITY OF SUCH DAMAGE.
32
*/
33

    
34
/*
35
	pfSense_BUILDER_BINARIES:	/usr/bin/awk	/bin/cat	/usr/sbin/arp	/usr/bin/wc	/usr/bin/grep
36
	pfSense_MODULE:	dhcpserver
37
*/
38

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

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

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

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

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

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

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

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

    
87
include("head.inc");
88

    
89
?>
90

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

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

    
99
function adjust_gmt($dt) {
100
	global $config; 
101
	$dhcpd = $config['dhcpd'];
102
	foreach ($dhcpd as $dhcpleaseinlocaltime) {
103
		$dhcpleaseinlocaltime = $dhcpleaseinlocaltime['dhcpleaseinlocaltime'];
104
		if ($dhcpleaseinlocaltime == "yes") 
105
			break;
106
	}
107
	$timezone = $config['system']['timezone'];
108
	$ts = strtotime($dt . " GMT");
109
	if ($dhcpleaseinlocaltime == "yes") {
110
		$this_tz = new DateTimeZone($timezone); 
111
		$dhcp_lt = new DateTime(strftime("%I:%M:%S%p", $ts), $this_tz); 
112
		$offset = $this_tz->getOffset($dhcp_lt);
113
		$ts = $ts + $offset;
114
		return strftime("%Y/%m/%d %I:%M:%S%p", $ts);
115
	}
116
	else
117
		return strftime("%Y/%m/%d %H:%M:%S", $ts);
118
}
119

    
120
function remove_duplicate($array, $field)
121
{
122
  foreach ($array as $sub)
123
   $cmp[] = $sub[$field];
124
  $unique = array_unique(array_reverse($cmp,true));
125
  foreach ($unique as $k => $rien)
126
   $new[] = $array[$k];
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 = array();
141
foreach ($rawdata as $line) {
142
	$elements = explode(' ',$line);
143
	if ($elements[3] != "(incomplete)") {
144
		$arpent = array();
145
		$arpent['ip'] = trim(str_replace(array('(',')'),'',$elements[1]));
146
		// $arpent['mac'] = trim($elements[3]);
147
		// $arpent['interface'] = trim($elements[5]);
148
	$arpdata[] = $arpent['ip'];
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 then 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
				$leases[$l]['end'] = $data[$f+2];
196
				$leases[$l]['end'] .= " " . $data[$f+3];
197
				$f = $f+3;
198
				break;
199
			case "tstp":
200
				$f = $f+3;
201
				break;
202
			case "tsfp":
203
				$f = $f+3;
204
				break;
205
			case "atsfp":
206
				$f = $f+3;
207
				break;
208
			case "cltt":
209
				$f = $f+3;
210
				break;
211
			case "binding":
212
				switch($data[$f+2]) {
213
					case "active":
214
						$leases[$l]['act'] = "active";
215
						break;
216
					case "free":
217
						$leases[$l]['act'] = "expired";
218
						$leases[$l]['online'] = "offline";
219
						break;
220
					case "backup":
221
						$leases[$l]['act'] = "reserved";
222
						$leases[$l]['online'] = "offline";
223
						break;
224
				}
225
				$f = $f+1;
226
				break;
227
			case "next":
228
				/* skip the next binding statement */
229
				$f = $f+3;
230
				break;
231
			case "rewind":
232
				/* skip the rewind binding statement */
233
				$f = $f+3;
234
				break;
235
			case "hardware":
236
				$leases[$l]['mac'] = $data[$f+2];
237
				/* check if it's online and the lease is active */
238
				if (in_array($leases[$l]['ip'], $arpdata)) {
239
					$leases[$l]['online'] = 'online';
240
				} else {
241
					$leases[$l]['online'] = 'offline';
242
				}
243
				$f = $f+2;
244
				break;
245
			case "client-hostname":
246
				if($data[$f+1] <> "") {
247
					$leases[$l]['hostname'] = preg_replace('/"/','',$data[$f+1]);
248
				} else {
249
					$hostname = gethostbyaddr($leases[$l]['ip']);
250
					if($hostname <> "") {
251
						$leases[$l]['hostname'] = $hostname;
252
					}
253
				}
254
				$f = $f+1;
255
				break;
256
			case "uid":
257
				$f = $f+1;
258
				break;
259
		}
260
		$f++;
261
	}
262
	$l++;
263
	$i++;
264
	/* slowly chisel away at the source array */
265
	array_shift($leases_content);
266
}
267
/* remove the old array */
268
unset($lease_content);
269

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

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

    
280
foreach($config['interfaces'] as $ifname => $ifarr) {
281
	if (is_array($config['dhcpd'][$ifname]) && 
282
		is_array($config['dhcpd'][$ifname]['staticmap'])) {
283
		foreach($config['dhcpd'][$ifname]['staticmap'] as $static) {
284
			$slease = array();
285
			$slease['ip'] = $static['ipaddr'];
286
			$slease['type'] = "static";
287
			$slease['mac'] = $static['mac'];
288
			$slease['start'] = "";
289
			$slease['end'] = "";
290
			$slease['hostname'] = htmlentities($static['hostname']);
291
			$slease['act'] = "static";
292
			$online = exec("/usr/sbin/arp -an |/usr/bin/grep {$slease['mac']}| /usr/bin/wc -l|/usr/bin/awk '{print $1;}'");
293
			if ($online == 1) {
294
				$slease['online'] = 'online';
295
			} else {
296
				$slease['online'] = 'offline';
297
			}
298
			$leases[] = $slease;
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
<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0">
310
  <tr>
311
    <td class="listhdrr"><?=gettext("Failover Group"); ?></a></td>
312
    <td class="listhdrr"><?=gettext("My State"); ?></a></td>
313
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
314
    <td class="listhdrr"><?=gettext("Peer State"); ?></a></td>
315
    <td class="listhdrr"><?=gettext("Since"); ?></a></td>
316
  </tr>
317
<?php
318
foreach ($pools as $data) {
319
	echo "<tr>\n";
320
	echo "<td class=\"listlr\">{$fspans}{$data['name']}{$fspane}&nbsp;</td>\n";
321
	echo "<td class=\"listr\">{$fspans}{$data['mystate']}{$fspane}&nbsp;</td>\n";
322
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['mydate']) . "{$fspane}&nbsp;</td>\n";
323
	echo "<td class=\"listr\">{$fspans}{$data['peerstate']}{$fspane}&nbsp;</td>\n";
324
	echo "<td class=\"listr\">{$fspans}" . adjust_gmt($data['peerdate']) . "{$fspane}&nbsp;</td>\n";
325
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
326
	echo "<td class=\"list\" valign=\"middle\" width=\"17\">&nbsp;</td>\n";
327
	echo "</tr>\n";
328
}
329

    
330
?>
331
</table>
332

    
333
<?php
334
/* only print pool status when we have one */
335
}
336
?>
337

    
338
<p>
339

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

    
422
                echo "<td valign=\"middle\"><a href=\"services_wol_edit.php?if={$data['if']}&mac={$data['mac']}&descr={$data['hostname']}\">";
423
		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") ."\"></a></td>\n";
424

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

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

    
451
<?php include("fend.inc"); ?>
452
</body>
453
</html>
(176-176/246)