Is there any better way to get mac address from arp table?
Asked Answered
C

7

5

I want to get a mac address from arp table by using ip address. Currently I am using this command

arp -a $ipAddress | awk '{print $4}'

This command prints what I want. But I am not comfortable with it and I wonder if there is any built-in way or more stable way to do this.

Charissa answered 8/12, 2012 at 13:47 Comment(0)
C
5

You can parse the /proc/net/arp file using awk:

awk "/^${ipAddress//./\.}\>/"' { print $4 }' /proc/net/arp

but I'm not sure it's simpler (it saves one fork and a subshell, though).

If you want a 100% bash solution:

while read ip _ _ mac _; do
    [[ "$ip" == "$ipAddress" ]] && break
done < /proc/net/arp
echo "$mac"
Cand answered 8/12, 2012 at 14:1 Comment(3)
nice answer. But I think if awk fails,the same reason (column order change etc.) probably causes to bash code fails. Am I wrong?Charissa
@Charissa You're absolutely right. If one day some guy decides there should be some change in the /proc/net/arp file, your code will fail miserably. Now is this likely to happen anytime soon? Who knows... The safest way is of course to use the ARP protocol directly using a wrapper library. But this will work until the library API is changed by some guy who decides it should... Anyway, I'd say you'll be safe for some time using either method.Cand
The linux kernel guys like to keep their external API stable -- as stated in my answer, it is the same source of information as arp uses.Philologian
S
1

Well, you could write a program (such as in C) to actually use the ARP protocol (yes, I know that's redundant, like ATM machine or PIN number) itself to get you the information but that's likely to be a lot harder than a simple pipeline.

Perhaps you should examine your comfort level a little more critically, since it's likely to cause you some unnecessary effort :-)

The manpage for the Linux ARP kernel module lists several methods for manipulating or reading the ARP tabes, ioctl probably being the easiest.

Senseless answered 8/12, 2012 at 13:50 Comment(0)
P
1

The output of arp -a is locale dependent (i.e. it changes with your system language). So it might be a good idea to at least force it to the default locale:

LC_ALL=C arp -a $ipAddress | awk '{print $4}'

However, I share your fear that the output of arp -a is not meant to be parsed. If your program is restricted to linux system, another option would be to parse the file /proc/net/arp. This file is exported by the kernel and is what arp itself parses to get its information. The format of this file is described in the manpage proc(5), see man 5 proc. This can be easily done with awk:

awk '$1==IPADDRESS {print $4}' /proc/net/arp
Philologian answered 8/12, 2012 at 14:1 Comment(0)
B
1

Update, removed PIPE

sed -nr 's/^'${ipAddress//./\.}'.*(([0-9A-Za-z]{2}:){5}[0-9A-Za-z]{2}).*$/\1/p' /proc/net/arp

Solution for non-fixed column;

arp -a $ipAddress | sed -n 's/^.*\(\([0-9A-Z]\{2\}:\)\{5\}[0-9A-Z]\{2\}\).*$/\1/p'

Explanation

  • ^.* - Match start of string ^ followed by any character .*.
  • [0-9A-Z]\{2\}: - Match any character of numeric alpha-numeric twice followed by colon.
  • \([0-9A-Z]\{2\}:\)\{5\} - Match the pattern between the ( ) five times.
  • [0-9A-Z]\{2\} - Match any character of numeric alpha-numeric twice.
  • .*$ - Match any characters zero or more times .* until end of string $.
  • \1/p - Return capture pattern 1 / p print the match.
Bubalo answered 9/12, 2012 at 5:46 Comment(0)
M
0

Here's an awk + sed solution which doesn't assume the column number is always 4.

#!/bin/bash

cat /proc/net/arp |\
    # remove space from column headers
    sed 's/\([^ ]\)[ ]\([^ ]\)/\1_\2/g' |\
    # find HW_address column number and/or print that column
    awk '{
        if ( !column ) {
            for (i = 1; i <= NF; i++ ) {
                if ( $i ~ /HW_address/ ) { column=i }
            };
            print $column
         }
         else {
            print $column
         }
    }'

There are still fragile assumptions here, such as the column name being "HW address".

Majoriemajority answered 9/12, 2012 at 3:8 Comment(0)
H
0

You can use this one for scripting:

awk ' $1~/[[:digit:]]/ {print $4}' /proc/net/arp

what it do:

  1. read /proc/net/arp (standard arp output)

  2. searchig for strings with [0-9]

  3. get the 4rd "column" with mac adresses

Enjoy!

Hornpipe answered 22/2, 2016 at 15:36 Comment(0)
S
0

I prefer to use the arping command to explicitly query the MAC of some IP address (this also updates the local ARP cache):

 arping -c 1 192.168.2.24 | grep -Eo "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]"

It's very useful to find if there exist two or more hosts using the same IP address (add -D option), or to check the current IP addresses used in the local VLAN with a simple script like:

for i in $(seq 1 254); do 
    IP="192.168.5.$i"
    MAC=$(arping -c 1 $IP | grep -Eo "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]")
    if [ "$MAC" ] ; then
        echo "$IP $MAC"
    fi
done

Note that arping can't detect the IP address of the local host in this way (but we can add checks in the script to show it if exists in the range).

There exist several versions of arping with slightly different options and output. In Linux Ubuntu there are one in the package iputils-arping and other in the package arping.

Note: To answer the question and not the problem, when filtering /proc/net/arp you must use a regex that ensures the full match, like ending the expression with a space (otherwise, in this example, it will show also 2.240-2.249 addresses if present):

ipaddress="192.168.2.24"
grep "^${ipaddress} " /proc/net/arp | grep -Eo "([0-9a-fA-F]{2}:){5}[0-9a-fA-F]")
Segarra answered 16/12, 2021 at 23:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.