Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Failed to convert source address to presentation format" when using a specified interface that has both IPv4 and IPv6 addresses #2206

Closed
empovit opened this issue Dec 16, 2020 · 4 comments
Assignees
Labels

Comments

@empovit
Copy link

@empovit empovit commented Dec 16, 2020

Describe the bug
When I try to discover hosts that are not reachable from a specific interface, and the interface has both IPv4 and IPv6 addresses, nmap fails with:

Failed to convert source address to presentation format!?!  Error: Address family not supported by protocol
QUITTING!

Moreover, if the argument is a list of IP addresses (some of them reachable), none of those hosts will be discovered because of the error.

To Reproduce
I'm including a script that reproduces the behavior with Docker CE (20.10.0 on Fedora 32 in my case).

Important: Make sure Docker assigns IPv4 addresses to the interfaces.

#!/bin/bash

DOCKER_IMAGE=docker.io/instrumentisto/nmap

echo ">>> Create two IPv6 networks"
docker network create --ipv6 --subnet 2001:db8::/120 ipv6-net-1
docker network create --ipv6 --subnet fe80:5054::/120 ipv6-net-2

echo
echo ">>> Run container #1 attached to the networks so it has two NICs"
CONTAINER_1=`docker run -d --entrypoint sleep --net ipv6-net-1 $DOCKER_IMAGE 600`
docker network connect ipv6-net-2 $CONTAINER_1
docker exec -ti $CONTAINER_1 ip a

echo
echo ">>> Run container #2 attached to the networks"
CONTAINER_2=`docker run -d --entrypoint sleep --net ipv6-net-1 $DOCKER_IMAGE 600`
docker network connect ipv6-net-2 $CONTAINER_2
docker exec -ti $CONTAINER_2 ip a

echo
echo ">>> Run NMAP from eth0 to the two addresses of container #1"
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth0 2001:db8::2 fe80:5054::2

echo
echo ">>> Run NMAP from eth1 to the two addresses of container #1"
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth1 2001:db8::2 fe80:5054::2

echo
echo ">>> Now run NMAP from eth0 and then eth1, but for each address individually"
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth0 2001:db8::2
echo
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth0 fe80:5054::2
echo
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth1 2001:db8::2
echo
docker exec -ti $CONTAINER_2 nmap -6 -sn -n -e eth1 fe80:5054::2

echo
echo ">>> Cleanup"
docker kill $CONTAINER_1 $CONTAINER_2
docker rm $CONTAINER_1 $CONTAINER_2
docker network rm ipv6-net-1 ipv6-net-2

Expected behavior
A standard message saying that the host is down, or at least some hosts discovered in case of multiple IP addresses.

Version info (please complete the following information):

  • OS: Alpine Linux v3.12 (containerized)
  • Output of nmap --version:
Nmap version 7.91 ( https://nmap.org )
Platform: x86_64-unknown-linux-gnu
Compiled with: nmap-liblua-5.3.5 openssl-3.1.2 nmap-libssh2-1.9.0 nmap-libz-1.2.11 nmap-libpcre-7.6 libpcap-1.9.1 nmap-libdnet-1.12 ipv6
Compiled without:
Available nsock engines: epoll poll select
  • Output of nmap --iflist
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-16 16:43 UTC
************************INTERFACES************************
DEV  (SHORT) IP/MASK                 TYPE     UP MTU   MAC
lo   (lo)    127.0.0.1/8             loopback up 65536
lo   (lo)    ::1/128                 loopback up 65536
eth0 (eth0)  172.22.0.3/16           ethernet up 1500  02:42:AC:16:00:03
eth0 (eth0)  2001:db8::3/120         ethernet up 1500  02:42:AC:16:00:03
eth0 (eth0)  fe80::42:acff:fe16:3/64 ethernet up 1500  02:42:AC:16:00:03
eth1 (eth1)  172.23.0.3/16           ethernet up 1500  02:42:AC:17:00:03
eth1 (eth1)  fe80::42:acff:fe17:3/64 ethernet up 1500  02:42:AC:17:00:03
eth1 (eth1)  fe80:5054::3/120        ethernet up 1500  02:42:AC:17:00:03

**************************ROUTES**************************
DST/MASK         DEV  METRIC GATEWAY
172.23.0.0/16    eth1 0
172.22.0.0/16    eth0 0
0.0.0.0/0        eth0 0      172.22.0.1
fe80:5054::3/128 eth1 0
::1/128          lo   0
2001:db8::3/128  eth0 0
2001:db8::/120   eth0 256
fe80:5054::/120  eth1 256
fe80::/64        eth0 256
fe80::/64        eth1 256
ff00::/8         eth0 256
ff00::/8         eth1 256
::/0             eth0 1024   2001:db8::1

Additional context
I observed this problem with a variety of OSs (containers) and nmap versions.

@empovit empovit added the Nmap label Dec 16, 2020
@nnposter
Copy link

@nnposter nnposter commented Dec 21, 2020

If you are in a position to compile Nmap then you could try this patch as a quick fix:

--- a/libnetutil/netutil.cc	2020-11-25 19:23:26.400705564 -0700
+++ b/libnetutil/netutil.cc	2020-12-20 22:56:08.182980811 -0700
@@ -3163,7 +3163,7 @@
   len -= NLMSG_LENGTH(sizeof(*nlmsg));
 
   /* See rtnetlink(7). Anything matching this route is actually unroutable. */
-  if (rtmsg->rtm_type == RTN_UNREACHABLE)
+  if (rtmsg->rtm_type == RTN_UNREACHABLE || rtmsg->rtm_type == RTN_UNSPEC)
     return 0;
 
   /* Default values to be possibly overridden. */
@nnposter
Copy link

@nnposter nnposter commented Dec 21, 2020

What appears to be going on is that in function route_dst_netlink, the final determination whether there is a good route for a given destination is implemented as a test whether interface info got populated:

if (ii != NULL) {

This rationale seems generally valid but it fails when the interface is determined upfront, via -e. In this case the interface info gets populated early:
ii = getInterfaceByName(device, dst->ss_family);

instead of by parsing a route attribute:
ii = getInterfaceByName(namebuf, dst->ss_family);

Incorrect value of 1 is returned to function setup_target, which then proceeds with setting up the target, finally trying to convert the source IP address to a string via inet_ntop:

nmap/Target.cc

Line 187 in cd63da6

if (inet_ntop(sin->sin_family, (sin->sin_family == AF_INET)?

This conversion fails because the requested family is AF_INET6, while the content of struct sockaddr_storage is AF_UNSPEC (because it did not get populated by route_dst_netlink).

The fix presented earlier avoids the issue by exiting early on RTN_UNSPEC. There are likely other route types that should be treated the same, such as RTN_BLACKHOLE or RTN_PROHIBIT.

@nnposter nnposter added the bug label Dec 28, 2020
@nnposter nnposter self-assigned this Dec 28, 2020
@nnposter
Copy link

@nnposter nnposter commented Dec 28, 2020

The patch above, with additional route types RTN_BLACKHOLE and RTN_PROHIBIT, will be committed on/after January 15 unless concerns are raised.

@nnposter
Copy link

@nnposter nnposter commented Jan 18, 2021

The patch has been committed as r38183. Thank you for reporting the issue.

@nmap-bot nmap-bot closed this in 4564749 Jan 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants