[ Team LiB ] Previous Section Next Section

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

1419 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

2022 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




    [ Team LiB ] Previous Section Next Section