通过SO_BINDTODEVICE实现interface绑定

本文介绍如何使用Perl语言设置服务器端程序,使其能够绑定到特定的网卡接口(如eth8),从而不仅可以接收指定IP地址的数据包,还能接收通过该接口传输的所有数据包。通过设置socket选项SO_BINDTODEVICE并指定相应的网络接口名称,可以实现这一需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般服务器端程序会通过socket => bind => listen来监听一个特定的端口,但通常绑定的地址是INADDR_ANY, 这样只要是请求连接到当前主机端口的或者是发送到当前主机端口的数据包都会被接受,当然了,你可以绑定一个特定的ip地址,这样server端只会接受指定IP的数据包,不过有的时候这个也不是你想要的,比如你想让server可以接受指定interface(eth8)的数据包,既接受IP = 172.16.8.87又接受VIP = 172.16.8.187 的数据包(ifconfig eth0 172.16.8.187 netmask 255.255.255.0 broadcast 172.16.8.255 up )。 {perl 实现eth8绑定} # SO_BINDTODEVICE = 25, bind to device eth8 setsockopt($lsock, SOL_SOCKET, 25, pack("Z*","eth8"));
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/if_ether.h> #include <netinet/ether.h> #include <netpacket/packet.h> #define ETH_ARP 0x0806 // ARP协议以太网类型 #define ARP_REQUEST 1 // ARP请求操作码 #define ARP_REPLY 2 // ARP响应操作码 #define BUF_SIZE 1024 // ARP包头结构体 (RFC 826) struct arp_header { uint16_t htype; // 硬件类型 uint16_t ptype; // 协议类型 uint8_t hlen; // 硬件地址长度 uint8_t plen; // 协议地址长度 uint16_t oper; // 操作码 uint8_t sha[6]; // 发送方MAC uint8_t spa[4]; // 发送方IP uint8_t tha[6]; // 目标MAC uint8_t tpa[4]; // 目标IP }; int main(int argc, char *argv[]) { if (argc != 4) { fprintf(stderr, "Usage: %s <bridge_interface> <start_ip> <end_ip>\n", argv[0]); fprintf(stderr, "Example: %s br0 192.168.1.1 192.168.1.254\n"); exit(EXIT_FAILURE); } char *iface = argv[1]; // 桥接接口名,如br0 char *start_ip = argv[2]; // 起始IP char *end_ip = argv[3]; // 结束IP // 创建原始套接字 (AF_PACKET: 链路层访问) int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock < 0) { perror("Socket creation failed"); exit(EXIT_FAILURE); } // 绑定到桥接接口 struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, iface, IFNAMSIZ); if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) { perror("Bind to interface failed"); close(sock); exit(EXIT_FAILURE); } // 构造以太网帧 + ARP请求 uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 广播MAC uint8_t local_mac[6]; struct ifreq mac_req; strncpy(mac_req.ifr_name, iface, IFNAMSIZ); if (ioctl(sock, SIOCGIFHWADDR, &mac_req) < 0) { // 获取本机MAC perror("Get MAC failed"); close(sock); exit(EXIT_FAILURE); } memcpy(local_mac, mac_req.ifr_hwaddr.sa_data, 6); // 发送ARP请求到每个IP struct sockaddr_ll sa; memset(&sa, 0, sizeof(sa)); sa.sll_family = AF_PACKET; sa.sll_ifindex = if_nametoindex(iface); sa.sll_halen = ETH_ALEN; memcpy(sa.sll_addr, broadcast_mac, 6); // 目标MAC=广播 for (uint32_t ip = ntohl(inet_addr(start_ip)); ip <= ntohl(inet_addr(end_ip)); ip++) { uint8_t packet[BUF_SIZE]; struct ethhdr *eth = (struct ethhdr *)packet; struct arp_header *arp = (struct arp_header *)(packet + sizeof(struct ethhdr)); // 填充以太网帧头 memcpy(eth->h_dest, broadcast_mac, 6); memcpy(eth->h_source, local_mac, 6); eth->h_proto = htons(ETH_ARP); // 类型=ARP // 填充ARP包头 arp->htype = htons(1); // 以太网 arp->ptype = htons(ETH_P_IP); // IPv4 arp->hlen = 6; // MAC长度 arp->plen = 4; // IP长度 arp->oper = htons(ARP_REQUEST); // 操作码=请求 memcpy(arp->sha, local_mac, 6); // 发送方MAC(本机) inet_pton(AF_INET, "0.0.0.0", arp->spa); // 发送方IP(通常设为0) memset(arp->tha, 0, 6); // 目标MAC(未知) uint32_t target_ip = htonl(ip); memcpy(arp->tpa, &target_ip, 4); // 目标IP // 发送数据包 if (sendto(sock, packet, sizeof(struct ethhdr) + sizeof(struct arp_header), 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("Send ARP request failed"); } usleep(1000); // 避免洪水攻击,延迟1ms } // 捕获ARP响应 printf("Scanning MAC addresses on %s...\n", iface); printf("IP Address\t\tMAC Address\n"); printf("----------------------------------------\n"); while (1) { uint8_t buffer[BUF_SIZE]; ssize_t len = recvfrom(sock, buffer, BUF_SIZE, 0, NULL, NULL); if (len < 0) { perror("Packet receive error"); break; } // 检查以太网类型是否为ARP struct ethhdr *recv_eth = (struct ethhdr *)buffer; if (ntohs(recv_eth->h_proto) != ETH_ARP) continue; // 解析ARP包头 struct arp_header *recv_arp = (struct arp_header *)(buffer + sizeof(struct ethhdr)); if (ntohs(recv_arp->oper) != ARP_REPLY) continue; // 仅处理响应 // 打印IP和MAC char ip_str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, recv_arp->spa, ip_str, INET_ADDRSTRLEN); printf("%-15s\t\t%02X:%02X:%02X:%02X:%02X:%02X\n", ip_str, recv_arp->sha[0], recv_arp->sha[1], recv_arp->sha[2], recv_arp->sha[3], recv_arp->sha[4], recv_arp->sha[5]); } close(sock); return 0; } 怎么修改
最新发布
08-06
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值