Project

General

Profile

Download (9.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	diag_arp.php
4
	part of the pfSense project	(https://www.pfsense.org)
5
	Copyright (C) 2004-2009 Scott Ullrich <sullrich@gmail.com>
6
	Copyright (C) 2013-2015 Electric Sheep Fencing, LP
7

    
8
	originally part of m0n0wall (http://m0n0.ch/wall)
9
	Copyright (C) 2005 Paul Taylor (paultaylor@winndixie.com) and 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:	/bin/cat		/usr/sbin/arp
36
	pfSense_MODULE:	arp
37
*/
38

    
39
##|+PRIV
40
##|*IDENT=page-diagnostics-arptable
41
##|*NAME=Diagnostics: ARP Table page
42
##|*DESCR=Allow access to the 'Diagnostics: ARP Table' page.
43
##|*MATCH=diag_arp.php*
44
##|-PRIV
45

    
46
@ini_set('zlib.output_compression', 0);
47
@ini_set('implicit_flush', 1);
48

    
49
require("guiconfig.inc");
50

    
51
function leasecmp($a, $b) {
52
	return strcmp($a[$_GET['order']], $b[$_GET['order']]);
53
}
54

    
55
function adjust_gmt($dt) {
56
	$ts = strtotime($dt . " GMT");
57
	return strftime("%Y/%m/%d %H:%M:%S", $ts);
58
}
59

    
60
function remove_duplicate($array, $field) {
61
	foreach ($array as $sub) {
62
		$cmp[] = $sub[$field];
63
	}
64
	$unique = array_unique($cmp);
65
	foreach ($unique as $k => $rien) {
66
		$new[] = $array[$k];
67
	}
68
	return $new;
69
}
70

    
71
// Define path to AWK
72
$awk = "/usr/bin/awk";
73

    
74
// Read in leases file
75
$leasesfile = "{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases";
76

    
77
/* this pattern sticks comments into a single array item */
78
$cleanpattern = "'{ gsub(\"#.*\", \"\");} { gsub(\";\", \"\"); print;}'";
79

    
80
/* We then split the leases file by } */
81
$splitpattern = "'BEGIN { RS=\"}\";} {for (i=1; i<=NF; i++) printf \"%s \", \$i; printf \"}\\n\";}'";
82

    
83
/* stuff the leases file in a proper format into an array by line */
84
exec("cat {$leasesfile} | {$awk} {$cleanpattern} | {$awk} {$splitpattern}", $leases_content);
85
$leases_count = count($leases_content);
86

    
87
$pools = array();
88
$leases = array();
89
$i = 0;
90
$l = 0;
91
$p = 0;
92
// Put everything together again
93
while ($i < $leases_count) {
94
	/* split the line by space */
95
	$data = explode(" ", $leases_content[$i]);
96
	/* walk the fields */
97
	$f = 0;
98
	$fcount = count($data);
99
	/* with less then 20 fields there is nothing useful */
100
	if ($fcount < 20) {
101
		$i++;
102
		continue;
103
	}
104
	while ($f < $fcount) {
105
		switch ($data[$f]) {
106
			case "failover":
107
				$pools[$p]['name'] = $data[$f+2];
108
				$pools[$p]['mystate'] = $data[$f+7];
109
				$pools[$p]['peerstate'] = $data[$f+14];
110
				$pools[$p]['mydate'] = $data[$f+10];
111
				$pools[$p]['mydate'] .= " " . $data[$f+11];
112
				$pools[$p]['peerdate'] = $data[$f+17];
113
				$pools[$p]['peerdate'] .= " " . $data[$f+18];
114
				$p++;
115
				$i++;
116
				continue 3;
117
			case "lease":
118
				$leases[$l]['ip'] = $data[$f+1];
119
				$leases[$l]['type'] = "dynamic";
120
				$f = $f+2;
121
				break;
122
			case "starts":
123
				$leases[$l]['start'] = $data[$f+2];
124
				$leases[$l]['start'] .= " " . $data[$f+3];
125
				$f = $f+3;
126
				break;
127
			case "ends":
128
				$leases[$l]['end'] = $data[$f+2];
129
				$leases[$l]['end'] .= " " . $data[$f+3];
130
				$f = $f+3;
131
				break;
132
			case "tstp":
133
				$f = $f+3;
134
				break;
135
			case "tsfp":
136
				$f = $f+3;
137
				break;
138
			case "atsfp":
139
				$f = $f+3;
140
				break;
141
			case "cltt":
142
				$f = $f+3;
143
				break;
144
			case "binding":
145
				switch ($data[$f+2]) {
146
					case "active":
147
						$leases[$l]['act'] = "active";
148
						break;
149
					case "free":
150
						$leases[$l]['act'] = "expired";
151
						$leases[$l]['online'] = "offline";
152
						break;
153
					case "backup":
154
						$leases[$l]['act'] = "reserved";
155
						$leases[$l]['online'] = "offline";
156
						break;
157
				}
158
				$f = $f+1;
159
				break;
160
			case "next":
161
				/* skip the next binding statement */
162
				$f = $f+3;
163
				break;
164
			case "rewind":
165
				/* skip the rewind binding statement */
166
				$f = $f+3;
167
				break;
168
			case "hardware":
169
				$leases[$l]['mac'] = $data[$f+2];
170
				/* check if it's online and the lease is active */
171
				if ($leases[$l]['act'] == "active") {
172
					$online = exec("/usr/sbin/arp -an |/usr/bin/awk '/{$leases[$l]['ip']}/ {print}'|wc -l");
173
					if ($online == 1) {
174
						$leases[$l]['online'] = 'online';
175
					} else {
176
						$leases[$l]['online'] = 'offline';
177
					}
178
				}
179
				$f = $f+2;
180
				break;
181
			case "client-hostname":
182
				if ($data[$f+1] <> "") {
183
					$leases[$l]['hostname'] = preg_replace('/"/', '', $data[$f+1]);
184
				} else {
185
					$hostname = gethostbyaddr($leases[$l]['ip']);
186
					if ($hostname <> "") {
187
						$leases[$l]['hostname'] = $hostname;
188
					}
189
				}
190
				$f = $f+1;
191
				break;
192
			case "uid":
193
				$f = $f+1;
194
				break;
195
		}
196
		$f++;
197
	}
198
	$l++;
199
	$i++;
200
}
201

    
202
/* remove duplicate items by mac address */
203
if (count($leases) > 0) {
204
	$leases = remove_duplicate($leases, "ip");
205
}
206

    
207
if (count($pools) > 0) {
208
	$pools = remove_duplicate($pools, "name");
209
	asort($pools);
210
}
211

    
212
// Put this in an easy to use form
213
$dhcpmac = array();
214
$dhcpip = array();
215

    
216
foreach ($leases as $value) {
217
	$dhcpmac[$value['mac']] = $value['hostname'];
218
	$dhcpip[$value['ip']] = $value['hostname'];
219
}
220

    
221
exec("/usr/sbin/arp -an", $rawdata);
222

    
223
$i = 0;
224

    
225
/* if list */
226
$ifdescrs = get_configured_interface_with_descr();
227

    
228
foreach ($ifdescrs as $key => $interface) {
229
	$thisif = convert_friendly_interface_to_real_interface_name($key);
230
	if (!empty($thisif)) {
231
		$hwif[$thisif] = $interface;
232
	}
233
}
234

    
235
$data = array();
236
foreach ($rawdata as $line) {
237
	$elements = explode(' ', $line);
238

    
239
	if ($elements[3] != "(incomplete)") {
240
		$arpent = array();
241
		$arpent['ip'] = trim(str_replace(array('(', ')'), '', $elements[1]));
242
		$arpent['mac'] = trim($elements[3]);
243
		$arpent['interface'] = trim($elements[5]);
244
		$data[] = $arpent;
245
	}
246
}
247

    
248
function _getHostName($mac, $ip) {
249
	global $dhcpmac, $dhcpip;
250

    
251
	if ($dhcpmac[$mac]) {
252
		return $dhcpmac[$mac];
253
	} else if ($dhcpip[$ip]) {
254
		return $dhcpip[$ip];
255
	} else {
256
		exec("host -W 1 " . escapeshellarg($ip), $output);
257
		if (preg_match('/.*pointer ([A-Za-z_0-9.-]+)\..*/', $output[0], $matches)) {
258
			if ($matches[1] <> $ip) {
259
				return $matches[1];
260
			}
261
		}
262
	}
263
	return "";
264
}
265

    
266
$pgtitle = array(gettext("Diagnostics"), gettext("ARP Table"));
267
include("head.inc");
268

    
269
?>
270

    
271
<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
272

    
273
<?php include("fbegin.inc"); ?>
274

    
275
<div id="loading">
276
	<img src="/themes/<?=$g['theme'];?>/images/misc/loader.gif" alt="loader" /><?= gettext("Loading, please wait..."); ?>
277
	<p>&nbsp;</p>
278
</div>
279

    
280
<?php
281

    
282
// Flush buffers out to client so that they see Loading, please wait....
283
for ($i = 0; $i < ob_get_level(); $i++) {
284
	ob_end_flush();
285
}
286
ob_implicit_flush(1);
287

    
288
// Resolve hostnames and replace Z_ with "".  The intention
289
// is to sort the list by hostnames, alpha and then the non
290
// resolvable addresses will appear last in the list.
291
$dnsavailable=1;
292
$dns = trim(_getHostName("", "8.8.8.8"));
293
if ($dns == "") {
294
	$dns = trim(_getHostName("", "8.8.4.4"));
295
	if ($dns == "") {
296
		$dnsavailable = 0;
297
	}
298
}
299

    
300
foreach ($data as &$entry) {
301
	if ($dnsavailable) {
302
		$dns = trim(_getHostName($entry['mac'], $entry['ip']));
303
	} else {
304
		$dns="";
305
	}
306
	if (trim($dns)) {
307
		$entry['dnsresolve'] = "$dns";
308
	} else {
309
		$entry['dnsresolve'] = "Z_ ";
310
	}
311
}
312

    
313
// Sort the data alpha first
314
$data = msort($data, "dnsresolve");
315

    
316
// Load MAC-Manufacturer table
317
$mac_man = load_mac_manufacturer_table();
318
?>
319
<table width="100%" border="0" cellpadding="0" cellspacing="0" summary="diag arp">
320
	<tr>
321
		<td>
322
			<table class="tabcont sortable" width="100%" border="0" cellpadding="0" cellspacing="0" summary="tabcont">
323
				<tr>
324
					<td class="listhdrr"><?= gettext("IP address"); ?></td>
325
					<td class="listhdrr"><?= gettext("MAC address"); ?></td>
326
					<td class="listhdrr"><?= gettext("Hostname"); ?></td>
327
					<td class="listhdr"><?= gettext("Interface"); ?></td>
328
					<td class="list"></td>
329
				</tr>
330
				<?php foreach ($data as $entry): ?>
331
					<tr>
332
						<td class="listlr"><?=$entry['ip'];?></td>
333
						<td class="listr">
334
						<?php
335
						$mac=trim($entry['mac']);
336
						$mac_hi = strtoupper($mac[0] . $mac[1] . $mac[3] . $mac[4] . $mac[6] . $mac[7]);
337
						print $mac;
338
						if (isset($mac_man[$mac_hi])) { print "<br /><font size=\"-2\"><i>{$mac_man[$mac_hi]}</i></font>"; }
339
						?>
340
						</td>
341
						<td class="listr">
342
							<?php
343
							echo trim(str_replace("Z_ ", "", $entry['dnsresolve']));
344
							?>
345
						</td>
346
						<td class="listr"><?=$hwif[$entry['interface']];?></td>
347
					</tr>
348
				<?php endforeach; ?>
349
			</table>
350
		</td>
351
	</tr>
352
	<tr>
353
		<td><br /><?= gettext("NOTE: Local IPv6 peers use") ?> <a href="diag_ndp.php"><?= gettext("NDP") ?></a> <?= gettext("instead of ARP") ?>.</td>
354
	</tr>
355
</table>
356

    
357
<?php include("fend.inc"); ?>
358

    
359
<script type="text/javascript">
360
//<![CDATA[
361
	jQuery('#loading').html('');
362
//]]>
363
</script>
364
</body>
365
</html>
(5-5/252)