From 940af5a896bcbf4b4d8256e88b516d8a883a308b Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Sat, 17 Jun 2023 10:41:10 +0200 Subject: [PATCH] Get the actual local address, not 0.0.0.0 The sockets are bound on all interfaces using INADDR_ANY, so getsockname always return 0.0.0.0. The actual address can be obtained from the destination address of the received IP packet using the socket ancillary data. --- src/TracerouteListener.cpp | 3 +++ src/TracerouteReader.cpp | 30 ++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/TracerouteListener.cpp b/src/TracerouteListener.cpp index 7da3489..0bbfac0 100644 --- a/src/TracerouteListener.cpp +++ b/src/TracerouteListener.cpp @@ -77,6 +77,9 @@ int TracerouteListener::bindSocket(int port) { localAddress.sin_addr.s_addr = INADDR_ANY; localAddress.sin_port = htons(port); + int on = 1; + setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); + if ((bind(sockfd, (struct sockaddr*)&localAddress, sizeof(localAddress))) < 0) { fprintf(stderr, "Error Binding Socket\n"); exit(1); diff --git a/src/TracerouteReader.cpp b/src/TracerouteReader.cpp index 64a1070..3adcb13 100644 --- a/src/TracerouteReader.cpp +++ b/src/TracerouteReader.cpp @@ -38,24 +38,42 @@ #include class TraceroutePacket* TracerouteReader::readPacket(int fd) { - char packet[32*1024]; + char cmsg[CMSG_SPACE(sizeof(struct in_pktinfo))]; struct sockaddr_in remoteAddress; struct sockaddr_in localAddress; - + struct msghdr msg; unsigned int size = sizeof(remoteAddress); memset((void*)&remoteAddress, 0, size); memset((void*)&localAddress, 0, size); + memset((void*)&msg, 0, sizeof(msg)); - if ((recvfrom(fd, packet, 32*1024, 0, (struct sockaddr*)&remoteAddress, &size)) < 0) { + // get local address + if ((getsockname(fd, (struct sockaddr*)&localAddress, &size)) < 0) { + fprintf(stderr, "Error getting local name."); + exit(1); + } + + // read message + msg.msg_name = &remoteAddress; + msg.msg_namelen = size; + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof(cmsg); + if (recvmsg(fd, &msg, 0) < 0) { fprintf(stderr, "Error receiving datagram."); exit(1); } - if ((getsockname(fd, (struct sockaddr*)&localAddress, &size)) < 0) { - fprintf(stderr, "Error getting local name."); - exit(1); + // get actual IP address + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { + struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg); + localAddress.sin_addr = pi->ipi_spec_dst; + break; + } } return new TraceroutePacket(inet_ntoa(remoteAddress.sin_addr),