Project

General

Profile

Download (11 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * diag_arp.php
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * originally based on 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
21
 *    the documentation and/or other materials provided with the
22
 *    distribution.
23
 *
24
 * 3. All advertising materials mentioning features or use of this software
25
 *    must display the following acknowledgment:
26
 *    "This product includes software developed by the pfSense Project
27
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
28
 *
29
 * 4. The names "pfSense" and "pfSense Project" must not be used to
30
 *    endorse or promote products derived from this software without
31
 *    prior written permission. For written permission, please contact
32
 *    coreteam@pfsense.org.
33
 *
34
 * 5. Products derived from this software may not be called "pfSense"
35
 *    nor may "pfSense" appear in their names without prior written
36
 *    permission of the Electric Sheep Fencing, LLC.
37
 *
38
 * 6. Redistributions of any form whatsoever must retain the following
39
 *    acknowledgment:
40
 *
41
 * "This product includes software developed by the pfSense Project
42
 * for use in the pfSense software distribution (http://www.pfsense.org/).
43
 *
44
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
45
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
48
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
49
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
51
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
53
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
54
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55
 * OF THE POSSIBILITY OF SUCH DAMAGE.
56
 */
57

    
58
##|+PRIV
59
##|*IDENT=page-diagnostics-arptable
60
##|*NAME=Diagnostics: ARP Table
61
##|*DESCR=Allow access to the 'Diagnostics: ARP Table' page.
62
##|*MATCH=diag_arp.php*
63
##|-PRIV
64

    
65
@ini_set('zlib.output_compression', 0);
66
@ini_set('implicit_flush', 1);
67

    
68
require_once("guiconfig.inc");
69

    
70
// delete arp entry
71
if (isset($_GET['deleteentry'])) {
72
	$ip = $_GET['deleteentry'];
73
	if (is_ipaddrv4($ip)) {
74
		$ret = mwexec("arp -d " . $_GET['deleteentry'], true);
75
	} else {
76
		$ret = 1;
77
	}
78
	if ($ret) {
79
		$savemsg = sprintf(gettext("%s is not a valid IPv4 address or could not be deleted."), $ip);
80
		$savemsgtype = 'alert-warning';
81
	} else {
82
		$savemsg = sprintf(gettext("The ARP cache entry for %s has been deleted."), $ip);
83
		$savemsgtype = 'success';
84
	}
85
}
86

    
87
function leasecmp($a, $b) {
88
	return strcmp($a[$_GET['order']], $b[$_GET['order']]);
89
}
90

    
91
function adjust_gmt($dt) {
92
	$ts = strtotime($dt . " GMT");
93
	return strftime("%Y/%m/%d %H:%M:%S", $ts);
94
}
95

    
96
function remove_duplicate($array, $field) {
97
	foreach ($array as $sub) {
98
		$cmp[] = $sub[$field];
99
	}
100
	$unique = array_unique($cmp);
101
	foreach ($unique as $k => $rien) {
102
		$new[] = $array[$k];
103
	}
104
	return $new;
105
}
106

    
107
// Define path to AWK
108
$awk = "/usr/bin/awk";
109

    
110
// Read in leases file
111
$leasesfile = "{$g['dhcpd_chroot_path']}/var/db/dhcpd.leases";
112

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

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

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

    
123
$pools = array();
124
$leases = array();
125
$i = 0;
126
$l = 0;
127
$p = 0;
128
// Put everything together again
129
while ($i < $leases_count) {
130
	/* split the line by space */
131
	$data = explode(" ", $leases_content[$i]);
132
	/* walk the fields */
133
	$f = 0;
134
	$fcount = count($data);
135
	/* with less then 20 fields there is nothing useful */
136
	if ($fcount < 20) {
137
		$i++;
138
		continue;
139
	}
140
	while ($f < $fcount) {
141
		switch ($data[$f]) {
142
			case "failover":
143
				$pools[$p]['name'] = $data[$f+2];
144
				$pools[$p]['mystate'] = $data[$f+7];
145
				$pools[$p]['peerstate'] = $data[$f+14];
146
				$pools[$p]['mydate'] = $data[$f+10];
147
				$pools[$p]['mydate'] .= " " . $data[$f+11];
148
				$pools[$p]['peerdate'] = $data[$f+17];
149
				$pools[$p]['peerdate'] .= " " . $data[$f+18];
150
				$p++;
151
				$i++;
152
				continue 3;
153
			case "lease":
154
				$leases[$l]['ip'] = $data[$f+1];
155
				$leases[$l]['type'] = "dynamic";
156
				$f = $f+2;
157
				break;
158
			case "starts":
159
				$leases[$l]['start'] = $data[$f+2];
160
				$leases[$l]['start'] .= " " . $data[$f+3];
161
				$f = $f+3;
162
				break;
163
			case "ends":
164
				$leases[$l]['end'] = $data[$f+2];
165
				$leases[$l]['end'] .= " " . $data[$f+3];
166
				$f = $f+3;
167
				break;
168
			case "tstp":
169
				$f = $f+3;
170
				break;
171
			case "tsfp":
172
				$f = $f+3;
173
				break;
174
			case "atsfp":
175
				$f = $f+3;
176
				break;
177
			case "cltt":
178
				$f = $f+3;
179
				break;
180
			case "binding":
181
				switch ($data[$f+2]) {
182
					case "active":
183
						$leases[$l]['act'] = "active";
184
						break;
185
					case "free":
186
						$leases[$l]['act'] = "expired";
187
						$leases[$l]['online'] = "offline";
188
						break;
189
					case "backup":
190
						$leases[$l]['act'] = "reserved";
191
						$leases[$l]['online'] = "offline";
192
						break;
193
				}
194
				$f = $f+1;
195
				break;
196
			case "next":
197
				/* skip the next binding statement */
198
				$f = $f+3;
199
				break;
200
			case "rewind":
201
				/* skip the rewind binding statement */
202
				$f = $f+3;
203
				break;
204
			case "hardware":
205
				$leases[$l]['mac'] = $data[$f+2];
206
				/* check if it's online and the lease is active */
207
				if ($leases[$l]['act'] == "active") {
208
					$online = exec("/usr/sbin/arp -an |/usr/bin/awk '/{$leases[$l]['ip']}/ {print}'|wc -l");
209
					if ($online == 1) {
210
						$leases[$l]['online'] = 'online';
211
					} else {
212
						$leases[$l]['online'] = 'offline';
213
					}
214
				}
215
				$f = $f+2;
216
				break;
217
			case "client-hostname":
218
				if ($data[$f+1] <> "") {
219
					$leases[$l]['hostname'] = preg_replace('/"/', '', $data[$f+1]);
220
				} else {
221
					$hostname = gethostbyaddr($leases[$l]['ip']);
222
					if ($hostname <> "") {
223
						$leases[$l]['hostname'] = $hostname;
224
					}
225
				}
226
				$f = $f+1;
227
				break;
228
			case "uid":
229
				$f = $f+1;
230
				break;
231
		}
232
		$f++;
233
	}
234
	$l++;
235
	$i++;
236
}
237

    
238
/* remove duplicate items by mac address */
239
if (count($leases) > 0) {
240
	$leases = remove_duplicate($leases, "ip");
241
}
242

    
243
if (count($pools) > 0) {
244
	$pools = remove_duplicate($pools, "name");
245
	asort($pools);
246
}
247

    
248
// Put this in an easy to use form
249
$dhcpmac = array();
250
$dhcpip = array();
251

    
252
foreach ($leases as $value) {
253
	$dhcpmac[$value['mac']] = $value['hostname'];
254
	$dhcpip[$value['ip']] = $value['hostname'];
255
}
256

    
257
exec("/usr/sbin/arp -an", $rawdata);
258

    
259
$i = 0;
260

    
261
/* if list */
262
$ifdescrs = get_configured_interface_with_descr();
263

    
264
foreach ($ifdescrs as $key => $interface) {
265
	$thisif = convert_friendly_interface_to_real_interface_name($key);
266
	if (!empty($thisif)) {
267
		$hwif[$thisif] = $interface;
268
	}
269
}
270

    
271
$data = array();
272
foreach ($rawdata as $line) {
273
	$elements = explode(' ', $line);
274

    
275
	if ($elements[3] != "(incomplete)") {
276
		$arpent = array();
277
		$arpent['ip'] = trim(str_replace(array('(', ')'), '', $elements[1]));
278
		$arpent['mac'] = trim($elements[3]);
279
		$arpent['interface'] = trim($elements[5]);
280
		$data[] = $arpent;
281
	}
282
}
283

    
284
function _getHostName($mac, $ip) {
285
	global $dhcpmac, $dhcpip;
286

    
287
	if ($dhcpmac[$mac]) {
288
		return $dhcpmac[$mac];
289
	} else if ($dhcpip[$ip]) {
290
		return $dhcpip[$ip];
291
	} else {
292
		exec("host -W 1 " . escapeshellarg($ip), $output);
293
		if (preg_match('/.*pointer ([A-Za-z_0-9.-]+)\..*/', $output[0], $matches)) {
294
			if ($matches[1] <> $ip) {
295
				return $matches[1];
296
			}
297
		}
298
	}
299
	return "";
300
}
301

    
302
$pgtitle = array(gettext("Diagnostics"), gettext("ARP Table"));
303
include("head.inc");
304

    
305
// Handle save msg if defined
306
if ($savemsg) {
307
	print_info_box(htmlentities($savemsg), $savemsgtype);
308
}
309
?>
310

    
311
<!-- On modern hardware the table will load so fast you may never see this! -->
312
<div id="loading">
313
	<?= gettext(" Loading, please wait...")?>
314
</div>
315

    
316
<?php
317

    
318
// Flush buffers out to client so that they see Loading, please wait....
319
for ($i = 0; $i < ob_get_level(); $i++) {
320
	ob_end_flush();
321
}
322

    
323
ob_implicit_flush(1);
324

    
325
// Resolve hostnames and replace Z_ with "".  The intention
326
// is to sort the list by hostnames, alpha and then the non
327
// resolvable addresses will appear last in the list.
328
$dnsavailable=1;
329
$dns = trim(_getHostName("", "8.8.8.8"));
330
if ($dns == "") {
331
	$dns = trim(_getHostName("", "8.8.4.4"));
332
	if ($dns == "") {
333
		$dnsavailable = 0;
334
	}
335
}
336

    
337
foreach ($data as &$entry) {
338
	if ($dnsavailable) {
339
		$dns = trim(_getHostName($entry['mac'], $entry['ip']));
340
	} else {
341
		$dns="";
342
	}
343
	if (trim($dns)) {
344
		$entry['dnsresolve'] = "$dns";
345
	} else {
346
		$entry['dnsresolve'] = "Z_ ";
347
	}
348
}
349
unset($entry);
350

    
351
// Sort the data alpha first
352
$data = msort($data, "dnsresolve");
353

    
354
// Load MAC-Manufacturer table
355
$mac_man = load_mac_manufacturer_table();
356
?>
357
<div class="panel panel-default">
358
	<div class="panel-heading"><h2 class="panel-title"><?=gettext('ARP Table')?></h2></div>
359
	<div class="panel-body">
360

    
361
<div class="table-responsive">
362
	<table class="sortable-theme-bootstrap table table-striped table-hover" data-sortable>
363
		<thead>
364
			<tr>
365
				<th><?= gettext("Interface")?></th>
366
				<th><?= gettext("IP address")?></th>
367
				<th><?= gettext("MAC address")?></th>
368
				<th><?= gettext("Hostname")?></th>
369
				<th data-sortable="false"><?=gettext("Actions")?></th>
370
			</tr>
371
		</thead>
372
		<tbody>
373

    
374
<?php
375
		foreach ($data as $entry): ?>
376
			<tr>
377
				<td><?=$hwif[$entry['interface']]?></td>
378
				<td><?=$entry['ip']?></td>
379
				<td>
380
					<?=trim($entry['mac'])?>
381
				<?php
382
					$mac = trim($entry['mac']);
383
					$mac_hi = strtoupper($mac[0] . $mac[1] . $mac[3] . $mac[4] . $mac[6] . $mac[7]);
384

    
385
					if (isset($mac_man[$mac_hi])) {
386
						print '<small>('. $mac_man[$mac_hi] .')</small>';
387
					}
388
	?>
389
				</td>
390
				<td><?=trim(str_replace("Z_ ", "", $entry['dnsresolve']))?></td>
391
				<td>
392
					<a class="fa fa-trash" title="<?=gettext('Delete arp cache entry')?>"	href="diag_arp.php?deleteentry=<?=$entry['ip']?>"></a>
393
				</td>
394
			</tr>
395
		<?php endforeach?>
396
		</tbody>
397
	</table>
398
</div>
399

    
400
	</div>
401
</div>
402

    
403
<script type="text/javascript">
404
//<![CDATA[
405
// Clear the "loading" div once the page has loaded"
406
events.push(function() {
407
	$('#loading').empty();
408
});
409
//]]>
410
</script>
411

    
412
<div class="infoblock blockopen">
413
<?php
414
print_info_box(gettext("Local IPv6 peers use ") . '<a href="diag_ndp.php">' . gettext("NDP") . '</a>' . gettext(" instead of ARP."), 'info', false);
415
?>
416
</div>
417

    
418
<?php
419
include("foot.inc");
420
?>
(4-4/227)