packet socket指定接收ARP协议,当接口放入桥中时,接收不到ARP数据包。
1 2 3 4 5 6 7 8 9 10 11 | struct sockaddr_ll sll; int sock; sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP)); memset (&sll, 0, sizeof (sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ARP); bind(sock, ( struct sockaddr *) &sll, sizeof (sll)); |
解决办法是使用ETH_P_ALL,并添加内核filter。注意ETH_P_ALL也会接收TX的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | struct sockaddr_ll sll; int sock; sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); memset (&sll, 0, sizeof (sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifindex; sll.sll_protocol = htons(ETH_P_ARP); bind(sock, ( struct sockaddr *) &sll, sizeof (sll)); struct sock_filter arpfilter[] = { BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), /* Skip 12 bytes */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_P_ARP, 0, 1), /* if eth type != ARP skip next instr. */ BPF_STMT(BPF_RET+BPF_K, sizeof ( struct arpMsg)), BPF_STMT(BPF_RET+BPF_K, 0), /* Return, either the ARP packet or nil */ }; struct sock_fprog fprog; fprog.filter = arpfilter; fprog.len = sizeof (arpfilter)/ sizeof ( struct sock_filter); setsockopt(mysock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof (fprog)); |
可以使用filter来实现不接收tx数据,recvfrom返回的地址,也可判断是否为TX数据包:
1 2 3 4 5 6 7 8 | struct sockaddr_ll addr; struct arpMsg arp; int addr_len = sizeof (addr); int err = recvfrom(sock, &arp, sizeof (arp), MSG_TRUNC, &addr, &addr_len); if (addr.sll_pkttype == PACKET_OUTGOING) printf ( "outgoing packet\n" ); |
参考:
https://stackoverflow.com/questions/16543191/missing-arp-packets-in-sock-raw-socket