摘要:相关定义条目相关操作的定义条目操作的结构与相关标志作为的第个参数,分别用于在表中删除获取添加单个条目结构地址作为的第个参数执行操作时,被转换为套接字地址结构,表示目的端的地址为通用套接字地址结构,为,中包含网络接口的层地址,如以太网地址
相关定义
ARP条目相关操作的定义
/* include/linux/sockios.h */ /* ARP cache control calls. */ /* 0x8950 - 0x8952 * obsolete calls, don"t re-use */ #define SIOCDARP 0x8953 /* delete ARP table entry */ #define SIOCGARP 0x8954 /* get ARP table entry */ #define SIOCSARP 0x8955 /* set ARP table entry */
ARP条目操作的结构与相关标志
/* include/linux/if_arp.h */ /* ARP ioctl request. */ struct arpreq { struct sockaddr arp_pa; /* protocol address */ struct sockaddr arp_ha; /* hardware address */ int arp_flags; /* flags */ struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ char arp_dev[16]; }; /* ARP Flag values. */ #define ATF_COM 0x02 /* completed entry (ha valid) */ #define ATF_PERM 0x04 /* permanent entry */ #define ATF_PUBL 0x08 /* publish entry */ #define ATF_USETRAILERS 0x10 /* has requested trailers */ #define ATF_NETMASK 0x20 /* want to use a netmask (only for proxy entries) */ #define ATF_DONTPUB 0x40 /* don"t answer this addresses */
SIOCDARP/SIOCGARP/SIOCSARP作为ioctl(2)的第2个参数,分别用于在ARP表中删除/获取/添加单个条目
struct arpreq结构地址作为ioctl(2)的第3个参数;执行操作时,arp_pa被转换为IPv4套接字地址结构(struct sockaddr_in),表示目的端的IP地址;arp_ha为通用套接字地址结构,sa_family为AF_UNSPEC,sa_data中包含网络接口的2层地址,如以太网mac地址,表示目的端的2层地址;arp_flags用于指定ARP操作的标志;arp_netmask用于代理ARP;arp_dev用于指定本地网络接口的名称
获取ARP条目时,需要初始化arp_pa,arp_dev,然后调用ioctl(SIOCGARP),成功返回后arp_pa中包含的IP地址对应的mac地址保存在arp_ha.sa_data中;若指定的网络接口不存在,或存在但与指定的目标主机IP地址不对应,则ioctl以"(ENXIO)No such device or address"错误调用失败
无法通过ioctl操作获取整个ARP表,arp(8)命令的-a选项是通过读取系统中的/proc/net/arp文件内容实现该目的
添加ARP条目时,需要同时初始化arp_pa,arp_dev,arp_ha.sa_data以及arp_flags,然后调用ioctl(SIOCSARP)
删除ARP条目时,需要初始化arp_pa,arp_dev,然后调用ioctl(SIOCDARP),成功返回后,指定目标地址对应的ARP条目被删除;若指定的网络接口不存在,或存在但与指定的目标主机IP地址不对应,则ioctl以"(ENXIO)No such device or address"错误调用失败
示例程序系统双网卡,名称分别为eth0与eth1
初始的ARP表内容为:
# arp -n Address HWtype HWaddress Flags Mask Iface 192.168.56.254 ether 00:50:56:f8:57:2f C eth0 192.168.56.2 ether 00:50:56:f4:a3:a0 C eth0 192.168.56.1 ether 00:50:56:c0:00:08 C eth0
1 . 指定本地网络接口名称与目标主机IP地址作为参数,获取对应的mac地址
/* get_arp_entry_ioctl.c */ #include#include #include #include #include #include #include #include #include #include static void get_arp_entry(const char *, const char *); int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s [local interface name] [dst ip addres] ", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {" "}; strncpy(ifname, argv[1], IFNAMSIZ-1); char ipaddr[INET_ADDRSTRLEN] = {" "}; strncpy(ipaddr, argv[2], INET_ADDRSTRLEN); get_arp_entry(ifname, ipaddr); return 0; } static void get_arp_entry(const char *dev, const char *ip) { int sfd, saved_errno, ret; unsigned char *mac; struct arpreq arp_req; struct sockaddr_in *sin; sin = (struct sockaddr_in *)&(arp_req.arp_pa); memset(&arp_req, 0, sizeof(arp_req)); sin->sin_family = AF_INET; inet_pton(AF_INET, ip, &(sin->sin_addr)); strncpy(arp_req.arp_dev, dev, IFNAMSIZ-1); sfd = socket(AF_INET, SOCK_DGRAM, 0); saved_errno = errno; ret = ioctl(sfd, SIOCGARP, &arp_req); if (ret < 0) { fprintf(stderr, "Get ARP entry failed : %s ", strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; if (arp_req.arp_flags & ATF_COM) { mac = (unsigned char *)arp_req.arp_ha.sa_data; printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x ", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } else { printf("MAC: Not in the ARP cache. "); } }
编译并运行
# gcc get_arp_entry_ioctl.c -g3 -DC=-5 -o get_arp_entry_ioctl # # ./get_arp_entry_ioctl eth0 192.168.56.1 MAC: 00:50:56:c0:00:08 # # ./get_arp_entry_ioctl eth1 192.168.56.1 Get ARP entry failed : No such device or address # # ./get_arp_entry_ioctl eth1 192.168.56.100 Get ARP entry failed : No such device or address
2 . 指定本地网络接口名称,目标主机IP地址与mac地址作为参数,添加ARP条目
/* set_arp_entry_ioctl.c */ #include#include #include #include #include #include #include #include #include #include #include static void set_arp_entry(char *, char *, char *); static int parse_mac(char *, char *); int main(int argc, char *argv[]) { if (argc != 4) { fprintf(stderr, "Usage: %s [local interface name] [dst ip addres] [dst mac address] ", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {" "}; strncpy(ifname, argv[1], IFNAMSIZ-1); char ipaddr[INET_ADDRSTRLEN] = {" "}; strncpy(ipaddr, argv[2], INET_ADDRSTRLEN); int mac_size = strlen(argv[3]); unsigned char *macaddr = (unsigned char *)malloc(mac_size); memcpy(macaddr, argv[3], mac_size); set_arp_entry(ifname, ipaddr, macaddr); printf("Adding an arp entry done. "); return 0; } static void set_arp_entry(char *dev, char *ip, char *mac) { int sfd, saved_errno, ret; struct arpreq arp_req; struct sockaddr_in *sin; sfd = socket(AF_INET, SOCK_DGRAM, 0); sin = (struct sockaddr_in *)&(arp_req.arp_pa); memset(&arp_req, 0, sizeof(arp_req)); sin->sin_family = AF_INET; inet_pton(AF_INET, ip, &(sin->sin_addr)); strncpy(arp_req.arp_dev, dev, IFNAMSIZ-1); parse_mac(mac, arp_req.arp_ha.sa_data); arp_req.arp_flags = ATF_PERM | ATF_COM; saved_errno = errno; ret = ioctl(sfd, SIOCSARP, &arp_req); if (ret < 0) { fprintf(stderr, "Set ARP entry failed : %s ", strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; } static int parse_mac(char *mac, char *dst) { int i; unsigned byte; char *s; i = 0; while ((s = strsep(&mac, ":")) != NULL) { if (sscanf(s, "%x", &byte) != 1 || byte > 0xff) return -1; *(dst+i) = byte; i++; } if (i != ETH_ALEN) { fprintf(stderr, "Invalid mac address "); exit(EXIT_FAILURE); } return 0; }
编译并运行
# gcc set_arp_entry_ioctl.c -g3 -DC=-5 -o set_arp_entry_ioctl # # ./set_arp_entry_ioctl eth0 192.168.56.100 aa:bb:cc:dd:ee:ff Adding an arp entry done. # # ./get_arp_entry_ioctl eth0 192.168.56.100 MAC: aa:bb:cc:dd:ee:ff # # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.56.1 ether 00:50:56:c0:00:08 C eth0 192.168.56.254 ether 00:50:56:f8:57:2f C eth0 192.168.56.100 ether aa:bb:cc:dd:ee:ff CM eth0 192.168.56.2 ether 00:50:56:f4:a3:a0 C eth0
3 . 指定本地网络接口名称与目标主机IP地址作为参数,删除对应的ARP条目
/* del_arp_entry_ioctl.c */ #include#include #include #include #include #include #include #include #include #include static void del_arp_entry(char *, char *); int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s [local interface name] [dst ip addres] ", argv[0]); exit(EXIT_FAILURE); } char ifname[IFNAMSIZ] = {" "}; strncpy(ifname, argv[1], IFNAMSIZ-1); char ipaddr[INET_ADDRSTRLEN] = {" "}; strncpy(ipaddr, argv[2], INET_ADDRSTRLEN); del_arp_entry(ifname, ipaddr); printf("Deleting an arp entry done. "); } static void del_arp_entry(char *dev, char *ip) { int sfd, saved_errno, ret; struct arpreq arp_req; struct sockaddr_in *sin; sfd = socket(AF_INET, SOCK_DGRAM, 0); sin = (struct sockaddr_in *)&(arp_req.arp_pa); memset(&arp_req, 0, sizeof(arp_req)); sin->sin_family = AF_INET; strncpy(arp_req.arp_dev, dev, IFNAMSIZ-1); inet_pton(AF_INET, ip, &(sin->sin_addr)); saved_errno = errno; ret = ioctl(sfd, SIOCDARP, &arp_req); if (ret < 0) { fprintf(stderr, "Delete ARP entry failed : %s ", strerror(errno)); exit(EXIT_FAILURE); } errno = saved_errno; }
编译并运行
# gcc del_arp_entry_ioctl.c -g3 -DC=-5 -o del_arp_entry_ioctl # # ./del_arp_entry_ioctl eth0 192.168.56.100 Deleting an arp entry done. # # ./del_arp_entry_ioctl eth0 192.168.56.200 Delete ARP entry failed : No such device or address # # ./del_arp_entry_ioctl eth1 192.168.56.100 Delete ARP entry failed : No such device or address # # arp -n Address HWtype HWaddress Flags Mask Iface 192.168.56.1 ether 00:50:56:c0:00:08 C eth0 192.168.56.254 ether 00:50:56:f8:57:2f C eth0 192.168.56.100 (incomplete) eth0 192.168.56.2 ether 00:50:56:f4:a3:a0 C eth0 # # cat /proc/net/arp IP address HW type Flags HW address Mask Device 192.168.56.1 0x1 0x2 00:50:56:c0:00:08 * eth0 192.168.56.254 0x1 0x2 00:50:56:f8:57:2f * eth0 192.168.56.100 0x1 0x0 aa:bb:cc:dd:ee:ff * eth0 192.168.56.2 0x1 0x2 00:50:56:f4:a3:a0 * eth0 # # ./get_arp_entry_ioctl eth0 192.168.56.100 MAC: Not in the ARP cache.
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/9301.html
摘要:提供了一系列网络接口操作相关的命令集,其中,一些传统的工具,如软件包中的,,等都是通过系统调用实现本篇介绍使用进行网络接口参数的获取与设置函数原型第一个参数指定一个由创建的文件描述符第二个参数指定操作的类型,即对该文件描述符执行何种操作第 Linux提供了一系列网络接口操作相关的命令集,其中,一些传统的工具,如net-tools软件包中的ifconfig(8),arp(8),route...
摘要:提供了一系列网络接口操作相关的命令集,其中,一些传统的工具,如软件包中的,,等都是通过系统调用实现本篇介绍使用进行网络接口参数的获取与设置函数原型第一个参数指定一个由创建的文件描述符第二个参数指定操作的类型,即对该文件描述符执行何种操作第 Linux提供了一系列网络接口操作相关的命令集,其中,一些传统的工具,如net-tools软件包中的ifconfig(8),arp(8),route...
摘要:需要修改数据包的二层源目地址以及三层包头的因为路由是逐跳转发的,每一跳都需要做这些工作,即使是现在通过流表转发,中间的转发器直接转发报文,到达倒数第一跳的时候还是需要把数据包的目的地址修改为接受端的地址。 前言 熟悉这款设备的同学,应该也快到不惑之年了吧!这应该是Cisco最古老的路由器了。上个世纪80年代至今,路由交换技术不断发展,但是在这波澜壮阔的变化之中,总有一些东西在嘈杂的机房...
摘要:需要修改数据包的二层源目地址以及三层包头的因为路由是逐跳转发的,每一跳都需要做这些工作,即使是现在通过流表转发,中间的转发器直接转发报文,到达倒数第一跳的时候还是需要把数据包的目的地址修改为接受端的地址。 前言 熟悉这款设备的同学,应该也快到不惑之年了吧!这应该是Cisco最古老的路由器了。上个世纪80年代至今,路由交换技术不断发展,但是在这波澜壮阔的变化之中,总有一些东西在嘈杂的机房...
摘要:需要修改数据包的二层源目地址以及三层包头的因为路由是逐跳转发的,每一跳都需要做这些工作,即使是现在通过流表转发,中间的转发器直接转发报文,到达倒数第一跳的时候还是需要把数据包的目的地址修改为接受端的地址。 前言 熟悉这款设备的同学,应该也快到不惑之年了吧!这应该是Cisco最古老的路由器了。上个世纪80年代至今,路由交换技术不断发展,但是在这波澜壮阔的变化之中,总有一些东西在嘈杂的机房...
阅读 2367·2021-11-17 09:33
阅读 1072·2019-08-30 15:55
阅读 990·2019-08-27 14:26
阅读 1525·2019-08-26 10:21
阅读 3270·2019-08-23 18:28
阅读 3282·2019-08-23 15:38
阅读 494·2019-08-23 15:24
阅读 2014·2019-08-23 13:59