Filter Discovered peers for ipv6 support (#6498)

* use existing NetworkUtility for PeerDiscoveryAgent pingpacket data filtering, add ipv6 check/fallback
* log at debug when we override pingpacket from
* use java native address parsing rather than lookup by host

Signed-off-by: garyschulte <garyschulte@gmail.com>
pull/6502/head
garyschulte 9 months ago committed by GitHub
parent d47e52664a
commit 79245bb9af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 45
      ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/discovery/PeerDiscoveryAgent.java
  2. 53
      util/src/main/java/org/hyperledger/besu/util/NetworkUtility.java
  3. 29
      util/src/test/java/org/hyperledger/besu/util/NetworkUtilityTest.java

@ -74,9 +74,6 @@ public abstract class PeerDiscoveryAgent {
// The devp2p specification says only accept packets up to 1280, but some
// clients ignore that, so we add in a little extra padding.
private static final int MAX_PACKET_SIZE_BYTES = 1600;
private static final List<String> PING_PACKET_SOURCE_IGNORED =
List.of("127.0.0.1", "255.255.255.255", "0.0.0.0", "::", "0:0:0:0:0:0:0:0");
protected final List<DiscoveryPeer> bootstrapPeers;
private final List<PeerRequirement> peerRequirements = new CopyOnWriteArrayList<>();
private final PeerPermissions peerPermissions;
@ -85,6 +82,7 @@ public abstract class PeerDiscoveryAgent {
private final RlpxAgent rlpxAgent;
private final ForkIdManager forkIdManager;
private final PeerTable peerTable;
private static final boolean isIpv6Available = NetworkUtility.isIPv6Available();
/* The peer controller, which takes care of the state machine of peers. */
protected Optional<PeerDiscoveryController> controller = Optional.empty();
@ -316,23 +314,38 @@ public abstract class PeerDiscoveryAgent {
* @return host address as string
*/
static String deriveHost(final Endpoint sourceEndpoint, final Packet packet) {
return packet
.getPacketData(PingPacketData.class)
.flatMap(PingPacketData::getFrom)
.map(Endpoint::getHost)
.filter(
fromAddr ->
(!PING_PACKET_SOURCE_IGNORED.contains(fromAddr)
&& InetAddresses.isInetAddress(fromAddr)))
final Optional<String> pingPacketHost =
packet
.getPacketData(PingPacketData.class)
.flatMap(PingPacketData::getFrom)
.map(Endpoint::getHost);
return pingPacketHost
// fall back to source endpoint "from" if ping packet from address does not satisfy filters
.filter(InetAddresses::isInetAddress)
.filter(h -> !NetworkUtility.isUnspecifiedAddress(h))
.filter(h -> !NetworkUtility.isLocalhostAddress(h))
.filter(h -> isIpv6Available || !NetworkUtility.isIpV6Address(h))
.stream()
.peek(
h ->
LOG.trace(
"Using \"From\" endpoint {} specified in ping packet. Ignoring UDP source host {}",
h,
sourceEndpoint.getHost()))
LOG.atTrace()
.setMessage(
"Using \"From\" endpoint {} specified in ping packet. Ignoring UDP source host {}")
.addArgument(h)
.addArgument(sourceEndpoint::getHost)
.log())
.findFirst()
.orElseGet(sourceEndpoint::getHost);
.orElseGet(
() -> {
LOG.atTrace()
.setMessage(
"Ignoring \"From\" endpoint {} in ping packet. Using UDP source host {}")
.addArgument(pingPacketHost.orElse("not specified"))
.addArgument(sourceEndpoint.getHost())
.log();
return sourceEndpoint.getHost();
});
}
/**

@ -16,6 +16,7 @@ package org.hyperledger.besu.util;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@ -26,6 +27,7 @@ import java.net.UnknownHostException;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.net.InetAddresses;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -33,8 +35,16 @@ import org.slf4j.LoggerFactory;
public class NetworkUtility {
/** The constant INADDR_ANY. */
public static final String INADDR_ANY = "0.0.0.0";
/** The constant INADDR_NONE. */
public static final String INADDR_NONE = "255.255.255.255";
/** The constant INADDR6_ANY. */
public static final String INADDR6_ANY = "0:0:0:0:0:0:0:0";
/** The constant INADDR6_NONE. */
public static final String INADDR6_NONE = "::";
/** The constant INADDR_LOCALHOST. */
public static final String INADDR_LOCALHOST = "127.0.0.1";
/** The constant INADDR6_LOCALHOST. */
public static final String INADDR6_LOCALHOST = "::1";
private static final Logger LOG = LoggerFactory.getLogger(NetworkUtility.class);
@ -119,7 +129,20 @@ public class NetworkUtility {
* @return the boolean
*/
public static boolean isUnspecifiedAddress(final String ipAddress) {
return INADDR_ANY.equals(ipAddress) || INADDR6_ANY.equals(ipAddress);
return INADDR_ANY.equals(ipAddress)
|| INADDR6_ANY.equals(ipAddress)
|| INADDR_NONE.equals(ipAddress)
|| INADDR6_NONE.equals(ipAddress);
}
/**
* Returns whether host address string is local host address.
*
* @param ipAddress the host address as a string
* @return true if the host address is a local host address
*/
public static boolean isLocalhostAddress(final String ipAddress) {
return INADDR_LOCALHOST.equals(ipAddress) || INADDR6_LOCALHOST.equals(ipAddress);
}
/**
@ -173,4 +196,32 @@ public class NetworkUtility {
public static boolean isPortAvailable(final int port) {
return isPortAvailableForTcp(port) && isPortAvailableForUdp(port);
}
/**
* Is hostAddress string an ip v4 address
*
* @param hostAddress the host address as a string
* @return true if the host address is an ip v4 address
*/
public static boolean isIpV4Address(final String hostAddress) {
try {
return InetAddresses.forString(hostAddress) instanceof Inet4Address;
} catch (final IllegalArgumentException e) {
return false;
}
}
/**
* Is hostAddress string an ip v6 address
*
* @param hostAddress the host address as a string
* @return true if the host address is an ip v6 address
*/
public static boolean isIpV6Address(final String hostAddress) {
try {
return InetAddresses.forString(hostAddress) instanceof Inet6Address;
} catch (final IllegalArgumentException e) {
return false;
}
}
}

@ -40,4 +40,33 @@ public class NetworkUtilityTest {
assertThat(!NetworkUtility.isPortAvailable(8541)).isEqualTo(true);
serverSocket.close();
}
@Test
public void assertLocalhostIdentification() {
assertThat(NetworkUtility.isLocalhostAddress("127.0.0.1")).isTrue();
assertThat(NetworkUtility.isLocalhostAddress("::1")).isTrue();
assertThat(NetworkUtility.isLocalhostAddress("192.168.1.1")).isFalse();
assertThat(NetworkUtility.isLocalhostAddress("::ffff:c0a8:101")).isFalse();
}
@Test
public void assertIpV4Address() {
assertThat(NetworkUtility.isIpV4Address("127.0.0.1")).isTrue();
assertThat(NetworkUtility.isIpV4Address("10.0.0.0")).isTrue();
assertThat(NetworkUtility.isIpV4Address("172.16.1.1")).isTrue();
assertThat(NetworkUtility.isIpV4Address("127.0.0.")).isFalse();
assertThat(NetworkUtility.isIpV4Address("256.256.256.256")).isFalse();
// ipv6 compatible ipv4 address
assertThat(NetworkUtility.isIpV4Address("::ffff:c0a8:5801")).isTrue();
assertThat(NetworkUtility.isIpV4Address("0:0:0:0:0:ffff:c0a8:5801")).isTrue();
assertThat(NetworkUtility.isIpV4Address("0000:0000:0000:0000:0000:ffff:c0a8:5801")).isTrue();
}
@Test
public void assertIpV6Address() {
assertThat(NetworkUtility.isIpV6Address("::1")).isTrue();
assertThat(NetworkUtility.isIpV6Address("::")).isTrue();
assertThat(NetworkUtility.isIpV6Address("2001:db8:3333:4444:5555:6666:7777:8888")).isTrue();
assertThat(NetworkUtility.isIpV6Address("00:00::00:00::00:00")).isFalse();
}
}

Loading…
Cancel
Save