ARP缓存表arp_tbl由协议栈在运行期间自动维护,包括邻居新建,更新,回收等。同时,TCP/IP协议栈的实现中也提供了三个命令,可以用来由用 户维护arp_tbl,这三个命令分别是SIOCDARP(删除arp_tbl中的一个邻居),SIOCSARP(设置arp_tbl中的一个邻居), SIOCGARP(获取arp_tbl中的一个邻居)。用户使用系统调用ioctl来传递这三个命令,命令参数是结构体struct arpreq,其定义如下:
struct arpreq {
struct sockaddr arp_pa; //协议地址
struct sockaddr arp_ha; //硬件地址
int arp_flags; //标志位
struct sockaddr arp_netmask; //网络掩码(只用于代理ARP)
char arp_dev[16]; //对应的网络设备接口的名称。
};
使用SIOCDARP命令时,只要在struct arpreq结构体填入arp_pa,arp_dev,内核会根据arp_pa中的邻居IP地址从myarp_tbl的哈希表hash_buckets中 找出该邻居,并把它的状态更新为NUD_FAILED(失败),则在下一次的arp垃圾回收中,该邻居就会被会收掉。
使用SIOCSARP命令时,需要设置struct arpreq的arp_pa,arp_ha,arp_flags。如果arp_tbl中已存在该邻居,会更新该邻居,否则新建一个邻居,其状态为 NUD_STALE,如果arp_flags中有ATF_PERM,状态再加上NUD_PERMANENT。
使用SIOCGARP时,只需要arp_pa,arp_dev 即可从arp_tbl中找到该邻居并返回,不过,一般要查看arp缓存,并不使用SIOCGARP命令,而是从proc/net/arp文件中取。
struct arpreq的arp_flags上的标志有如下一些:
#define ATF_COM 0x02 //已完成的邻居 (成员ha有效,且含有正确的MAC地址)
#define ATF_PERM 0x04 //永久性的邻居(邻居状态有NUD_PERMANENT)
#define ATF_PUBL 0x08 //发布该邻居。
#define ATF_USETRAILERS 0x10 //不是非常清楚。
#define ATF_NETMASK 0x20 //仅用于代理ARP。
#define ATF_DONTPUB 0x40 //不处理该邻居。
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
你应该还包含其他的头文件
struct arpreq arpreq;
ioctl(s, SIOCSARP, (caddr_t)&arpreq);
ioctl(s, SIOCGARP, (caddr_t)&arpreq);
ioctl(s, SIOCDARP, (caddr_t)&arpreq);
int Get_Entry()
{
int sd;
struct arpreq arpreq;
struct sockaddr_in *sin;
struct in_addr ina;
char ip[] = "192.168.10.1";
unsigned char *hw_addr;
int rc;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
{
perror("socket() error/n");
exit(1);
}
/* Try to find an entry in arp cache for the ip address specified */
printf("Find arp entry for IP : %s/n", ip);
/*you must add this becasue some system will return "Invlid argument"
because some argument isn't zero */
memset(&arpreq, 0, sizeof(struct arpreq));
sin = (struct sockaddr_in *) &arpreq.arp_pa;
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
ina.s_addr = inet_addr(ip);
memcpy(&sin->sin_addr, (char *)&ina, sizeof(struct in_addr));
strcpy(arpreq.arp_dev, "eth1");
rc = ioctl(sd, SIOCGARP, &arpreq);
if (rc < 0)
{
perror("Entry not available in cache.../n");
}
else
{
printf("/nentry has been successfully retreived/n");
hw_addr = (unsigned char *) arpreq.arp_ha.sa_data;
printf("HWAddr found : %02x:%02x:%02x:%02x:%02x:%02x/n",
hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4], hw_addr[5]);
}
return 0;
}
struct arpreq {
struct sockaddr arp_pa; //协议地址
struct sockaddr arp_ha; //硬件地址
int arp_flags; //标志位
struct sockaddr arp_netmask; //网络掩码(只用于代理ARP)
char arp_dev[16]; //对应的网络设备接口的名称。
};
使用SIOCDARP命令时,只要在struct arpreq结构体填入arp_pa,arp_dev,内核会根据arp_pa中的邻居IP地址从myarp_tbl的哈希表hash_buckets中 找出该邻居,并把它的状态更新为NUD_FAILED(失败),则在下一次的arp垃圾回收中,该邻居就会被会收掉。
使用SIOCSARP命令时,需要设置struct arpreq的arp_pa,arp_ha,arp_flags。如果arp_tbl中已存在该邻居,会更新该邻居,否则新建一个邻居,其状态为 NUD_STALE,如果arp_flags中有ATF_PERM,状态再加上NUD_PERMANENT。
使用SIOCGARP时,只需要arp_pa,arp_dev 即可从arp_tbl中找到该邻居并返回,不过,一般要查看arp缓存,并不使用SIOCGARP命令,而是从proc/net/arp文件中取。
struct arpreq的arp_flags上的标志有如下一些:
#define ATF_COM 0x02 //已完成的邻居 (成员ha有效,且含有正确的MAC地址)
#define ATF_PERM 0x04 //永久性的邻居(邻居状态有NUD_PERMANENT)
#define ATF_PUBL 0x08 //发布该邻居。
#define ATF_USETRAILERS 0x10 //不是非常清楚。
#define ATF_NETMASK 0x20 //仅用于代理ARP。
#define ATF_DONTPUB 0x40 //不处理该邻居。
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/if_ether.h>
你应该还包含其他的头文件
struct arpreq arpreq;
ioctl(s, SIOCSARP, (caddr_t)&arpreq);
ioctl(s, SIOCGARP, (caddr_t)&arpreq);
ioctl(s, SIOCDARP, (caddr_t)&arpreq);
int Get_Entry()
{
int sd;
struct arpreq arpreq;
struct sockaddr_in *sin;
struct in_addr ina;
char ip[] = "192.168.10.1";
unsigned char *hw_addr;
int rc;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd < 0)
{
perror("socket() error/n");
exit(1);
}
/* Try to find an entry in arp cache for the ip address specified */
printf("Find arp entry for IP : %s/n", ip);
/*you must add this becasue some system will return "Invlid argument"
because some argument isn't zero */
memset(&arpreq, 0, sizeof(struct arpreq));
sin = (struct sockaddr_in *) &arpreq.arp_pa;
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
ina.s_addr = inet_addr(ip);
memcpy(&sin->sin_addr, (char *)&ina, sizeof(struct in_addr));
strcpy(arpreq.arp_dev, "eth1");
rc = ioctl(sd, SIOCGARP, &arpreq);
if (rc < 0)
{
perror("Entry not available in cache.../n");
}
else
{
printf("/nentry has been successfully retreived/n");
hw_addr = (unsigned char *) arpreq.arp_ha.sa_data;
printf("HWAddr found : %02x:%02x:%02x:%02x:%02x:%02x/n",
hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4], hw_addr[5]);
}
return 0;
}