qemu hostfwd only translates localhost addresses
I want to use the hostfwd feature of qemu. When I access the host port from the machine where qemu is running on using localhost like wget https://localhost:4221
it gets forward to the service running inside qemu like expected. When I do the same with the external IP address of the host system it does not work: wget https://192.168.10.104:4221
.
The port is bound to 0.0.0.0:
[hauke@hauke-p14s ~]$ netstat -tuplen |grep 4221
tcp 0 0 0.0.0.0:4221 0.0.0.0:* LISTEN 1000 5185538 1719168/qemu-system
I started qemu like this:
$ LD_LIBRARY_PATH=/home/hauke/linux/libslirp/build /home/hauke/linux/qemu/build/qemu-bundle/usr/local/bin/qemu-system-mips -machine malta -cpu 24Kc -nographic -kernel bin/targets/malta/be/openwrt-malta-be-vmlinux-initramfs.elf --netdev user,id=lan,net=192.168.1.1/24,restrict=yes,hostfwd=tcp::4221-192.168.1.1:443 --netdev user,id=wan -net nic,netdev=lan -net nic,netdev=wan
This is used today`s master of libslirp and qemu.
libslirp gets configured like this by qemu:
vnetwork: '192.168.1.0'
vnetmask: '255.255.255.0'
vhost: '192.168.1.2'
vdhcp_start: '192.168.1.15'
This is the network configuration of the OpenWrt running in the qemu VM:
root@OpenWrt:/# ip addr show br-lan
5: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 52:54:00:12:34:56 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.1/24 brd 192.168.1.255 scope global br-lan
valid_lft forever preferred_lft forever
inet6 fdf2:b01b:f8ea::1/60 scope global noprefixroute
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe12:3456/64 scope link
valid_lft forever preferred_lft forever
192.168.10.104 is one of the IP addresses of the host machine.
When I run wget https://192.168.10.104:4221
on the host it does not work. The tcpdump looks like this:
root@OpenWrt:/# tcpdump -i br-lan
.....
15:03:02.739757 ARP, Request who-has 192.168.1.1 tell 192.168.1.2, length 46
15:03:02.740452 ARP, Reply 192.168.1.1 is-at 52:54:00:12:34:56 (oui Unknown), length 28
15:03:02.740816 IP 192.168.10.104.40134 > 192.168.1.1.443: Flags [S], seq 3584001, win 65535, options [mss 1460], length 0
15:03:08.238180 IP 192.168.10.104.40134 > 192.168.1.1.443: Flags [S], seq 3584001, win 65535, options [mss 1460], length 0
The system uses the wrong source IP address. 192.168.10.104 is not part of the network 192.168.1.1/24 and Linux ignores it.
When I use wget https://127.0.0.1:4221
on the host it works:
root@OpenWrt:/# tcpdump -i br-lan
.....
15:03:41.661057 IP 192.168.1.2.56216 > 192.168.1.1.443: Flags [S], seq 8640001, win 65535, options [mss 1460], length 0
15:03:41.661555 IP 192.168.1.1.443 > 192.168.1.2.56216: Flags [S.], seq 972274957, ack 8640002, win 64240, options [mss 1460], length 0
15:03:41.661730 IP 192.168.1.2.56216 > 192.168.1.1.443: Flags [.], ack 1, win 65535, length 0
15:03:41.664779 IP 192.168.1.2.56216 > 192.168.1.1.443: Flags [P.], seq 1:518, ack 1, win 65535, length 517
15:03:41.665920 IP 192.168.1.1.443 > 192.168.1.2.56216: Flags [.], ack 518, win 63784, length 0
15:03:41.699275 IP 192.168.1.1.443 > 192.168.1.2.56216: Flags [P.], seq 1:161, ack 518, win 63784, length 160
....
libslirp translates the source address to the host address. The TCP connection works like expected.
When I do this change to libslirp it works for me with the 192.168.10.104 address too.
--- a/src/socket.c
+++ b/src/socket.c
@@ -1075,6 +1075,7 @@ void sotranslate_accept(struct socket *so)
(loopback_addr.s_addr & loopback_mask)) {
so->so_faddr = slirp->vhost_addr;
}
+ so->so_faddr = slirp->vhost_addr;
break;
case AF_INET6:
With this change the tcpdump for wget https://192.168.10.104:4221
looks like this inside of qemu:
15:12:57.051061 ARP, Request who-has 192.168.1.1 tell 192.168.1.2, length 46
15:12:57.051699 ARP, Reply 192.168.1.1 is-at 52:54:00:12:34:56 (oui Unknown), length 28
15:12:57.052470 IP 192.168.1.2.42564 > 192.168.1.1.443: Flags [S], seq 4736001, win 65535, options [mss 1460], length 0
15:12:57.055161 IP 192.168.1.1.443 > 192.168.1.2.42564: Flags [S.], seq 975635372, ack 4736002, win 64240, options [mss 1460], length 0
15:12:57.055384 IP 192.168.1.2.42564 > 192.168.1.1.443: Flags [.], ack 1, win 65535, length 0
15:12:57.058005 IP 192.168.1.2.42564 > 192.168.1.1.443: Flags [P.], seq 1:518, ack 1, win 65535, length 517
15:12:57.059185 IP 192.168.1.1.443 > 192.168.1.2.42564: Flags [.], ack 518, win 63784, length 0
15:12:57.112207 IP 192.168.1.1.443 > 192.168.1.2.42564: Flags [P.], seq 1:161, ack 518, win 63784, length 160
....
This change looks strange to me. If this is a reasonable change I can create a PR, the if condition before it is not needed any more.