ioctl操作ARP缓存表(ZZ)

原文地址: http://hi.baidu.com/virusfun/item/b526b5dea33bc447dcf9be74
 
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
002
003 #include
004 #include
005 #include
006
007 #include
008 #include
009 #include
010 #include
011 #include
012 #include
013 #include
014 #include
015 #include
016 #include
017 #include
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 }

你可能感兴趣的:(linux编程)