17.8 ARP Cache Operations
On some systems, the ARP cache is also
manipulated with the ioctl function. Systems that use
routing sockets (Chapter 18) usually use routing
sockets instead of ioctl to access the ARP cache. These
requests use an arpreq structure, shown in Figure 17.12 and defined by
including the <net/if_arp.h> header.
Figure 17.12
arpreq structure used with ioctl requests for ARP
cache.
<net/if_arp.h>
struct arpreq {
struct sockaddr arp_pa; /* protocol address */
struct sockaddr arp_ha; /* hardware address */
int arp_flags; /* flags */
};
#define ATF_INUSE 0x01 /* entry in use */
#define ATF_COM 0x02 /* completed entry (hardware addr valid) */
#define ATF_PERM 0x04 /* permanent entry */
#define ATF_PUBL 0x08 /* published entry (respond for other host) */
The third argument to ioctl must point
to one of these structures. The following three requests are supported:
SIOCSARP
|
Add a new entry to the ARP cache or modify an
existing entry. arp_pa is an Internet socket address
structure containing the IP address, and arp_ha is a
generic socket address structure with sa_family set to
AF_UNSPEC and sa_data containing the hardware
address (e.g., the 6-byte Ethernet address). The two flags,
ATF_PERM and ATF_PUBL, can be specified by the
application. The other two flags, ATF_INUSE and
ATF_COM, are set by the kernel.
|
SIOCDARP
|
Delete an entry from the ARP cache. The caller
specifies the Internet address for the entry to be deleted.
|
SIOCGARP
|
Get an entry from the ARP cache. The caller
specifies the Internet address, and the corresponding Ethernet
address is returned along with the flags.
|
Only the superuser can add or delete an entry.
These three requests are normally issued by the arp
program.
These ARP-related ioctl requests are
not supported on some newer systems, which use routing sockets for
these ARP operations.
Notice that there is no way with ioctl
to list all the entries in the ARP cache. On many systems, the
arp command, when invoked with the -a flag (list
all entries in the ARP cache), reads the kernel's memory
(/dev/kmem) to obtain the current contents of the ARP
cache. We will see an easier (and better) way to do this using
sysctl, which only works on some systems (Section
18.4).
Example: Print Hardware Addresses of
Host
We now use our get_ifi_info function to
return all of a host's IP addresses, followed by an ioctl
of SIOCGARP for each IP address to obtain and print the
hardware addresses. We show our program in Figure 17.13.
Get List of Addresses and Loop Through
Each One
12 We
call get_ifi_info to obtain the host's IP addresses and
then loop through each address.
Print IP Address
13 We
print the IP address using sock_ntop. We asked
get_ifi_info to only return IPv4 addresses, since ARP is
not used with IPv6.
Issue ioctl and Check for
Error
14鈥?9
We fill in the arp_pa structure as an IPv4 socket address
structure containing the IPv4 address. ioctl is called,
and if it returns an error (e.g., because the address supplied
isn't on an interface that supports ARP), we print the error and
loop to the next address.
Print Hardware Address
20鈥?2
The hardware address returned from the ioctl is
printed.
Figure 17.13
Print a host's hardware addresses.
ioctl/prmac.c
1 #include "unpifi.h"
2 #include <net/if_arp.h>
3 int
4 main(int argc, char **argv)
5 {
6 int sockfd;
7 struct ifi_info *ifi;
8 unsigned char *ptr;
9 struct arpreq arpreq;
10 struct sockaddr_in *sin;
11 sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
12 for (ifi = get_ifi_info(AF_INET, 0); ifi != NULL; ifi = ifi->ifi_next) {
13 printf("%s: ", Sock_ntop(ifi->ifi_addr, sizeof(struct sockaddr_in)));
14 sin = (struct sockaddr_in *) &arpreq.arp_pa;
15 memcpy(sin, ifi->ifi_addr, sizeof(struct sockaddr_in));
16 if (ioctl(sockfd, SIOCGARP, &arpreq) < 0) {
17 err_ret("ioctl SIOCGARP");
18 continue;
19 }
20 ptr = &arpreq.arp_ha.sa_data[0];
21 printf("%x:%x:%x:%x:%x:%x\n", *ptr, *(ptr + 1),
22 *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));
23 }
24 exit(0);
25 }
Running this program on our hpux host
gives
hpux % prmac
192.6.38.100: 0:60:b0:c2:68:9b
192.168.1.1: 0:60:b0:b2:28:2b
127.0.0.1: ioctl SIOCGARP: Invalid argument
|