I just run pfsense in a virtualbox on the dual-nic box - in addition to standard router/firewall functions, I can play with enhanced security functions with much ease. Other solutions I have tried include free Sophos UTM-9 software appliance, zeroshell, m0n0wall, endian and family. Manually reimplementing all the functions provided by FOSS router/firewalls would be interesting and exhausting.
--- Supratim Sanyal, W1XMT 39.19151 N, 77.23432 W QCOCAL::SANYAL via HECnet > On Sep 19, 2021, at 2:58 PM, Charlie Turner <chtu...@gmail.com> wrote: > > Hi, > My goal is to have a virtual networking infrastructure, with one dual-NIC > machine acting as a gateway. One of its NICs is connected to the private > LAN, and provides a DHCP service, the other NIC is connected to the > "upstream", and provides Internet service. > > I start by creating a bridge to connect the private NIC of the gateway, > to the virtual clients that will join the network later on, > > ┌──── > │ ip link add name br0 type bridge > │ ip addr add 10.42.0.1/24 dev br0 # this is the network ID of the > =private= interface, inside the host > │ ip link set br0 up > └──── > > To experiment with what works, I did the following > > ┌──── > │ IFACE=br0 > │ dnsmasq --dhcp-match=set:efi-x86_64,option:client-arch,7 > --dhcp-boot=tag:efi-x86_64,syslinux.efi --dhcp-boot=lpxelinux.0 \ > │ --dhcp-range=10.42.0.10,10.42.0.100 --dhcp-script=/bin/echo \ > │ --enable-tftp=$IFACE \ > │ --tftp-root=/mnt/tmp/boots/tftp \ > │ --log-queries=extra --conf-file=/dev/null --interface=$IFACE > └──── > > And then spin up a test machine, connected to the `br0'. It uses the > interface `tap15', which is created like so, > > ┌──── > │ ip tuntap add mode tap tap15 > │ ip link set tap15 up > │ ip link set tap15 master br0 > └──── > > ┌──── > │ qemu-system-x86_64 \ > │ -machine pc-q35-6.0,accel=kvm \ > │ -m 1024 -smp 2,sockets=2,cores=1,threads=1 \ > │ -hda dut_disk0.qcow2 \ > │ -chardev file,id=logfile,path=dut-log-525400112200-193528-19092021.log \ > │ -chardev > socket,id=foo,path=/run/salad_socks/machine0.socket,server=on,wait=off,logfile=dut-log-525400112200-193528-19092021.log > \ > │ -device pci-serial,chardev=foo \ > │ -netdev tap,id=net0,ifname=tap15,script=no,downscript=no \ > │ -device virtio-net-pci,netdev=net0,bootindex=1,mac=52:54:00:11:22:00 \ > │ -vga virtio > └──── > > This works fine. Now, I'd like to go a step further and run the > `dnsmasq' inside a VM, not on my host. It will be listening to the > `private' interface I described above. > > For the host-side of the private NIC interface, I create a tap device, > like before, > > ┌──── > │ ip tuntap add mode tap tap0 > │ ip link set tap0 up > │ ip link set tap0 master br0 > └──── > > With this setup out of the way, I start the dual-NIC gateway machine, > > ┌──── > │ qemu-system-x86_64 \ > │ -hda $DISK_FILE \ > │ -boot c \ > │ -device virtio-net-pci,romfile=,netdev=net0 \ > │ -device virtio-net-pci,romfile=,netdev=net1 \ > │ `# Simulate the plugged in "upstream" cable with user-mode networking` \ > │ -netdev > user,id=net0,hostfwd=tcp::60022-:22,hostfwd=tcp::8080-:80,hostfwd=tcp::8081-:8000,hostfwd=tcp::2375-:2375 > \ > │ `# And now the unplugged one with, with TAP networks` \ > │ -netdev tap,id=net1,ifname=tap0,script=no,downscript=no \ # > this is interface dnsmasq will listen on > │ $BOOT_MODE \ > │ -m 4G \ > │ -display sdl \ > │ -enable-kvm \ > │ -serial stdio > └──── > > This VM has a pre-configured "disk file", that will launch a > dnsmasq server, listening on the net1 interface. > > I try the above experiment again, this time the dnsmasq instance is > listening from within a VM, not on the `br0' interface, but rather, on > `tap0', which is plugged into the bridge, > > ┌──── > │ qemu-system-x86_64 \ > │ -machine pc-q35-6.0,accel=kvm \ > │ -m 1024 -smp 2,sockets=2,cores=1,threads=1 \ > │ -hda dut_disk0.qcow2 \ > │ -chardev file,id=logfile,path=dut-log-525400112200-193528-19092021.log \ > │ -chardev > socket,id=foo,path=/run/salad_socks/machine0.socket,server=on,wait=off,logfile=dut-log-525400112200-193528-19092021.log > \ > │ -device pci-serial,chardev=foo \ > │ -netdev tap,id=net0,ifname=tap15,script=no,downscript=no \ > │ -device virtio-net-pci,netdev=net0,bootindex=1,mac=52:54:00:11:22:00 \ > │ -vga virtio > └──── > > When this machine boots, by monitoring the bridge, I can see the BOOTP > requests on the `br0' interface using `tcpdump', > > ┌──── > │ # tcpdump -i br0 -nN > │ tcpdump: verbose output suppressed, use -v[v]... for full protocol decode > │ listening on br0, link-type EN10MB (Ethernet), snapshot length 262144 bytes > │ 18:47:53.882429 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, > Request from 52:54:00:11:22:01, length 397 > │ 18:47:54.924377 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, > Request from 52:54:00:11:22:01, length 397 > │ 18:47:56.956663 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, > Request from 52:54:00:11:22:01, length 397 > │ 18:48:01.021086 IP 0.0.0.0.68 > 255.255.255.255.67: BOOTP/DHCP, > Request from 52:54:00:11:22:01, length 397 > └──── > > But, nothing responds to it, and so the boot fails. I was expecting that > the `dnsmasq' listening on `tap0', which is also connected to the `br0', > would see these requests, and send a BOOTP response. > > During research, I found that "When you junction interfaces into a > bridge, you no longer use the individual interfaces but the entire > bridge as an interface. You probably need to change your DHCP server to > listen on br0 instead of tap0." <https://superuser.com/a/419612/291744> > > Unfortunately, I can't ask QEMU to assign one of the interfaces to be > `br0', rather than `tap0'. Changing the gateway invocation to, > > ┌──── > │ qemu-system-x86_64 \ > │ -hda $DISK_FILE \ > │ -boot c \ > │ -device virtio-net-pci,romfile=,netdev=net0 \ > │ -device virtio-net-pci,romfile=,netdev=net1 \ > │ `# Simulate the plugged in "upstream" cable with user-mode networking` \ > │ -netdev > user,id=net0,hostfwd=tcp::60022-:22,hostfwd=tcp::8080-:80,hostfwd=tcp::8081-:8000,hostfwd=tcp::2375-:2375 > \ > │ `# And now the unplugged one with, with TAP networks` \ > │ -netdev tap,id=net1,ifname=br0,script=no,downscript=no \ > │ $BOOT_MODE \ > │ -m 4G \ > │ -display sdl \ > │ -enable-kvm \ > │ -serial stdio > └──── > > (Note, `net1''s `ifname' is now specified as `br0', not `tap0') > > This unfortunately fails with > > ┌──── > │ qemu-system-x86_64: -netdev > tap,id=net1,ifname=br0,script=no,downscript=no: could not configure > /dev/net/tun (br0): Invalid argument > └──── > > And I'm stuck at this point, how can I have the gateway's private NIC > respond to DHCP requests on the bridge? > > Thanks for reading! > > B.R. > Charles. >