ARP缓存表arp_tbl由协议栈在运行期间自动维护,包括邻居新建,更新,回收等。同时,TCP/IP协议栈的实现中也提供了三个命令,可以用来由用户维护arp_tbl,这三个命令分别是SIOCDARP(删除arp_tbl中的一个邻居),SIOCSARP(设置arp_tbl中的一个邻居), SIOCGARP(获取arp_tbl中的一个邻居)。用户使用系统调用ioctl来传递这三个命令,命令参数是结构体struct arpreq,其定义如下:
1 struct arpreq {
2 struct sockaddr arp_pa; //协议地址
3 struct sockaddr arp_ha; //硬件地址
4 int arp_flags; //标志位
5 struct sockaddr arp_netmask; //网络掩码(只用于代理ARP)
6 char arp_dev[16]; //对应的网络设备接口的名称。
7 };
使用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_tbl中找到该邻居并返回,不过,一般要查看arp缓存,并不使用SIOCGARP命令,而是从proc/net/arp文件中取。
struct arpreq的arp_flags上的标志有如下一些:
1 #define ATF_COM 0x02 //已完成的邻居(成员ha有效,且含有正确的MAC地址)
2 #define ATF_PERM 0x04 //永久性的邻居(邻居状态有NUD_PERMANENT)
3 #define ATF_PUBL 0x08 //发布该邻居
4 #define ATF_USETRAILERS 0x10 //不是非常清楚
5 #define ATF_NETMASK 0x20 //仅用于代理ARP
6 #define ATF_DONTPUB 0x40 //不处理该邻居
001 #include <sys/types.h>
002
003 #include <sys/socket.h>
004 #include <netinet/in.h>
005 #include <arpa/inet.h>
006
007 #include <sys/ioctl.h>
008 #include <net/if.h>
009 #include <netinet/if_ether.h>
010 #include <net/if_arp.h>
011 #include <stdlib.h>
012 #include <stdio.h>
013 #include <errno.h>
014 #include <ctype.h>
015 #include <fcntl.h>
016 #include <string.h>
017 #include <unistd.h>
018
019 #define DEV_NAME "eth0"
020 //#define SIOCDARP 0x8953 /* delete ARP table entry */
021 //#define SIOCGARP 0x8954 /* get ARP table entry */
022 //#define SIOCSARP 0x8955 /* set ARP table entry */
023
024 static int sd;
025
026 /* Delete an entry from the ARP cache. */
027 static int arp_del(char *ip)
028 {
029 struct arpreq arpreq;
030 struct sockaddr_in *sin;
031 struct in_addr ina;
032 int rc;
033
034 printf("del arp entry for IP : %s\n", ip);
035
036 /*you must add this becasue some system will return "Invlid argument"
037 because some argument isn't zero */
038 memset(&arpreq, 0, sizeof(struct arpreq));
039
040 sin = (struct sockaddr_in *) &arpreq.arp_pa;
041 memset(sin, 0, sizeof(struct sockaddr_in));
042 sin->sin_family = AF_INET;
043 ina.s_addr = inet_addr(ip);
044 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
045
046 strcpy(arpreq.arp_dev, DEV_NAME);
047 rc = ioctl(sd, SIOCDARP, &arpreq);
048 if (rc < 0)
049 {
050 printf("%s\n", "del arp error...");
051 return -1;
052 } else
053 printf("%s\n", "del arp success...");
054
055 return 0;
056 }
057
058 void get_hw_addr(u_char * buf, char *str)
059 {
060 int i;
061 unsigned int p[6];
062
063 i = sscanf(str, "%x:%x:%x:%x:%x:%x", &p[0], &p[1], &p[2],
064 &p[3], &p[4], &p[5]);
065
066 if (i != 6)
067 {
068 printf("%s\n", "error parsing MAC");
069 exit(1);
070 }
071
072 for (i = 0; i < 6; i++)
073 buf[i] = p[i];
074 }
075
076 /* Set an entry in the ARP cache. */
077 static int arp_set(char *ip, char *mac)
078 {
079 struct arpreq arpreq;
080 struct sockaddr_in *sin;
081 struct in_addr ina;
082 int flags;
083 int rc;
084
085 printf("set arp entry for IP:%s\tMAC:%s\n", ip, mac);
086
087 /*you must add this becasue some system will return "Invlid argument"
088 because some argument isn't zero */
089 memset(&arpreq, 0, sizeof(struct arpreq));
090 sin = (struct sockaddr_in *) &arpreq.arp_pa;
091 memset(sin, 0, sizeof(struct sockaddr_in));
092 sin->sin_family = AF_INET;
093 ina.s_addr = inet_addr(ip);
094 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
095
096 get_hw_addr((unsigned char *) arpreq.arp_ha.sa_data, mac);
097 strcpy(arpreq.arp_dev, DEV_NAME);
098
099 flags = ATF_PERM | ATF_COM; //note, must set flag, if not,you will get error
100
101 arpreq.arp_flags = flags;
102
103 rc = ioctl(sd, SIOCSARP, &arpreq);
104 if (rc < 0)
105 {
106 printf("%s\n", "set arp error...");
107 return -1;
108 } else
109 printf("%s\n", "set arp successfully");
110
111 return 0;
112 }
113
114 static int arp_get(char *ip)
115 {
116 struct arpreq arpreq;
117 struct sockaddr_in *sin;
118 struct in_addr ina;
119 unsigned char *hw_addr;
120 int rc;
121
122 printf("Find arp entry for IP : %s\n", ip);
123
124 /*you must add this becasue some system will return "Invlid argument"
125 because some argument isn't zero */
126
127 memset(&arpreq, 0, sizeof(struct arpreq));
128
129 sin = (struct sockaddr_in *) &arpreq.arp_pa;
130 memset(sin, 0, sizeof(struct sockaddr_in));
131 sin->sin_family = AF_INET;
132 ina.s_addr = inet_addr(ip);
133 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
134
135 strcpy(arpreq.arp_dev, DEV_NAME);
136 rc = ioctl(sd, SIOCGARP, &arpreq);
137 if (rc < 0)
138 {
139 printf("%s\n", "Entry not available in cache...");
140 return -1;
141 } else
142 {
143 printf("%s\n", "entry has been successfully retreived");
144 hw_addr = (unsigned char *) arpreq.arp_ha.sa_data;
145
146 printf("HWAddr found : %02x:%02x:%02x:%02x:%02x:%02x\n",
147 hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4],
148 hw_addr[5]);
149 }
150 return 0;
151 }
152
153 int main(int argc, char **argv)
154 {
155 sd = socket(AF_INET, SOCK_DGRAM, 0);
156 if (sd < 0)
157 {
158 perror("socket() error\n");
159 exit(1);
160 }
161
162 if (strcmp(argv[1], "add") == 0)
163 arp_set(argv[2], argv[3]);
164 else if (strcmp(argv[1], "del") == 0)
165 arp_del(argv[2]);
166 else if (strcmp(argv[1], "get") == 0)
167 arp_get(argv[2]);
168
169 close(sd);
170 return 0;
171 }
1 struct arpreq {
2 struct sockaddr arp_pa; //协议地址
3 struct sockaddr arp_ha; //硬件地址
4 int arp_flags; //标志位
5 struct sockaddr arp_netmask; //网络掩码(只用于代理ARP)
6 char arp_dev[16]; //对应的网络设备接口的名称。
7 };
使用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_tbl中找到该邻居并返回,不过,一般要查看arp缓存,并不使用SIOCGARP命令,而是从proc/net/arp文件中取。
struct arpreq的arp_flags上的标志有如下一些:
1 #define ATF_COM 0x02 //已完成的邻居(成员ha有效,且含有正确的MAC地址)
2 #define ATF_PERM 0x04 //永久性的邻居(邻居状态有NUD_PERMANENT)
3 #define ATF_PUBL 0x08 //发布该邻居
4 #define ATF_USETRAILERS 0x10 //不是非常清楚
5 #define ATF_NETMASK 0x20 //仅用于代理ARP
6 #define ATF_DONTPUB 0x40 //不处理该邻居
001 #include <sys/types.h>
002
003 #include <sys/socket.h>
004 #include <netinet/in.h>
005 #include <arpa/inet.h>
006
007 #include <sys/ioctl.h>
008 #include <net/if.h>
009 #include <netinet/if_ether.h>
010 #include <net/if_arp.h>
011 #include <stdlib.h>
012 #include <stdio.h>
013 #include <errno.h>
014 #include <ctype.h>
015 #include <fcntl.h>
016 #include <string.h>
017 #include <unistd.h>
018
019 #define DEV_NAME "eth0"
020 //#define SIOCDARP 0x8953 /* delete ARP table entry */
021 //#define SIOCGARP 0x8954 /* get ARP table entry */
022 //#define SIOCSARP 0x8955 /* set ARP table entry */
023
024 static int sd;
025
026 /* Delete an entry from the ARP cache. */
027 static int arp_del(char *ip)
028 {
029 struct arpreq arpreq;
030 struct sockaddr_in *sin;
031 struct in_addr ina;
032 int rc;
033
034 printf("del arp entry for IP : %s\n", ip);
035
036 /*you must add this becasue some system will return "Invlid argument"
037 because some argument isn't zero */
038 memset(&arpreq, 0, sizeof(struct arpreq));
039
040 sin = (struct sockaddr_in *) &arpreq.arp_pa;
041 memset(sin, 0, sizeof(struct sockaddr_in));
042 sin->sin_family = AF_INET;
043 ina.s_addr = inet_addr(ip);
044 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
045
046 strcpy(arpreq.arp_dev, DEV_NAME);
047 rc = ioctl(sd, SIOCDARP, &arpreq);
048 if (rc < 0)
049 {
050 printf("%s\n", "del arp error...");
051 return -1;
052 } else
053 printf("%s\n", "del arp success...");
054
055 return 0;
056 }
057
058 void get_hw_addr(u_char * buf, char *str)
059 {
060 int i;
061 unsigned int p[6];
062
063 i = sscanf(str, "%x:%x:%x:%x:%x:%x", &p[0], &p[1], &p[2],
064 &p[3], &p[4], &p[5]);
065
066 if (i != 6)
067 {
068 printf("%s\n", "error parsing MAC");
069 exit(1);
070 }
071
072 for (i = 0; i < 6; i++)
073 buf[i] = p[i];
074 }
075
076 /* Set an entry in the ARP cache. */
077 static int arp_set(char *ip, char *mac)
078 {
079 struct arpreq arpreq;
080 struct sockaddr_in *sin;
081 struct in_addr ina;
082 int flags;
083 int rc;
084
085 printf("set arp entry for IP:%s\tMAC:%s\n", ip, mac);
086
087 /*you must add this becasue some system will return "Invlid argument"
088 because some argument isn't zero */
089 memset(&arpreq, 0, sizeof(struct arpreq));
090 sin = (struct sockaddr_in *) &arpreq.arp_pa;
091 memset(sin, 0, sizeof(struct sockaddr_in));
092 sin->sin_family = AF_INET;
093 ina.s_addr = inet_addr(ip);
094 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
095
096 get_hw_addr((unsigned char *) arpreq.arp_ha.sa_data, mac);
097 strcpy(arpreq.arp_dev, DEV_NAME);
098
099 flags = ATF_PERM | ATF_COM; //note, must set flag, if not,you will get error
100
101 arpreq.arp_flags = flags;
102
103 rc = ioctl(sd, SIOCSARP, &arpreq);
104 if (rc < 0)
105 {
106 printf("%s\n", "set arp error...");
107 return -1;
108 } else
109 printf("%s\n", "set arp successfully");
110
111 return 0;
112 }
113
114 static int arp_get(char *ip)
115 {
116 struct arpreq arpreq;
117 struct sockaddr_in *sin;
118 struct in_addr ina;
119 unsigned char *hw_addr;
120 int rc;
121
122 printf("Find arp entry for IP : %s\n", ip);
123
124 /*you must add this becasue some system will return "Invlid argument"
125 because some argument isn't zero */
126
127 memset(&arpreq, 0, sizeof(struct arpreq));
128
129 sin = (struct sockaddr_in *) &arpreq.arp_pa;
130 memset(sin, 0, sizeof(struct sockaddr_in));
131 sin->sin_family = AF_INET;
132 ina.s_addr = inet_addr(ip);
133 memcpy(&sin->sin_addr, (char *) &ina, sizeof(struct in_addr));
134
135 strcpy(arpreq.arp_dev, DEV_NAME);
136 rc = ioctl(sd, SIOCGARP, &arpreq);
137 if (rc < 0)
138 {
139 printf("%s\n", "Entry not available in cache...");
140 return -1;
141 } else
142 {
143 printf("%s\n", "entry has been successfully retreived");
144 hw_addr = (unsigned char *) arpreq.arp_ha.sa_data;
145
146 printf("HWAddr found : %02x:%02x:%02x:%02x:%02x:%02x\n",
147 hw_addr[0], hw_addr[1], hw_addr[2], hw_addr[3], hw_addr[4],
148 hw_addr[5]);
149 }
150 return 0;
151 }
152
153 int main(int argc, char **argv)
154 {
155 sd = socket(AF_INET, SOCK_DGRAM, 0);
156 if (sd < 0)
157 {
158 perror("socket() error\n");
159 exit(1);
160 }
161
162 if (strcmp(argv[1], "add") == 0)
163 arp_set(argv[2], argv[3]);
164 else if (strcmp(argv[1], "del") == 0)
165 arp_del(argv[2]);
166 else if (strcmp(argv[1], "get") == 0)
167 arp_get(argv[2]);
168
169 close(sd);
170 return 0;
171 }