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 9e0f79c  - Renamed RawSocket to RawIpSocket and added a new 
RawEthernetSocket, which allows to create raw sockets on ethernet frame level.
9e0f79c is described below

commit 9e0f79c8881afe5dbb07b44cfaec5e44f76c6900
Author: Christofer Dutz <christofer.d...@c-ware.de>
AuthorDate: Mon Mar 12 14:03:18 2018 +0100

    - Renamed RawSocket to RawIpSocket and added a new RawEthernetSocket, which 
allows to create raw sockets on ethernet frame level.
---
 .../java/utils/rawsockets/RawEthernetSocket.java   | 149 +++++++++++++++++++++
 .../{RawSocket.java => RawIpSocket.java}           |   6 +-
 .../{RawSocketTest.java => RawIpSocketTest.java}   |  12 +-
 3 files changed, 158 insertions(+), 9 deletions(-)

diff --git 
a/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawEthernetSocket.java
 
b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawEthernetSocket.java
new file mode 100644
index 0000000..07975c8
--- /dev/null
+++ 
b/plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawEthernetSocket.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2014 The Netty Project
+ *
+ * The Netty Project licenses this file to you under the Apache License,
+ * version 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at:
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.plc4x.java.utils.rawsockets;
+
+import org.pcap4j.core.*;
+import org.pcap4j.packet.*;
+import org.pcap4j.packet.namednumber.*;
+import org.pcap4j.util.LinkLayerAddress;
+import org.pcap4j.util.MacAddress;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * The raw ethernet socket relies on a layer 3 IP protocol implementation for 
finding the
+ * Network device able to connect to a given mac address. In Contrast to the 
{@link RawIpSocket}
+ * the Layer 2 protocol does not support gateways and routers, so we don't 
need the logic
+ * for looking up the default gateway, which makes this implementation a lot 
simpler.
+ */
+public class RawEthernetSocket {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(RawEthernetSocket.class);
+
+    private static final int SNAPLEN = 65536;
+    private static final int READ_TIMEOUT = 10;
+
+    // The EtherType of the protocol we will be communicating in.
+    private final EtherType etherType;
+
+    private PcapNetworkInterface nif;
+    private MacAddress remoteMacAddress;
+    private MacAddress localMacAddress;
+    private ExecutorService pool = Executors.newSingleThreadExecutor();
+    private PcapHandle receiveHandle;
+
+    private final List<RawSocketListener> listeners = new LinkedList<>();
+
+    public RawEthernetSocket(EtherType etherType) {
+        this.etherType = etherType;
+    }
+
+    public void connect(String localMacAddress, String remoteMacAddress) 
throws RawSocketException {
+        try {
+            pool = Executors.newScheduledThreadPool(2);
+
+            this.localMacAddress = MacAddress.getByName(localMacAddress);
+            this.remoteMacAddress = MacAddress.getByName(remoteMacAddress);
+            // Find out which network device is able to connect to the given 
mac address.
+            nif = null;
+            for (PcapNetworkInterface dev : Pcaps.findAllDevs()) {
+                if(!dev.isLoopBack()) {
+                    for (LinkLayerAddress macAddress : 
dev.getLinkLayerAddresses()) {
+                        if(Arrays.equals(macAddress.getAddress(), 
this.localMacAddress.getAddress())) {
+                            nif = dev;
+                        }
+                    }
+                }
+            }
+            if(nif == null) {
+                throw new RawSocketException(
+                    "Unable to find local network device with mac address " + 
remoteMacAddress);
+            }
+
+            // 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 = "ether proto " + etherType.valueAsString() +
+                " and ether src " + this.remoteMacAddress.toString() +
+                " and ether dst " + this.localMacAddress.toString();
+
+            receiveHandle.setFilter(filterString, 
BpfProgram.BpfCompileMode.OPTIMIZE);
+            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 {}",
+                        etherType.valueAsString(), remoteMacAddress, e);
+                }
+            });
+        } catch (PcapNativeException | NotOpenException e) {
+            throw new RawSocketException("Error setting up RawSocket", e);
+        }
+    }
+
+    public void disconnect() throws RawSocketException {
+        // TODO: Terminate all the listeners and the thread pool.
+    }
+
+    public void write(byte[] rawData) throws RawSocketException {
+        try (PcapHandle sendHandle =
+                 nif.openLive(SNAPLEN, 
PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, READ_TIMEOUT)) {
+            UnknownPacket.Builder packetBuilder = new UnknownPacket.Builder();
+            packetBuilder.rawData(rawData);
+
+            EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder();
+            etherBuilder.dstAddr(remoteMacAddress)
+                .srcAddr(localMacAddress)
+                .type(etherType)
+                .paddingAtBuild(true);
+            etherBuilder.payloadBuilder(
+                new AbstractPacket.AbstractBuilder() {
+                    @Override
+                    public Packet build() {
+                        return packetBuilder.build();
+                    }
+                }
+            );
+
+            Packet p = etherBuilder.build();
+            sendHandle.sendPacket(p);
+        } catch (PcapNativeException | NotOpenException e) {
+            throw new RawSocketException("Error sending packet.", e);
+        }
+    }
+
+    public void addListener(RawSocketListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removeListener(RawSocketListener listener) {
+        listeners.remove(listener);
+    }
+
+}
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/RawIpSocket.java
similarity index 99%
rename from 
plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawSocket.java
rename to 
plc4j/utils/raw-sockets/src/main/java/org/apache/plc4x/java/utils/rawsockets/RawIpSocket.java
index 3d23d1f..62b5643 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/RawIpSocket.java
@@ -37,9 +37,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.*;
 
-public class RawSocket {
+public class RawIpSocket {
 
-    private static final Logger logger = 
LoggerFactory.getLogger(RawSocket.class);
+    private static final Logger logger = 
LoggerFactory.getLogger(RawIpSocket.class);
 
     private static final int SNAPLEN = 65536;
     private static final int READ_TIMEOUT = 10;
@@ -59,7 +59,7 @@ public class RawSocket {
 
     private final List<RawSocketListener> listeners = new LinkedList<>();
 
-    public RawSocket(int protocolNumber) {
+    public RawIpSocket(int protocolNumber) {
         this.protocolNumber = protocolNumber;
     }
 
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/RawIpSocketTest.java
similarity index 92%
rename from 
plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawSocketTest.java
rename to 
plc4j/utils/raw-sockets/src/test/java/org/apache/plc4x/java/utils/rawsockets/RawIpSocketTest.java
index b15f0d2..fca6d62 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/RawIpSocketTest.java
@@ -31,7 +31,7 @@ import static org.hamcrest.Matchers.*;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeThat;
 
-public class RawSocketTest {
+public class RawIpSocketTest {
 
     @Test
     @Ignore("Need to make tests run in Docker container first as this test 
requires libpcap or the entrie application to be run as 'root'")
@@ -39,11 +39,11 @@ public class RawSocketTest {
         // TODO: cdutz: jenkins won't allow access on the inet device. Maybe 
try to fix this on a branch.
         assumeThat(System.getenv("PLC4X_BUILD_ON_JENKINS"), 
is(not(equalToIgnoringCase("true"))));
         // Protocol number 1 = ICMP (Ping)
-        RawSocket rawSocket = new RawSocket(1);
+        RawIpSocket rawIpSocket = new RawIpSocket(1);
 
         CompletableFuture<Boolean> result = new CompletableFuture<>();
         // Simply print the result to the console
-        rawSocket.addListener(rawData -> {
+        rawIpSocket.addListener(rawData -> {
             System.out.println("Got response:");
             System.out.println(Arrays.toString(rawData));
             result.complete(true);
@@ -63,13 +63,13 @@ public class RawSocketTest {
                 for (PcapAddress pcapAddress : dev.getAddresses()) {
                     if (pcapAddress.getAddress() instanceof Inet4Address) {
                         System.out.println("Trying to connect on PcapAddress " 
+ pcapAddress);
-                        rawSocket.connect("plc4x.apache.org");
+                        rawIpSocket.connect("plc4x.apache.org");
                     }
                 }
             }
         }
         // On travis we won't have any interface at all so we don't need to 
run there
-        assumeThat(rawSocket, notNullValue());
+        assumeThat(rawIpSocket, notNullValue());
 
         // Simple ICMP (Ping packet)
         byte[] rawData = new byte[]{
@@ -85,7 +85,7 @@ public class RawSocketTest {
             (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, 
(byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x09};
 
         // Write the raw packet to the remote host.
-        rawSocket.write(rawData);
+        rawIpSocket.write(rawData);
 
         try {
             result.get(3, TimeUnit.SECONDS);

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

Reply via email to