You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2018/02/21 14:36:53 UTC

[incubator-plc4x] branch master updated: PLC4X-31 - Make RawSocket able to connect to remotes using a gateway. - Made the RawSocket get and use the default-gateway for connecting to hosts not in the local network. - Added a Test for RawSocket sending a ICMP (Ping) packet to the plc4x.apache.org host.

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-plc4x.git


The following commit(s) were added to refs/heads/master by this push:
     new 9352611  PLC4X-31 - Make RawSocket able to connect to remotes using a gateway. - Made the RawSocket get and use the default-gateway for connecting to hosts not in the local network. - Added a Test for RawSocket sending a ICMP (Ping) packet to the plc4x.apache.org host.
9352611 is described below

commit 935261177b1b2659f577c5b7022b6bf4c871a14a
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Wed Feb 21 15:36:14 2018 +0100

    PLC4X-31 - Make RawSocket able to connect to remotes using a gateway.
    - Made the RawSocket get and use the default-gateway for connecting to hosts not in the local network.
    - Added a Test for RawSocket sending a ICMP (Ping) packet to the plc4x.apache.org host.
---
 plc4j/utils/raw-sockets/pom.xml                    |   5 +
 .../plc4x/java/utils/rawsockets/RawSocket.java     | 504 +++++++++++++++++----
 .../plc4x/java/utils/rawsockets/RawSocketTest.java |  35 +-
 3 files changed, 459 insertions(+), 85 deletions(-)

diff --git a/plc4j/utils/raw-sockets/pom.xml b/plc4j/utils/raw-sockets/pom.xml
index f22a424..da5f71f 100644
--- a/plc4j/utils/raw-sockets/pom.xml
+++ b/plc4j/utils/raw-sockets/pom.xml
@@ -51,6 +51,11 @@
     </dependency>
 
     <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+
+    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
diff --git a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawSocket.java b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawSocket.java
index 098008a..0cbe603 100644
--- a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawSocket.java
+++ b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawSocket.java
@@ -15,17 +15,20 @@
  */
 package org.apache.plc4x.java.utils.rawsockets;
 
+import org.apache.commons.lang3.SystemUtils;
 import org.pcap4j.core.*;
 import org.pcap4j.packet.*;
 import org.pcap4j.packet.namednumber.*;
 import org.pcap4j.util.ByteArrays;
+import org.pcap4j.util.LinkLayerAddress;
 import org.pcap4j.util.MacAddress;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.*;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -43,7 +46,7 @@ public class RawSocket {
 
     private PcapNetworkInterface nif;
     private InetAddress remoteIpAddress;
-    private MacAddress remoteMacAddress;
+    private MacAddress firstHopMacAddress;
     private InetAddress localIpAddress;
     private MacAddress localMacAddress;
     private ExecutorService pool = Executors.newSingleThreadExecutor();
@@ -61,35 +64,73 @@ public class RawSocket {
 
             remoteIpAddress = InetAddress.getByName(remoteAddress);
 
-            localIpAddress = getLocalNetworkAddress(remoteIpAddress);
-            if (localIpAddress == null) {
-                throw new RawSocketException("Unable to connect to the remote address " + remoteAddress);
+            // As we have to create the Ethernet packets ourselves, and
+            // in case of non local remote addresses we need to go through
+            // routers and gateways, we need do differentiate between the
+            // next ethernet node and the remote ip address.
+            //
+            // We therefore need to know the following information:
+            // 1. Can we connect to the remote directly (a) or do we
+            //    need a gateway (b)?
+            // 2. The local IP and Mac Address of our device
+            // 3a. The remote IP and Mac address of the target device
+            // 3b. The remote IP of the target device & the Mac address
+            //     of the gateway.
+
+            // Check if we can connect directly to the destination.
+            FirstHop firstHop = getFirstHop(remoteIpAddress);
+            if(firstHop == null) {
+                // If this wouldn't work, try to figure out the default
+                // gateway and use that as next hop.
+                InetAddress defaultGatewayAddress = getDefaultGatewayAddress();
+                if(defaultGatewayAddress != null) {
+                    firstHop = getFirstHop(defaultGatewayAddress);
+                    if (firstHop == null) {
+                        // If this didn't work, we simply can't reach the
+                        // destination and give up with an exception. Not
+                        // much we can do here.
+                        throw new RawSocketException("Unable to connect to " + remoteAddress);
+                    }
+                } else {
+                    throw new RawSocketException("Unable to connect to " + remoteAddress);
+                }
+            }
+
+            nif = firstHop.networkInterface;
+
+            if (nif.isLoopBack()) {
+                throw new RawSocketException("Can't use RawSocket on loopback devices");
             }
-            nif = Pcaps.getDevByAddress(localIpAddress);
-            localMacAddress = MacAddress.getByAddress(nif.getLinkLayerAddresses().get(0).getAddress());
 
-            remoteMacAddress = getMacAddress(remoteIpAddress);
+            localMacAddress = MacAddress.getByAddress(firstHop.localMacAddress.getAddress());
+            localIpAddress = firstHop.localInetAddress;
+
+            firstHopMacAddress = MacAddress.getByAddress(firstHop.remoteMacAddress.getAddress());
 
             // Setup receiving of packets and redirecting them to the corresponding listeners.
             // Filter packets to contain only the ip protocol number of the current protocol.
             receiveHandle = nif.openLive(SNAPLEN, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
+
             // Set the filter.
             String filterString = "ip protochain " + protocolNumber +
                 " and ether dst " + localMacAddress.toString() +
-                " and ether src " + remoteMacAddress.toString();
+                " and ip dst " + localIpAddress.getHostAddress() +
+                " and ether src " + firstHopMacAddress.toString() +
+                " and ip src " + remoteIpAddress.getHostAddress();
+
             receiveHandle.setFilter(filterString, BpfProgram.BpfCompileMode.OPTIMIZE);
-            PacketListener packetListener
-                = packet -> {
+            PacketListener packetListener = packet -> {
                 for(RawSocketListener listener : listeners) {
                     listener.packetReceived(packet.getRawData());
                 }
             };
+
             pool.execute(() -> {
                 try {
                     receiveHandle.loop(-1, packetListener);
                 } catch (PcapNativeException | InterruptedException | NotOpenException e) {
                     logger.error("Error receiving packet for protocol {} from MAC address {}",
-                        protocolNumber, remoteMacAddress, e);
+                        protocolNumber, firstHopMacAddress, e);
                 }
             });
         } catch (PcapNativeException | NotOpenException | UnknownHostException e) {
@@ -121,7 +162,7 @@ public class RawSocket {
             ipV4Builder.identification((short) 1);
 
             EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
-            etherBuilder.dstAddr(remoteMacAddress)
+            etherBuilder.dstAddr(firstHopMacAddress)
                 .srcAddr(localMacAddress)
                 .type(EtherType.IPV4)
                 .paddingAtBuild(true);
@@ -149,76 +190,88 @@ public class RawSocket {
         listeners.remove(listener);
     }
 
-    protected MacAddress getMacAddress(InetAddress address) throws RawSocketException {
-        if(!arpCache.containsKey(address)) {
-            MacAddress macAddress = lookupMacAddress(address);
-            arpCache.put(address, macAddress);
+    private MacAddress getMacAddress(PcapNetworkInterface dev, InetAddress localIpAddress, InetAddress remoteIpAddress) throws RawSocketException {
+        if(!arpCache.containsKey(remoteIpAddress)) {
+            MacAddress macAddress = lookupMacAddress(dev, localIpAddress, remoteIpAddress);
+            arpCache.put(remoteIpAddress, macAddress);
             return macAddress;
         }
-        return arpCache.get(address);
+        return arpCache.get(remoteIpAddress);
     }
 
-    protected MacAddress lookupMacAddress(InetAddress remoteIpAddress) throws RawSocketException {
-        try (PcapHandle receiveHandle
-                 = nif.openLive(SNAPLEN, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
-             PcapHandle sendHandle
-                 = nif.openLive(SNAPLEN, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT)){
-
-            // Setup the filter to accept only the arp packets sent back to the current
-            // host from the address of the remote host we wanted to get the mac address
-            // from.
-            receiveHandle.setFilter(
-                "arp and src host " + remoteIpAddress.getHostAddress()
-                    + " and dst host " + localIpAddress.getHostAddress()
-                    + " and ether dst " + localMacAddress.toString(),
-                BpfProgram.BpfCompileMode.OPTIMIZE
-            );
-
-            CompletableFuture<MacAddress> resolutionFuture = new CompletableFuture<>();
-            PacketListener listener
-                = packet -> {
-                if (packet.contains(ArpPacket.class)) {
-                    ArpPacket arp = packet.get(ArpPacket.class);
-                    if (arp.getHeader().getOperation().equals(ArpOperation.REPLY)) {
-                        resolutionFuture.complete(arp.getHeader().getSrcHardwareAddr());
+    private MacAddress lookupMacAddress(PcapNetworkInterface dev, InetAddress localIpAddress, InetAddress remoteIpAddress) throws RawSocketException {
+        try {
+            PcapHandle receiveHandle =
+                dev.openLive(SNAPLEN, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
+            PcapHandle sendHandle =
+                dev.openLive(SNAPLEN, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT);
+            try {
+                // Setup the filter to accept only the arp packets sent back to the current
+                // host from the address of the remote host we wanted to get the mac address
+                // from.
+                receiveHandle.setFilter(
+                    "arp and src host " + remoteIpAddress.getHostAddress()
+                        + " and dst host " + localIpAddress.getHostAddress(),
+                    BpfProgram.BpfCompileMode.OPTIMIZE
+                );
+
+                CompletableFuture<MacAddress> resolutionFuture = new CompletableFuture<>();
+                PacketListener listener
+                    = packet -> {
+                    if (packet.contains(ArpPacket.class)) {
+                        ArpPacket arp = packet.get(ArpPacket.class);
+                        if (arp.getHeader().getOperation().equals(ArpOperation.REPLY)) {
+                            resolutionFuture.complete(arp.getHeader().getSrcHardwareAddr());
+                        }
                     }
-                }
-            };
+                };
 
-            pool.execute(() -> {
+                pool.execute(() -> {
+                    try {
+                        receiveHandle.loop(-1, listener);
+                    } catch (PcapNativeException | InterruptedException | NotOpenException e) {
+                        logger.error("Error receiving ARP lookup", e);
+                    }
+                });
+
+                MacAddress localMacAddress = MacAddress.getByAddress(
+                    dev.getLinkLayerAddresses().iterator().next().getAddress());
+                ArpPacket.Builder arpBuilder = new ArpPacket.Builder();
+                arpBuilder
+                    .hardwareType(ArpHardwareType.ETHERNET)
+                    .protocolType(EtherType.IPV4)
+                    .hardwareAddrLength((byte) MacAddress.SIZE_IN_BYTES)
+                    .protocolAddrLength((byte) ByteArrays.INET4_ADDRESS_SIZE_IN_BYTES)
+                    .operation(ArpOperation.REQUEST)
+                    .srcHardwareAddr(localMacAddress)
+                    .srcProtocolAddr(localIpAddress)
+                    .dstHardwareAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
+                    .dstProtocolAddr(remoteIpAddress);
+
+                EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
+                etherBuilder.dstAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
+                    .srcAddr(localMacAddress)
+                    .type(EtherType.ARP)
+                    .payloadBuilder(arpBuilder)
+                    .paddingAtBuild(true);
+
+                Packet p = etherBuilder.build();
+                sendHandle.sendPacket(p);
                 try {
-                    receiveHandle.loop(-1, listener);
-                } catch (PcapNativeException | InterruptedException | NotOpenException e) {
-                    logger.error("Error receiving ARP lookup", e);
+                    return resolutionFuture.get(3000, TimeUnit.MILLISECONDS);
+                } catch (TimeoutException e) {
+                    logger.info("Couldn't resolve MAC address for ip address {}", remoteIpAddress.getHostAddress(), e);
+                    return null;
+                }
+            } finally {
+                if (sendHandle.isOpen()) {
+                    sendHandle.close();
+                }
+                if(receiveHandle.isOpen()) {
+                    // Terminate the receive loop first.
+                    receiveHandle.breakLoop();
+                    receiveHandle.close();
                 }
-            });
-
-            ArpPacket.Builder arpBuilder = new ArpPacket.Builder();
-            arpBuilder
-                .hardwareType(ArpHardwareType.ETHERNET)
-                .protocolType(EtherType.IPV4)
-                .hardwareAddrLength((byte) MacAddress.SIZE_IN_BYTES)
-                .protocolAddrLength((byte) ByteArrays.INET4_ADDRESS_SIZE_IN_BYTES)
-                .operation(ArpOperation.REQUEST)
-                .srcHardwareAddr(localMacAddress)
-                .srcProtocolAddr(localIpAddress)
-                .dstHardwareAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
-                .dstProtocolAddr(remoteIpAddress);
-
-            EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
-            etherBuilder.dstAddr(MacAddress.ETHER_BROADCAST_ADDRESS)
-                .srcAddr(localMacAddress)
-                .type(EtherType.ARP)
-                .payloadBuilder(arpBuilder)
-                .paddingAtBuild(true);
-
-            Packet p = etherBuilder.build();
-            sendHandle.sendPacket(p);
-            try {
-                return resolutionFuture.get(10000, TimeUnit.MILLISECONDS);
-            } catch (TimeoutException e) {
-                logger.info("Couldn't resolve MAC address for ip address {}", remoteIpAddress.getHostAddress(), e);
-                return null;
             }
         } catch (PcapNativeException | InterruptedException | ExecutionException | NotOpenException e) {
             throw new RawSocketException("Error looking up mac address.", e);
@@ -232,17 +285,18 @@ public class RawSocket {
      * @return PcapNetworkInterface interface that should be able to connect to the given address.
      * @throws RawSocketException something went wrong.
      */
-    protected InetAddress getLocalNetworkAddress(InetAddress remoteAddress) throws RawSocketException {
+    private FirstHop getFirstHop(InetAddress remoteAddress) throws RawSocketException {
         byte[] remoteIp = remoteAddress.getAddress();
         // Iterate over all network interfaces.
         try {
+            // First try if we can connect to the remote device directly.
             for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
                 // Iterate over all addresses configured for this interface.
-                for (PcapAddress addr : dev.getAddresses()) {
+                for (PcapAddress localAddress : dev.getAddresses()) {
                     // Only check addresses matching the IP-version of the remote address.
-                    if (remoteAddress.getClass().equals(addr.getAddress().getClass())) {
-                        byte[] localIp = addr.getAddress().getAddress();
-                        byte[] netMask = addr.getNetmask().getAddress();
+                    if (remoteAddress.getClass().equals(localAddress.getAddress().getClass())) {
+                        byte[] localIp = localAddress.getAddress().getAddress();
+                        byte[] netMask = localAddress.getNetmask().getAddress();
                         boolean matches = true;
                         // Iterate over all bytes of the address and see if they match
                         // after applying the net mask filter.
@@ -255,15 +309,299 @@ public class RawSocket {
                         // If the current address would be able to connect to the remote
                         // address, return this device.
                         if (matches) {
-                            return addr.getAddress();
+                            return new FirstHop(dev, localAddress.getAddress(),
+                                dev.getLinkLayerAddresses().iterator().next(),
+                                getMacAddress(dev, localAddress.getAddress(), remoteAddress));
                         }
                     }
                 }
             }
+            return null;
         } catch (PcapNativeException e) {
             throw new RawSocketException("Error finding a device to communicate with remote address.", e);
         }
+    }
+
+    /**
+     * Unfortunately there is no way to get the ip address of the default gateway the
+     * system uses to route traffic to remote networks. Luckily the 'netstat' command
+     * is available on all systems and the only difference is the output. So in this
+     * case we fallback to executing this command and parsing it's output depending on
+     * the system it is run on.
+     *
+     * @return InetAddress representing the address of the internet gateway.
+     */
+    private InetAddress getDefaultGatewayAddress() {
+        try {
+            Runtime rt = Runtime.getRuntime();
+            String[] commands = {"netstat", "-rn"};
+            Process proc = rt.exec(commands);
+
+            BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+
+            String linePrefix;
+            int gatewayColumn;
+            if (SystemUtils.IS_OS_WINDOWS) {
+                linePrefix = "0.0.0.0";
+                gatewayColumn = 2;
+            } else if (SystemUtils.IS_OS_MAC_OSX) {
+                linePrefix = "default";
+                gatewayColumn = 1;
+            } else if (SystemUtils.IS_OS_LINUX) {
+                linePrefix = "0.0.0.0";
+                gatewayColumn = 1;
+            } else {
+                return null;
+            }
+
+            String s;
+            while ((s = stdInput.readLine()) != null) {
+                if (s.trim().startsWith(linePrefix)) {
+                    String[] columns = s.trim().split("\\s+");
+                    return InetAddress.getByName(columns[gatewayColumn]);
+                }
+            }
+        } catch (IOException e) {
+            return null;
+        }
+
+        // Command on all platforms: "netstat -rn"
+
+        /* Windows 7: line.trim().startsWith("0.0.0.0")
+
+===========================================================================
+Schnittstellenliste
+ 14...00 1c 42 98 16 7d ......Intel(R) PRO/1000 MT-Netzwerkverbindung #2
+ 11...00 1c 42 2e f3 40 ......Intel(R) PRO/1000 MT-Netzwerkverbindung
+  1...........................Software Loopback Interface 1
+ 13...00 00 00 00 00 00 00 e0 Microsoft-ISATAP-Adapter
+ 12...00 00 00 00 00 00 00 e0 Teredo Tunneling Pseudo-Interface
+ 15...00 00 00 00 00 00 00 e0 Microsoft-ISATAP-Adapter #2
+===========================================================================
+
+IPv4-Routentabelle
+===========================================================================
+Aktive Routen:
+     Netzwerkziel    Netzwerkmaske          Gateway    Schnittstelle Metrik
+          0.0.0.0          0.0.0.0      10.211.55.1      10.211.55.3     10
+      10.211.55.0    255.255.255.0   Auf Verbindung       10.211.55.3    266
+      10.211.55.3  255.255.255.255   Auf Verbindung       10.211.55.3    266
+    10.211.55.255  255.255.255.255   Auf Verbindung       10.211.55.3    266
+        127.0.0.0        255.0.0.0   Auf Verbindung         127.0.0.1    306
+        127.0.0.1  255.255.255.255   Auf Verbindung         127.0.0.1    306
+  127.255.255.255  255.255.255.255   Auf Verbindung         127.0.0.1    306
+      192.168.0.0      255.255.0.0   Auf Verbindung      192.168.0.43    266
+     192.168.0.43  255.255.255.255   Auf Verbindung      192.168.0.43    266
+  192.168.255.255  255.255.255.255   Auf Verbindung      192.168.0.43    266
+        224.0.0.0        240.0.0.0   Auf Verbindung         127.0.0.1    306
+        224.0.0.0        240.0.0.0   Auf Verbindung       10.211.55.3    266
+        224.0.0.0        240.0.0.0   Auf Verbindung      192.168.0.43    266
+  255.255.255.255  255.255.255.255   Auf Verbindung         127.0.0.1    306
+  255.255.255.255  255.255.255.255   Auf Verbindung       10.211.55.3    266
+  255.255.255.255  255.255.255.255   Auf Verbindung      192.168.0.43    266
+===========================================================================
+Ständige Routen:
+  Keine
+
+IPv6-Routentabelle
+===========================================================================
+Aktive Routen:
+ If Metrik Netzwerkziel             Gateway
+ 11    266 ::/0                     fe80::21c:42ff:fe00:18
+  1    306 ::1/128                  Auf Verbindung
+ 11     18 fdb2:2c26:f4e4::/64      Auf Verbindung
+ 11    266 fdb2:2c26:f4e4:0:24b4:9398:1a69:664/128
+                                    Auf Verbindung
+ 11    266 fdb2:2c26:f4e4:0:7147:34d4:e033:a879/128
+                                    Auf Verbindung
+ 14     18 fdb2:2c26:f4e4:1::/64    Auf Verbindung
+ 14    266 fdb2:2c26:f4e4:1:797d:18a9:3dd6:8105/128
+                                    Auf Verbindung
+ 14    266 fdb2:2c26:f4e4:1:bcd1:eeb5:c8c1:cf05/128
+                                    Auf Verbindung
+ 11    266 fe80::/64                Auf Verbindung
+ 14    266 fe80::/64                Auf Verbindung
+ 11    266 fe80::7147:34d4:e033:a879/128
+                                    Auf Verbindung
+ 14    266 fe80::797d:18a9:3dd6:8105/128
+                                    Auf Verbindung
+  1    306 ff00::/8                 Auf Verbindung
+ 11    266 ff00::/8                 Auf Verbindung
+ 14    266 ff00::/8                 Auf Verbindung
+===========================================================================
+Ständige Routen:
+  Keine
+
+
+        Windows 10
+
+===========================================================================
+Schnittstellenliste
+ 14...00 1c 42 98 16 7d ......Intel(R) PRO/1000 MT-Netzwerkverbindung #2
+ 11...00 1c 42 2e f3 40 ......Intel(R) PRO/1000 MT-Netzwerkverbindung
+  1...........................Software Loopback Interface 1
+ 13...00 00 00 00 00 00 00 e0 Microsoft-ISATAP-Adapter
+ 12...00 00 00 00 00 00 00 e0 Teredo Tunneling Pseudo-Interface
+ 15...00 00 00 00 00 00 00 e0 Microsoft-ISATAP-Adapter #2
+===========================================================================
+
+IPv4-Routentabelle
+===========================================================================
+Aktive Routen:
+     Netzwerkziel    Netzwerkmaske          Gateway    Schnittstelle Metrik
+          0.0.0.0          0.0.0.0      10.211.55.1      10.211.55.3     10
+      10.211.55.0    255.255.255.0   Auf Verbindung       10.211.55.3    266
+      10.211.55.3  255.255.255.255   Auf Verbindung       10.211.55.3    266
+    10.211.55.255  255.255.255.255   Auf Verbindung       10.211.55.3    266
+        127.0.0.0        255.0.0.0   Auf Verbindung         127.0.0.1    306
+        127.0.0.1  255.255.255.255   Auf Verbindung         127.0.0.1    306
+  127.255.255.255  255.255.255.255   Auf Verbindung         127.0.0.1    306
+      192.168.0.0      255.255.0.0   Auf Verbindung      192.168.0.43    266
+     192.168.0.43  255.255.255.255   Auf Verbindung      192.168.0.43    266
+  192.168.255.255  255.255.255.255   Auf Verbindung      192.168.0.43    266
+        224.0.0.0        240.0.0.0   Auf Verbindung         127.0.0.1    306
+        224.0.0.0        240.0.0.0   Auf Verbindung       10.211.55.3    266
+        224.0.0.0        240.0.0.0   Auf Verbindung      192.168.0.43    266
+  255.255.255.255  255.255.255.255   Auf Verbindung         127.0.0.1    306
+  255.255.255.255  255.255.255.255   Auf Verbindung       10.211.55.3    266
+  255.255.255.255  255.255.255.255   Auf Verbindung      192.168.0.43    266
+===========================================================================
+Ständige Routen:
+  Keine
+
+IPv6-Routentabelle
+===========================================================================
+Aktive Routen:
+ If Metrik Netzwerkziel             Gateway
+ 11    266 ::/0                     fe80::21c:42ff:fe00:18
+  1    306 ::1/128                  Auf Verbindung
+ 11     18 fdb2:2c26:f4e4::/64      Auf Verbindung
+ 11    266 fdb2:2c26:f4e4:0:24b4:9398:1a69:664/128
+                                    Auf Verbindung
+ 11    266 fdb2:2c26:f4e4:0:7147:34d4:e033:a879/128
+                                    Auf Verbindung
+ 14     18 fdb2:2c26:f4e4:1::/64    Auf Verbindung
+ 14    266 fdb2:2c26:f4e4:1:797d:18a9:3dd6:8105/128
+                                    Auf Verbindung
+ 14    266 fdb2:2c26:f4e4:1:bcd1:eeb5:c8c1:cf05/128
+                                    Auf Verbindung
+ 11    266 fe80::/64                Auf Verbindung
+ 14    266 fe80::/64                Auf Verbindung
+ 11    266 fe80::7147:34d4:e033:a879/128
+                                    Auf Verbindung
+ 14    266 fe80::797d:18a9:3dd6:8105/128
+                                    Auf Verbindung
+  1    306 ff00::/8                 Auf Verbindung
+ 11    266 ff00::/8                 Auf Verbindung
+ 14    266 ff00::/8                 Auf Verbindung
+===========================================================================
+Ständige Routen:
+  Keine
+
+
+        Ubuntu: line.trim().startsWith("0.0.0.0")
+
+Kernel IP routing table
+Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
+0.0.0.0         10.211.55.1     0.0.0.0         UG        0 0          0 enp0s5
+10.211.55.0     0.0.0.0         255.255.255.0   U         0 0          0 enp0s5
+169.254.0.0     0.0.0.0         255.255.0.0     U         0 0          0 enp0s5
+
+        Mac: line.trim().startsWith("default")
+
+Routing tables
+
+Internet:
+Destination        Gateway            Flags        Refs      Use   Netif Expire
+default            10.10.56.1         UGSc          109     1893     en0
+10.10.56/24        link#9             UCS             0        0     en0
+10.10.56.1/32      link#9             UCS             3        0     en0
+10.10.56.1         0:90:7f:a2:7a:a3   UHLWIir        39       16     en0   1188
+10.10.56.8/32      link#9             UCS             1        0     en0
+10.10.56.8         8c:85:90:18:6f:a9  UHLWI           0        5     lo0
+10.37.129/24       link#22            UC              1        0   vnic1
+10.211.55/24       link#21            UC              2        0   vnic0
+10.211.55.3        0:1c:42:2e:f3:40   UHLWIi          1        0   vnic0   1120
+10.211.55.4        0:1c:42:ec:9d:4d   UHLWI           0        0   vnic0   1075
+127                127.0.0.1          UCS             0        0     lo0
+127.0.0.1          127.0.0.1          UH             26   320774     lo0
+169.254            link#9             UCS             1        0     en0
+169.254            link#7             UCSI            0        0     en7
+169.254            link#20            UCSI            1        0     en8
+169.254.233.80/32  link#20            UCS             0        0     en8
+169.254.255.255    link#9             UHLSW           6       30     en0
+192.168.0/16       link#7             UCS             1        0     en7
+192.168.0.99/32    link#7             UCS             1        0     en7
+192.168.42.1       link#7             UHLWIi          1       10     en7
+224.0.0/4          link#9             UmCS            3        0     en0
+224.0.0/4          link#7             UmCSI           1        0     en7
+224.0.0/4          link#20            UmCSI           1        0     en8
+224.0.0.251        1:0:5e:0:0:fb      UHmLWI          0      106     en0
+224.0.0.252        1:0:5e:0:0:fc      UHmLWI          0       32     en0
+239.255.255.250    1:0:5e:7f:ff:fa    UHmLWI          0      124     en7
+239.255.255.250    1:0:5e:7f:ff:fa    UHmLWI          0      682     en0
+239.255.255.250    1:0:5e:7f:ff:fa    UHmLWI          0       64     en8
+255.255.255.255/32 link#9             UCS             0        0     en0
+255.255.255.255/32 link#7             UCSI            0        0     en7
+255.255.255.255/32 link#20            UCSI            0        0     en8
+
+Internet6:
+Destination                             Gateway                         Flags         Netif Expire
+default                                 fe80::%utun0                    UGcI          utun0
+default                                 fe80::%utun1                    UGcI          utun1
+::1                                     ::1                             UHL             lo0
+fe80::%lo0/64                           fe80::1%lo0                     UcI             lo0
+fe80::1%lo0                             link#1                          UHLI            lo0
+fe80::%en7/64                           link#7                          UCI             en7
+fe80::4a8:61b9:6131:3848%en7            48:65:ee:12:d2:c7               UHLI            lo0
+fe80::%en5/64                           link#8                          UCI             en5
+fe80::aede:48ff:fe00:1122%en5           ac:de:48:0:11:22                UHLI            lo0
+fe80::aede:48ff:fe33:4455%en5           ac:de:48:33:44:55               UHLWIi          en5
+fe80::%en0/64                           link#9                          UCI             en0
+fe80::10cf:c2ea:7baa:626b%en0           8c:85:90:18:6f:a9               UHLI            lo0
+fe80::%awdl0/64                         link#11                         UCI           awdl0
+fe80::cbd:62ff:fe3e:406c%awdl0          e:bd:62:3e:40:6c                UHLI            lo0
+fe80::%utun0/64                         fe80::3a17:f866:7728:6e8d%utun0 UcI           utun0
+fe80::3a17:f866:7728:6e8d%utun0         link#17                         UHLI            lo0
+fe80::%utun1/64                         fe80::eb7a:3ecf:562c:167b%utun1 UcI           utun1
+fe80::eb7a:3ecf:562c:167b%utun1         link#18                         UHLI            lo0
+fe80::%en8/64                           link#20                         UCI             en8
+fe80::415:f342:498d:14d2%en8            42:4d:7f:8a:b3:83               UHLI            lo0
+ff01::%lo0/32                           ::1                             UmCI            lo0
+ff01::%en7/32                           link#7                          UmCI            en7
+ff01::%en5/32                           link#8                          UmCI            en5
+ff01::%en0/32                           link#9                          UmCI            en0
+ff01::%awdl0/32                         link#11                         UmCI          awdl0
+ff01::%utun0/32                         fe80::3a17:f866:7728:6e8d%utun0 UmCI          utun0
+ff01::%utun1/32                         fe80::eb7a:3ecf:562c:167b%utun1 UmCI          utun1
+ff01::%en8/32                           link#20                         UmCI            en8
+ff02::%lo0/32                           ::1                             UmCI            lo0
+ff02::%en7/32                           link#7                          UmCI            en7
+ff02::%en5/32                           link#8                          UmCI            en5
+ff02::%en0/32                           link#9                          UmCI            en0
+ff02::%awdl0/32                         link#11                         UmCI          awdl0
+ff02::%utun0/32                         fe80::3a17:f866:7728:6e8d%utun0 UmCI          utun0
+ff02::%utun1/32                         fe80::eb7a:3ecf:562c:167b%utun1 UmCI          utun1
+ff02::%en8/32                           link#20                         UmCI            en8
+
+
+         */
         return null;
     }
 
+    private static class FirstHop {
+        private final PcapNetworkInterface networkInterface;
+        private final InetAddress localInetAddress;
+        private final LinkLayerAddress localMacAddress;
+        private final LinkLayerAddress remoteMacAddress;
+
+        private FirstHop(PcapNetworkInterface networkInterface, InetAddress localInetAddress, LinkLayerAddress localMacAddress,
+                         LinkLayerAddress remoteMacAddress) {
+            this.networkInterface = networkInterface;
+            this.localInetAddress = localInetAddress;
+            this.localMacAddress = localMacAddress;
+            this.remoteMacAddress = remoteMacAddress;
+        }
+    }
+
 }
diff --git a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawSocketTest.java b/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawSocketTest.java
index 1434f67..36674f4 100644
--- a/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawSocketTest.java
+++ b/plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawSocketTest.java
@@ -15,18 +15,32 @@
  */
 package org.apache.plc4x.java.utils.rawsockets;
 
+import org.junit.Test;
+import org.pcap4j.core.PcapAddress;
+import org.pcap4j.core.PcapNetworkInterface;
+import org.pcap4j.core.Pcaps;
+
+import java.net.Inet4Address;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import static org.junit.Assert.fail;
 
 public class RawSocketTest {
 
-    public static void main(String[] args) throws Exception {
+    @Test
+    public void testPingPacket() throws Exception {
         // Protocol number 1 = ICMP (Ping)
         RawSocket rawSocket = new RawSocket(1);
 
+        CompletableFuture<Boolean> result = new CompletableFuture<>();
         // Simply print the result to the console
         rawSocket.addListener(rawData -> {
             System.out.println("Got response:");
             System.out.println(Arrays.toString(rawData));
+            result.complete(true);
         });
 
         // Connect to the remote address
@@ -34,7 +48,18 @@ public class RawSocketTest {
         // does the ARP MAC address lookup and sets up the listener
         // to accept packets sent from that mac address to the
         // current machines with the given IP protocol id.
-        rawSocket.connect("10.10.56.1");
+        // In this test we simply look for a real network device
+        // (The loopback device doesn't have a MAC address)
+        // and ping itself.
+        for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
+            if(!dev.getLinkLayerAddresses().isEmpty()) {
+                for (PcapAddress pcapAddress : dev.getAddresses()) {
+                    if(pcapAddress.getAddress() instanceof Inet4Address) {
+                        rawSocket.connect("plc4x.apache.org");
+                    }
+                }
+            }
+        }
 
         // Simple ICMP (Ping packet)
         byte[] rawData = new byte[] {
@@ -51,6 +76,12 @@ public class RawSocketTest {
 
         // Write the raw packet to the remote host.
         rawSocket.write(rawData);
+
+        try {
+            result.get(3, TimeUnit.SECONDS);
+        } catch (TimeoutException e) {
+            fail("Request timed out.");
+        }
     }
 
 }

-- 
To stop receiving notification emails like this one, please contact
cdutz@apache.org.