[英]Receiving AF_PACKET multicast on a Linux network interface
我正在 Linux 上實現非標准/未發布的以太網協議。 以太網幀的 EtherType 0x5eeb
並被多播到77:68:76:68:76:69
。
我正在努力編寫一個簡單的程序,該程序可以在綁定到單個接口時接收這些幀。 我現在用幾種語言嘗試過這個; 這是 C 版本:
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
const unsigned short eth_type = 0x5eeb;
int main() {
/* Open a socket */
int fd = socket(AF_PACKET, SOCK_RAW, htons(eth_type));
if (fd < 0) {
perror("socket");
exit(1);
}
/* Find out the interface index number */
struct ifreq ifr;
const char * if_name = "eth0";
size_t if_name_len = strlen (if_name);
memcpy(ifr.ifr_name, if_name, if_name_len);
ioctl(fd, SIOCGIFINDEX, &ifr);
printf("Interface has index %d\n", ifr.ifr_ifindex);
/* Add the interface to the multicast group */
char mcast[] = {0x77, 0x68, 0x76, 0x68, 0x76, 0x69, 0, 0};
struct packet_mreq mreq = {0};
mreq.mr_ifindex = ifr.ifr_ifindex;
mreq.mr_type = PACKET_MR_MULTICAST;
memcpy(mreq.mr_address, mcast, 8);
mreq.mr_alen = 6;
if(setsockopt(fd, SOL_SOCKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
perror("setsockopt");
exit(1);
}
/* Bind to the interface */
struct sockaddr_ll addr = {0};
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifr.ifr_ifindex;
addr.sll_protocol = htons(eth_type); // Defaults to the socket protocol anyway
addr.sll_pkttype = PACKET_MULTICAST;
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("bind");
exit(1);
}
/* Receive a frame and output some details */
char buf [2048];
struct sockaddr_ll src_addr;
socklen_t src_addr_len = sizeof(src_addr);
ssize_t count = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&src_addr, &src_addr_len);
if (count == -1) {
perror("recvfrom");
exit(1);
} else {
printf("Received frame.\n");
printf("Dest MAC: ");
for (int ii = 0; ii < 5; ii++) {
printf("%02hhx:", buf[ii]);
}
printf("%02hhx\n", buf[5]);
printf("Src MAC: ");
for (int ii = 6; ii < 11; ii++) {
printf("%02hhx:", buf[ii]);
}
printf("%02hhx\n", buf[11]);
}
}
如果我刪除標題為Bind to the interface
的部分,那么我會收到幀,我只是從系統上的每個接口接收它們,而不僅僅是我嘗試收聽的接口。 如果我將使用eth_type
的任何地方更改為ETH_P_ALL
,那么我會得到所有到達綁定接口的幀,而不僅僅是帶有我的 EtherType 的幀(就此而言,不僅僅是多播幀; bind
似乎不尊重PACKET_MULTICAST
在這種情況下)。
有什么方法可以讓bind
和特定的 EtherTypes 很好地結合在一起嗎?
我在 Linux 5.11 和 4.9 上試過這個。 如果有人想做一些測試,這里有一個簡短的 Python 3 程序,它會吐出幀。 您需要pyroute2
package。
import socket
from pyroute2 import IPDB
import sys
import struct
import binascii
import time
ip = IPDB()
SMAC=bytes.fromhex(ip.interfaces[sys.argv[1]]['address'].replace(':', ''))
DMAC=bytes.fromhex('776876687669')
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW)
s.bind((sys.argv[1], 0x5eeb))
#s.bind((sys.argv[1], 0))
dgram = struct.pack("!6s6sHH", DMAC, SMAC, 0x5eeb, 0x7668)
print(' '.join('{:02x}'.format(x) for x in dgram))
while True:
s.send(dgram)
time.sleep(0.1)
這里的問題實際上是PACKET_ADD_MULTICAST
套接字選項,它是一個SOL_PACKET
選項,而不是像我嘗試的SOL_SOCKET
選項。 我不完全確定SOL_SOCKET
+ PACKET_ADD_MEMBERSHIP
做了什么,但無論它是什么,它都不會返回錯誤並且會破壞事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.