diff --git a/CHANGELOG.md b/CHANGELOG.md index bd243cde..7f102a8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [#94](https://github.com/scionproto-contrib/jpan/pull/94) - **BREAKING CHANGE**: removed `RequestPath` and `ScionAddress` from public API. [#95](https://github.com/scionproto-contrib/jpan/pull/95) +- Better error message for SCMP echo in local AS + [#96](https://github.com/scionproto-contrib/jpan/issues/96) ### Fixed - Fixed locking and resizing of buffers. [#68](https://github.com/scionproto-contrib/jpan/pull/68) diff --git a/src/main/java/org/scion/jpan/PathMetadata.java b/src/main/java/org/scion/jpan/PathMetadata.java index 30646a71..25a95db3 100644 --- a/src/main/java/org/scion/jpan/PathMetadata.java +++ b/src/main/java/org/scion/jpan/PathMetadata.java @@ -43,9 +43,17 @@ static PathMetadata create(Daemon.Path path, InetAddress dstIP, int dstPort) { private PathMetadata(Daemon.Path path, InetAddress dstIP, int dstPort) { this.pathProtoc = path; this.pathRaw = path.getRaw().toByteArray(); + // path length 0 means "local AS" if (getRawPath().length == 0) { - // local AS has path length 0 + // See issue https://github.com/scionproto-contrib/jpan/issues/96 + // if (dstIP.isAnyLocalAddress()) { + // // This is an SCMP request + // ScionService service = Scion.defaultService(); + // firstHop = + // ScionUtil.parseInetSocketAddress(service.getBorderRouterStrings().get(0)); + // } else { firstHop = new InetSocketAddress(dstIP, dstPort); + // } } else { firstHop = getFirstHopAddress(path); } diff --git a/src/main/java/org/scion/jpan/ScionService.java b/src/main/java/org/scion/jpan/ScionService.java index 5b7ca427..6071cd6a 100644 --- a/src/main/java/org/scion/jpan/ScionService.java +++ b/src/main/java/org/scion/jpan/ScionService.java @@ -36,6 +36,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.Collectors; import org.scion.jpan.internal.*; import org.scion.jpan.proto.control_plane.SegmentLookupServiceGrpc; import org.scion.jpan.proto.daemon.Daemon; @@ -605,4 +606,14 @@ InetAddress getExternalIP(InetSocketAddress firstHopAddress) { } } } + + List getBorderRouterStrings() { + if (daemonStub != null) { + return getInterfaces().values().stream() + .map(i -> i.getAddress().getAddress()) + .collect(Collectors.toList()); + } else { + return bootstrapper.getBorderRouterAddresses(); + } + } } diff --git a/src/main/java/org/scion/jpan/ScionUtil.java b/src/main/java/org/scion/jpan/ScionUtil.java index cccf190b..37f204bd 100644 --- a/src/main/java/org/scion/jpan/ScionUtil.java +++ b/src/main/java/org/scion/jpan/ScionUtil.java @@ -14,6 +14,9 @@ package org.scion.jpan; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import org.scion.jpan.internal.PathRawParser; /** Scion utility functions. */ @@ -190,5 +193,15 @@ public static long extractAs(long isdAs) { return isdAs & MAX_AS; } + static InetSocketAddress parseInetSocketAddress(String addrStr) { + try { + int posColon = addrStr.indexOf(':'); + InetAddress inetAddress = InetAddress.getByName(addrStr.substring(0, posColon)); + return new InetSocketAddress(inetAddress, Integer.parseInt(addrStr.substring(posColon + 1))); + } catch (UnknownHostException e) { + throw new IllegalArgumentException(e); + } + } + private ScionUtil() {} } diff --git a/src/main/java/org/scion/jpan/ScmpChannel.java b/src/main/java/org/scion/jpan/ScmpChannel.java index 337dedf0..148a3fb9 100644 --- a/src/main/java/org/scion/jpan/ScmpChannel.java +++ b/src/main/java/org/scion/jpan/ScmpChannel.java @@ -219,6 +219,11 @@ Scmp.TimedMessage sendEchoRequest(Scmp.EchoMessage request) throws IOException { writeLock().lock(); try { Path path = request.getPath(); + if (path.getRawPath().length == 0 + && path.getFirstHopAddress().getAddress().isAnyLocalAddress()) { + throw new ScionException( + "Cannot ping service address in local AS: " + path.getFirstHopAddress()); + } super.channel().connect(path.getFirstHopAddress()); ByteBuffer buffer = getBufferSend(DEFAULT_BUFFER_SIZE); // EchoHeader = 8 + data diff --git a/src/main/java/org/scion/jpan/internal/ScionBootstrapper.java b/src/main/java/org/scion/jpan/internal/ScionBootstrapper.java index 3ca188fd..93b79fae 100644 --- a/src/main/java/org/scion/jpan/internal/ScionBootstrapper.java +++ b/src/main/java/org/scion/jpan/internal/ScionBootstrapper.java @@ -197,6 +197,14 @@ public String getBorderRouterAddress(int interfaceId) { throw new ScionRuntimeException("No router found with interface ID " + interfaceId); } + public List getBorderRouterAddresses() { + List result = new ArrayList<>(); + for (BorderRouter br : borderRouters) { + result.add(br.internalAddress); + } + return result; + } + public int getLocalMtu() { return this.localMtu; } diff --git a/src/test/java/org/scion/jpan/api/SCMPTest.java b/src/test/java/org/scion/jpan/api/SCMPTest.java index 2ddc0cd9..757f798a 100644 --- a/src/test/java/org/scion/jpan/api/SCMPTest.java +++ b/src/test/java/org/scion/jpan/api/SCMPTest.java @@ -102,8 +102,13 @@ void echo() throws IOException { } @Test - void echo_localAS() throws IOException { - testEcho(this::getPathToLocalAS); + void echo_localAS_BR() throws IOException { + testEcho(this::getPathToLocalAS_BR); + } + + @Test + void echo_localAS_SVC() { + assertThrows(ScionException.class, () -> testEcho(this::getPathToLocalAS_SVC)); } private void testEcho(Supplier path) throws IOException { @@ -194,8 +199,13 @@ void traceroute() throws IOException { } @Test - void traceroute_localAS() throws IOException { - testTraceroute(this::getPathToLocalAS, 0); + void traceroute_localAS_BR() throws IOException { + testTraceroute(this::getPathToLocalAS_BR, 0); + } + + @Test + void traceroute_localAS_SVC() throws IOException { + testTraceroute(this::getPathToLocalAS_SVC, 0); } private void testTraceroute(Supplier path, int nHops) throws IOException { @@ -307,10 +317,11 @@ private Path getPathTo112(InetAddress dstAddress) { return service.getPaths(dstIA, dstAddress, Constants.SCMP_PORT).get(0); } - private Path getPathToLocalAS() { + private Path getPathToLocalAS_BR() { ScionService service = Scion.defaultService(); long dstIA = service.getLocalIsdAs(); try { + // Border router address InetAddress addr = InetAddress.getByName(MockNetwork.BORDER_ROUTER_HOST); int port = MockNetwork.BORDER_ROUTER_PORT1; List paths = service.getPaths(dstIA, new InetSocketAddress(addr, port)); @@ -320,6 +331,20 @@ private Path getPathToLocalAS() { } } + private Path getPathToLocalAS_SVC() { + ScionService service = Scion.defaultService(); + long dstIA = service.getLocalIsdAs(); + try { + // Service address + InetAddress addr = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); + int port = Constants.SCMP_PORT; + List paths = service.getPaths(dstIA, new InetSocketAddress(addr, port)); + return paths.get(0); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + @Test void setUpScmpResponder_echo() throws IOException, InterruptedException { MockNetwork.startTiny(); diff --git a/src/test/java/org/scion/jpan/demo/ScmpEchoDemo.java b/src/test/java/org/scion/jpan/demo/ScmpEchoDemo.java index c781e76a..37962bce 100644 --- a/src/test/java/org/scion/jpan/demo/ScmpEchoDemo.java +++ b/src/test/java/org/scion/jpan/demo/ScmpEchoDemo.java @@ -64,14 +64,13 @@ public ScmpEchoDemo(int localPort) { private static final Network network = Network.PRODUCTION; public static void main(String[] args) throws IOException { - ScionService service = Scion.defaultService(); switch (network) { case JUNIT_MOCK: { DemoTopology.configureMock(); MockDNS.install("1-ff00:0:112", "ip6-localhost", "::1"); ScmpEchoDemo demo = new ScmpEchoDemo(); - demo.runDemo(service.getPaths(DemoConstants.ia112, serviceIP).get(0)); + demo.runDemo(Scion.defaultService().getPaths(DemoConstants.ia112, serviceIP).get(0)); DemoTopology.shutDown(); break; } @@ -87,15 +86,18 @@ public static void main(String[] args) throws IOException { // System.setProperty(Constants.PROPERTY_DAEMON, DemoConstants.daemon1111_minimal); ScmpEchoDemo demo = new ScmpEchoDemo(); - demo.runDemo(service.getPaths(DemoConstants.ia211, serviceIP).get(0)); - // demo.runDemo(service.getPaths(DemoConstants.ia111, serviceIP).get(0)); - // demo.runDemo(service.getPaths(DemoConstants.ia1111, serviceIP).get(0)); + demo.runDemo(Scion.defaultService().getPaths(DemoConstants.ia211, serviceIP).get(0)); + // Echo to local AS and on-path AS (111 is "on" the UP segment) is currently broken, + // see https://github.com/scionproto-contrib/jpan/issues/96 + // demo.runDemo(Scion.defaultService().getPaths(DemoConstants.ia111, serviceIP).get(0)); + // demo.runDemo(Scion.defaultService().getPaths(DemoConstants.ia1111, serviceIP).get(0)); break; } case PRODUCTION: { // Local port must be 30041 for networks that expect a dispatcher ScmpEchoDemo demo = new ScmpEchoDemo(Constants.SCMP_PORT); + ScionService service = Scion.defaultService(); demo.runDemo(service.lookupAndGetPath("ethz.ch", Constants.SCMP_PORT, null)); demo.runDemo(service.getPaths(DemoConstants.iaOVGU, serviceIP).get(0)); break; @@ -160,10 +162,4 @@ private static void println(String msg) { System.out.println(msg); } } - - private static InetSocketAddress toAddr(String addrString) throws UnknownHostException { - int posColon = addrString.indexOf(':'); - InetAddress addr = InetAddress.getByName(addrString.substring(0, posColon)); - return new InetSocketAddress(addr, Constants.SCMP_PORT); - } } diff --git a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java index b1b3ce13..a9020610 100644 --- a/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java +++ b/src/test/java/org/scion/jpan/demo/ScmpTracerouteDemo.java @@ -72,6 +72,8 @@ public static void main(String[] args) throws IOException { System.setProperty(Constants.PROPERTY_DAEMON, DemoConstants.daemon1111_minimal); ScmpTracerouteDemo demo = new ScmpTracerouteDemo(); demo.runDemo(DemoConstants.ia211); + demo.runDemo(DemoConstants.ia111); + demo.runDemo(DemoConstants.ia1111); break; } case PRODUCTION: diff --git a/src/test/java/org/scion/jpan/testutil/MockDaemon.java b/src/test/java/org/scion/jpan/testutil/MockDaemon.java index 9a9a90d3..e9ed5016 100644 --- a/src/test/java/org/scion/jpan/testutil/MockDaemon.java +++ b/src/test/java/org/scion/jpan/testutil/MockDaemon.java @@ -206,5 +206,21 @@ public void aS(Daemon.ASRequest req, StreamObserver responseO responseObserver.onNext(replyBuilder.build()); responseObserver.onCompleted(); } + + @Override + public void interfaces( + Daemon.InterfacesRequest req, StreamObserver responseObserver) { + callCount.incrementAndGet(); + Daemon.InterfacesResponse.Builder replyBuilder = Daemon.InterfacesResponse.newBuilder(); + int i = -1; + for (String br : borderRouters) { + Daemon.Interface.Builder ifBuilder = Daemon.Interface.newBuilder(); + ifBuilder.setAddress(Daemon.Underlay.newBuilder().setAddress(br).build()); + // Interface IDs are currently not supported + replyBuilder.putInterfaces(i--, ifBuilder.build()); + } + responseObserver.onNext(replyBuilder.build()); + responseObserver.onCompleted(); + } } }