我正在尝试在QEMU中创建一个到主机接口的网桥,很像Virtualbox和VMWare的网桥适配器,使用套接字网络和一个名为Scapy的Python库的组合(基本上,在幕后依赖Windows操作系统上的WinPcap/Npcap或Unix操作系统上的libpcap)。下面是我创建的桥接脚本,用于将QEMU的socket
网络后端创建的VLAN连接到外部接口:
import argparse
import scapy
import threading
import socket
import struct
import scapy.sendrecv
import scapy.packet
import scapy.config
import scapy.layers.l2
MAX_PACKET_SIZE = 65535
send_lock = threading.Lock()
qemu_senders = set()
iface_senders = set()
def qemu_in_iface_out_traffic_thread_func(iface, mcast_addr, mcast_port, local_addr):
global MAX_PACKET_SIZE
global send_lock
global qemu_senders
global iface_senders
# Create the multicast listen socket.
listener_addr = (local_addr, mcast_port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(listener_addr)
mcast_group = socket.inet_aton(mcast_addr)
mreq = struct.pack('4sL', mcast_group, socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Get the packets from the QEMU VLAN, and send them over to the host's interface.
while True:
data, _ = sock.recvfrom(MAX_PACKET_SIZE)
send_lock.acquire()
eth_pkt = scapy.layers.l2.Ether(data)
if eth_pkt.src not in iface_senders:
qemu_senders.add(eth_pkt.src)
scapy.sendrecv.sendp(eth_pkt, iface=iface, verbose=0)
send_lock.release()
def iface_in_qemu_out_traffic_thread_func(iface, mcast_addr, mcast_port):
global send_lock
global qemu_senders
global iface_senders
# Create the multicast send socket.
mcast_group = (mcast_addr, mcast_port)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
# Sniff packets from the host's interface, and send them to the QEMU VLAN.
def process_packet(eth_pkt):
send_lock.acquire()
if eth_pkt.src not in qemu_senders:
iface_senders.add(eth_pkt.src)
sock.sendto(scapy.packet.Raw(eth_pkt).load, mcast_group)
send_lock.release()
scapy.sendrecv.sniff(iface=iface, prn=process_packet, store=0)
if __name__ == "__main__":
# Parse the command line arguments.
parser = argparse.ArgumentParser()
parser.add_argument('--iface', '-i', required=True)
parser.add_argument('--mcast-addr', '-a', required=True)
parser.add_argument('--mcast-port', '-p', required=True, type=int)
parser.add_argument('--local-addr', '-l', default='127.0.0.1')
parser.add_argument('--disable-promisc', '-d',
default=False, action='store_true')
args = parser.parse_args()
# Set promiscuous mode.
scapy.config.conf.sniff_promisc = 0 if args.disable_promisc else 1
# Create the traffic threads.
qemu_in_iface_out_traffic_thread = \
threading.Thread(target=qemu_in_iface_out_traffic_thread_func, args=(
args.iface, args.mcast_addr, args.mcast_port, args.local_addr
))
iface_in_qemu_out_traffic_thread = \
threading.Thread(target=iface_in_qemu_out_traffic_thread_func, args=(
args.iface, args.mcast_addr, args.mcast_port
))
# Run the traffic threads, and join them to wait for their exit.
qemu_in_iface_out_traffic_thread.start()
iface_in_qemu_out_traffic_thread.start()
qemu_in_iface_out_traffic_thread.join()
iface_in_qemu_out_traffic_thread.join()
有了这个桥接源代码,我能够在我的主机之外的设备(例如Raspberry Pi控制器)和我的QEMU VM之间来回ping
,我的控制器和主机都位于同一个LAN上。但是,我无法在同一网络上的QEMU VM和主机之间执行相同的操作。我想知道问题是否与两个不同的MAC地址(即我的QEMU VM的MAC地址和我的主机的MAC地址)具有相同的接口(连接到LAN的主机接口)以及到同一LAN的流量被过滤掉有关,或者我在这里遗漏了什么
编辑#1:
因此,我检查了QEMU VM或我的主机在网络上发送/接收的数据包,它们在网络上的所有设备上都被接收。我已将一个路由器连接到我的网络,并将另一台带有Wi-Fi和Wireshark的笔记本电脑设备通过路由器连接到网络。我可以看到在网络的所有端接收到的数据包(例如,在网络上的新笔记本电脑上),但我的主机不响应ARP数据包,例如,由同一接口上的另一台机器(如QEMU VM)发起的数据包
以下是分别从主机和网络上的新笔记本电脑上截取的Wireshark屏幕截图:
从上面截图中可以看出,我的主机之外的任何设备(192.168.1.1的路由器、Rasberry Pi控制器和其他笔记本电脑)都可以与我的QEMU VM对话并回复ARP请求(同样,QEMU VM也可以),但主机不能
以下是我所看到的观察结果(为这张糟糕的画道歉):
但是,如果我用Virtualbox虚拟机替换QEMU虚拟机,主机和Virtualbox虚拟机之间就会有连接。此外,QEMU虚拟机也不能与主机内的任何机器进行对话,例如QEMU虚拟机和Virtualbox虚拟机之间的对话,两者都通过主机接口连接到同一LAN
编辑#2:
我观察到的另一件事是,当从VirtualBox虚拟机ARP我的主机时,我不会在Wireshark的同一界面上看到主机对虚拟机的ARP回复(就像上面的症状一样)。我认为VirtualBox的NetFilter主机驱动程序负责创建网桥,它创建了另一个网络,主机和虚拟机的请求和响应在该网络中交换,而主机和虚拟机在真实界面上与外部世界通信。显然,我需要创建自己的主机驱动程序,将数据包注入从QEMU VM通过网桥发送的接收流中
目前没有回答
相关问题 更多 >
编程相关推荐