赞
踩
目录
ARP(Address Resolution Protocol)协议是一种在局域网中解析MAC地址的协议。
当主机要向局域网中的另一台主机发送数据时,需要知道目标主机的MAC地址。ARP协议就是用来解析目标主机的MAC地址的。主机会广播一个ARP请求包,请求目标主机回应自己的MAC地址。目标主机接收到请求后会返回一个ARP响应包,包括自己的MAC地址。这样,请求主机就可以通过MAC地址向目标主机发送数据了。
图 1 ARP工作原理
局域网主机A和主机B通信,如果双方原来没有通信过,主机A只知道主机B的IP地址,不知道主机B的MAC地址,此时主机A和主机B无法正常通信。
局域网通信的基础通信双方都得知道对方的MAC地址,MAC地址通常是存储在主机的ARP表中。
此时主机A会尝试去获取主机B的MAC地址,获取的MAC地址的方式是发送ARP请求(以广播形式发送),主机B如果收到ARP请求会回复ARP响应给主机A。
主机A收到响应后会把主机B的IP和MAC地址记录在ARP表中,此时主机A能够发送数据给主机B,主机B因为收到主机A的ARP请求,通过ARP请求知道主机A的MAC地址,把主机A的IP和MAC地址记录在ARP表中,主机B也能给主机A发送数据,正阳主机A和主机B就能正常通信。
主机A要访问一个公网主机,由于主机A和公网主机IP地址不再同一网段,此时需要用到路由功能,路由功能后续章节会详细介绍。
我们只要记住一个核心点,路由功能核心作用就是找到去往目的IP的网关IP地址。
网关IP地址必须和主机A处于同一局域网。找到网关IP地址的目的是为了获取网关MAC地址,获取到网关MAC地址,可以通过网关MAC地址把数据包发送给网关,让网关转发数据包至公网。
如果通过网关IP获取到网关MAC地址可以参考局域网通信。
跨网段通信流程:
步骤1:通过路由查找到网关IP地址
步骤2:如果不知道网关MAC地址,需要通过ARP协议获取到网关MAC地址。
步骤3:把网关MAC地址填入以太网报文头部,将数据包发给网关。
步骤4:网关转发数据包至公网。
图 2 ARP报文结构
图 3 ARP请求报文
ARP请求各个字段如何填充如上图:
硬件类型:1,ARPHRD_ETHER类型
协议类型:0x8000,IPv4协议
硬件地址长度:6字节,MAC地址长度
协议地址长度:4字节,IP地址长度
操作码:1,ARP请求码
发送方MAC地址:14:23:0a:39:e3:75
发送方IP地址:192.168.1.1
目的MAC地址:00:00:00:00:00:00
目的IP地址:192.168.1.19
图 4 ARP响应报文
ARP响应各个字段如何填充如上图:
硬件类型:1,ARPHRD_ETHER类型
协议类型:0x8000,IPv4协议
硬件地址长度:6字节,MAC地址长度
协议地址长度:4字节,IP地址长度
操作码:2,ARP响应
发送方MAC地址:00:93:37:5b:d9:2f
发送方IP地址:192.168.1.19
目的MAC地址:14:23:0a:39:e3:75
目的IP地址:192.168.1.1
图 5 ARP攻击
ARP攻击(Address Resolution Protocol attack)是一种网络攻击方式,它利用ARP协议进行攻击,通过伪造或欺骗网络中的ARP响应包,将合法网络设备的IP地址映射到攻击者所控制的设备上,从而使攻击者可以窃取或篡改网络中的数据流量。
ARP攻击可以分为两种类型,一种是ARP欺骗(ARP Spoofing),另一种是ARP投毒(ARP Poisoning)。
攻击者会向网络中的设备发送伪造的ARP响应包,使其将攻击者所控制的设备的MAC地址当作目标设备的MAC地址,从而使攻击者可以拦截、篡改或窃取网络中的数据流量。
攻击者会向网络中的设备发送大量的伪造ARP响应包,从而使网络设备的ARP缓存被攻击者所控制的设备所替换,这样一来,攻击者就可以直接访问目标设备,而无需再进行ARP欺骗攻击。
a.使用静态ARP表:将网络设备的IP地址和MAC地址的映射关系手动输入到静态ARP表中,可以防止攻击者篡改ARP响应包。
b.使用端口安全(Port Security):在交换机上配置端口安全,限制每个端口能够连接的MAC地址数量,可以有效地防止ARP攻击。
c.使用ARP防火墙(ARP Firewall):ARP防火墙可以监控网络流量中的ARP请求和响应包,并根据预设的规则进行过滤和阻断,从而有效地防止ARP攻击。
d.加密网络流量:使用加密技术(如SSL、TLS等)对网络流量进行加密,可以防止数据被窃听和篡改,从而有效地保护网络安全。
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/udp.h>
- #include <netinet/ip.h>
- #include <linux/in.h>
- #include <arpa/inet.h>
- #include <linux/if_packet.h>
- #include <linux/if_ether.h>
- #include <linux/if_arp.h>
-
- uint8_t src_mac[ETH_ALEN] = {0x08,0x00,0x27,0x06,0x38,0xba};
- uint8_t nexthop_mac[ETH_ALEN] = {0x08,0x00,0x27,0xc1,0xdf,0xea};
-
- #define LOCAL_IP "192.168.1.18"
- #define PEER_IP "192.168.1.19"
-
- #define MAX_BUF_SIZE (2048)
- #define IP_ADDR_LEN (4)
-
- struct _arphdr {
- __be16 ar_hrd;
- __be16 ar_pro;
- unsigned char ar_hln;
- unsigned char ar_pln;
- __be16 ar_op;
-
- unsigned char ar_sha[ETH_ALEN];
- unsigned char ar_sip[4];
- unsigned char ar_tha[ETH_ALEN];
- unsigned char ar_tip[4];
- };
-
- uint32_t create_pack(char *buf) {
- struct ethhdr *eh = (struct ethhdr *)buf;
- memcpy(eh->h_dest, nexthop_mac, ETH_ALEN);
- memcpy(eh->h_source, src_mac, ETH_ALEN);
- eh->h_proto = htons(ETH_P_ARP);
-
- struct _arphdr *ah = (struct _arphdr *)(buf + ETH_HLEN);
- ah->ar_hrd = htons(ARPHRD_ETHER);
- ah->ar_pro = htons(ETH_P_IP);
- ah->ar_hln = ETH_ALEN;
- ah->ar_pln = IP_ADDR_LEN;
- ah->ar_op = htons(ARPOP_REQUEST);
-
- memcpy(ah->ar_sha, src_mac, ETH_ALEN);
- uint32_t src_ip = inet_addr(LOCAL_IP);
- memcpy(ah->ar_sip, &src_ip, IP_ADDR_LEN);
-
- memcpy(ah->ar_tha, nexthop_mac, ETH_ALEN);
- uint32_t peer_ip = inet_addr(PEER_IP);
- memcpy(ah->ar_tip, &peer_ip, IP_ADDR_LEN);
-
- return ETH_HLEN + sizeof(struct _arphdr);
- }
-
- int main(int argc , char *argv[]) {
- int ret;
- int sockfd;
- char send_buf[MAX_BUF_SIZE] = {0};
- struct sockaddr_ll local;
- struct sockaddr_ll peer;
-
- sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
- if (sockfd == -1) {
- perror("socket error");
- return -1;
- }
-
- bzero(&peer, sizeof(struct sockaddr_ll));
- peer.sll_family = PF_PACKET;
- peer.sll_protocol = htons(ETH_P_ARP);
- peer.sll_ifindex = 2;
- peer.sll_hatype = ARPHRD_ETHER;
- peer.sll_pkttype = PACKET_OTHERHOST;
- peer.sll_halen = ETH_ALEN;
- memcpy(peer.sll_addr, nexthop_mac, ETH_ALEN);
-
- uint32_t slen = create_pack(send_buf);
-
- while(1) {
- ret = sendto(sockfd, send_buf, slen, 0, (struct sockaddr *)&peer, sizeof(peer));
- if (ret <= 0) {
- printf("sendto ret:%d, errno:%d(%s)\n", ret, errno, strerror(errno));
- break;
- }
-
- sleep(1);
- }
-
- close(sockfd);
-
- return 0;
- }
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <linux/in.h>
- #include <linux/if_packet.h>
- #include <linux/if_ether.h>
- #include <linux/if_arp.h>
-
- uint8_t src_mac[ETH_ALEN] = {0x08,0x00,0x27,0xc1,0xdf,0xea};
- uint8_t nexthop_mac[ETH_ALEN] = {0x08,0x00,0x27,0x06,0x38,0xba};
- #define LOCAL_IP "192.168.1.19"
- #define PEER_IP "192.168.1.18"
-
- #define IP_ADDR_LEN (4)
- #define MAX_BUF_SIZE (2048)
-
- struct _arphdr {
- __be16 ar_hrd;
- __be16 ar_pro;
- unsigned char ar_hln;
- unsigned char ar_pln;
- __be16 ar_op;
-
- unsigned char ar_sha[ETH_ALEN];
- unsigned char ar_sip[4];
- unsigned char ar_tha[ETH_ALEN];
- unsigned char ar_tip[4];
- };
-
- void print_arp(char *msg, const char *buf) {
- struct _arphdr *ah = (struct _arphdr *)(buf + ETH_HLEN);
- printf("%s\n"
- "硬件类型:%u\n"
- "协议类型:%u\n"
- "硬件地址长度:%u\n"
- "协议地址长度:%u\n"
- "操作码:%u\n"
- "发送方硬件地址:%02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n"
- "发送方协议地址:%02hx.%02hx.%02hx.%02hx\n"
- "接收方硬件地址:%02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n"
- "接收方协议地址:%02hx.%02hx.%02hx.%02hx\n",
- msg,
- ntohs(ah->ar_hrd),
- ntohs(ah->ar_pro),
- ah->ar_hln,
- ah->ar_pln,
- ntohs(ah->ar_op),
- ah->ar_sha[0], ah->ar_sha[1], ah->ar_sha[2], ah->ar_sha[3], ah->ar_sha[4], ah->ar_sha[5],
- ah->ar_sip[0], ah->ar_sip[1], ah->ar_sip[2], ah->ar_sip[3],
- ah->ar_tha[0], ah->ar_tha[1], ah->ar_tha[2], ah->ar_tha[3], ah->ar_tha[4], ah->ar_tha[5],
- ah->ar_tip[0], ah->ar_tip[1], ah->ar_tip[2], ah->ar_tip[3]);
- }
-
- int parse_pack(char *msg, char *buf) {
- print_arp(msg, buf);
- return 0;
- }
-
- uint32_t create_pack(char *sbuf, char *rbuf) {
- struct ethhdr *eh = (struct ethhdr *)sbuf;
- memcpy(eh->h_dest, nexthop_mac, ETH_ALEN);
- memcpy(eh->h_source, src_mac, ETH_ALEN);
- eh->h_proto = htons(ETH_P_ARP);
-
- struct _arphdr *rah = (struct _arphdr *)(rbuf + ETH_HLEN);
- struct _arphdr *ah = (struct _arphdr *)(sbuf + ETH_HLEN);
- ah->ar_hrd = htons(ARPHRD_ETHER);
- ah->ar_pro = htons(ETH_P_IP);
- ah->ar_hln = ETH_ALEN;
- ah->ar_pln = IP_ADDR_LEN;
- ah->ar_op = htons(ARPOP_REPLY);
-
- memcpy(ah->ar_sha, src_mac, ETH_ALEN);
- uint32_t src_ip = inet_addr(LOCAL_IP);
- memcpy(ah->ar_sip, &src_ip, IP_ADDR_LEN);
- memcpy(ah->ar_tha, rah->ar_sha, ETH_ALEN);
- memcpy(ah->ar_tip, rah->ar_sip, IP_ADDR_LEN);
-
- return ETH_HLEN + sizeof(struct _arphdr);
- }
-
- bool isvalid(const char *buf) {
- struct ethhdr *eh = (struct ethhdr *)buf;
- if (ntohs(eh->h_proto) == ETH_P_ARP) return true;
- return false;
- }
-
- int main(int argc , char *argv[]) {
- int ret;
- int sockfd;
- char send_buf[MAX_BUF_SIZE] = {0};
- char recv_buf[MAX_BUF_SIZE] = {0};
- struct sockaddr_ll peer;
- socklen_t peerlen = 0;
-
- sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
- if (sockfd == -1) {
- perror("socket error");
- return -1;
- }
-
- bzero(&peer, sizeof(struct sockaddr_ll));
- peer.sll_family = PF_PACKET;
- peer.sll_protocol = htons(ETH_P_ARP);
- peer.sll_ifindex = 2;
- peer.sll_hatype = ARPHRD_ETHER;
- peer.sll_pkttype = PACKET_OTHERHOST;
- peer.sll_halen = ETH_ALEN;
- memcpy(peer.sll_addr, nexthop_mac, ETH_ALEN);
-
- while(1) {
- memset(recv_buf, 0, MAX_BUF_SIZE);
- ret = recvfrom(sockfd, recv_buf, MAX_BUF_SIZE, 0, NULL, NULL);
- if (ret <= 0) {
- printf("recvfrom ret:%d error\n", ret);
- break;
- } else {
- bool bret = isvalid(recv_buf);
- printf("ret:%d, bret:%d\n", ret, bret);
- if (bret == false) {
- continue;
- }
- parse_pack("recv buf", recv_buf);
-
- memset(send_buf, 0, MAX_BUF_SIZE);
- int slen = create_pack(send_buf, recv_buf);
- slen += 18;
- printf("sendbuf len:%d\n", slen);
- ret = sendto(sockfd, send_buf, slen, 0, (struct sockaddr *)&peer, sizeof(peer));
- if (ret <= 0) {
- printf("sendto ret:%d error:%d(%s)\n", ret, errno, strerror(errno));
- break;
- }
- }
- }
-
- close(sockfd);
-
- return 0;
- }
ip neigh
ip neigh add 192.168.1.19 dev enp0s3 lladdr 08:00:27:c1:df:ea
ip neigh del 192.168.1.19 dev enp0s3 lladdr 08:00:27:c1:df:ea
如果觉得本文对你有帮助,希望给个一键三连,支持博主,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。