Browse Source

Adds IcMPv6 Ping Protocol and checksum

Andreas T. Meyer-Berg 5 years ago
parent
commit
27effd0b95

+ 2 - 0
src/main/java/de/tu_darmstadt/tk/SmartHomeNetworkSim/core/ImportConfiguration.java

@@ -3,6 +3,7 @@ package de.tu_darmstadt.tk.SmartHomeNetworkSim.core;
 import java.util.LinkedList;
 
 import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.MQTT_protocol;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.Ping_protocol;
 import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimpleLink;
 import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.simpleImplementation.SimpleProtocol;
 
@@ -35,6 +36,7 @@ public class ImportConfiguration {
 	public ImportConfiguration() {
 		//Add the default Classes
 		standardProtocols.add(MQTT_protocol.class);
+		standardProtocols.add(Ping_protocol.class);
 		standardProtocols.add(SimpleProtocol.class);
 		
 		standardLinks.add(SimpleLink.class);

+ 118 - 0
src/main/java/de/tu_darmstadt/tk/SmartHomeNetworkSim/core/protocols/Ping_protocol.java

@@ -0,0 +1,118 @@
+package de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Protocol;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.packets.Ping_packet;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.Pair;
+
+/**
+ * Ping Protocol which sends simple Ping requests to the target
+ * 
+ * @author Andreas T. Meyer-Berg
+ */
+public class Ping_protocol implements Protocol {
+
+	/**
+	 * Sender / Source of the Ping Request
+	 */
+	private Port sender;
+	/**
+	 * Target / Destination of the Ping Request
+	 */
+	private Port target;
+	/**
+	 * Creates a new Ping Protocol
+	 */
+	public Ping_protocol(){
+		sender = null;
+		target = null;
+	}
+	short sequence = 0;
+	@Override
+	public Collection<Packet> generateNextPakets(Port port, long timestep, boolean packetLost) {
+		/**
+		 * Packets which are generated during this timestep
+		 */
+		LinkedList<Packet> packets = new LinkedList<>();
+		if(port == null || port.getStatus() != Port.SENDING)
+			return packets;
+		/**
+		 * Update trigger time
+		 */
+		port.setLastTrigger(timestep);
+		
+		if(port == sender && target != null){
+			packets.add(new Ping_packet(timestep, sender, target, Ping_packet.EchoRequest, sequence));
+			if(target.getStatus() >= Port.OPEN){
+				packets.add(new Ping_packet(timestep, target, sender, Ping_packet.EchoReply, sequence));
+			}
+		}
+		else if(port == target && sender != null){
+			packets.add(new Ping_packet(timestep, target, sender, Ping_packet.EchoRequest, sequence));
+			if(sender.getStatus() >= Port.OPEN){
+				packets.add(new Ping_packet(timestep, sender, target, Ping_packet.EchoReply, sequence));
+			}
+		}
+		return packets;
+	}
+
+	@Override
+	public String[] getRoles() {
+		return new String[]{"Sender", "Target"};
+	}
+
+	@Override
+	public Collection<Port> getDevicesWithRole(int role) {
+		/**
+		 * Devices of the given Role
+		 */
+		LinkedList<Port> devicesOfRole = new LinkedList<Port>();
+		switch (role) {
+		case 0:
+			if(sender != null)
+				devicesOfRole.add(sender);
+			break;
+		case 1:
+			if(target != null)
+				devicesOfRole.add(target);
+			break;
+		default:
+			return null; 
+		}
+		return devicesOfRole;
+	}
+
+	@Override
+	public boolean addDeviceOfRole(Port device, int role) {
+		if(role == 0 &&sender == null)
+			sender = device;
+		else if(role == 1 && target == null)
+			target = device;
+		else
+			return false;
+		return true;
+	}
+
+	@Override
+	public void removeDevice(Port device) {
+		if(sender == device)
+			sender = null;
+		if(target == device)
+			target = null;
+	}
+
+	@Override
+	public String getName() {
+		return "Ping";
+	}
+
+	@Override
+	public Collection<Pair<Port, Port>> getDeletedTopology() {
+		return new LinkedList<Pair<Port, Port>>();
+	}
+
+}

+ 171 - 0
src/main/java/de/tu_darmstadt/tk/SmartHomeNetworkSim/core/protocols/packets/Ping_packet.java

@@ -0,0 +1,171 @@
+package de.tu_darmstadt.tk.SmartHomeNetworkSim.core.protocols.packets;
+
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Packet;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.Port;
+import de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util.ICMPv6Checksum;
+/**
+ * IcMPv6 Ping Packages
+ * 
+ * @see http://www.networksorcery.com/enp/protocol/icmpv6.htm http://www.networksorcery.com/enp/rfc/rfc4443.txt
+ * @author Andreas T. Meyer-Berg
+ */
+public class Ping_packet extends Packet {
+	
+	/**
+	 * Echo Request type
+	 */
+	public static byte EchoRequest = 0x10; // 128;
+	/**
+	 * Echo reply type
+	 */
+	public static byte EchoReply = 0x11; //129;
+	/**
+	 * Type of the packet
+	 */
+	private byte type;
+	/**
+	 * Code byte
+	 */
+	private byte code = 0x00;
+	/**
+	 * Checksum
+	 */
+	private byte[] checksum = new byte[]{0x00,0x00};
+	/**
+	 * Identifier
+	 */
+	private byte[] id = new byte[]{0x00,0x00};
+	/**
+	 * Sequence Number
+	 */
+	private byte[] sequenceNumber = new byte[]{0x00,0x00};
+	/**
+	 * Payload data
+	 */
+	private byte[] data = "abcdefghijklmnopqrstuvwabcdefghi".getBytes();
+	
+	/*
+	 *  0                   1                   2                   3
+     *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |     Type      |     Code      |          Checksum             |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |           Identifier          |        Sequence Number        |
+     * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+     * |     Data ...
+     * +-+-+-+-+-
+	 */
+	
+	/* Failure codes on response
+	 * 0 network unreachable
+	 * 1 host unreachable
+	 * 2 protocol unreachable
+	 * 3 port unreachable
+	 * 4 fragmentation needed but don‘t fragment bit set
+	 * 5 source route failed
+	 * 6 destination network unknown
+	 * 7 destination host unknown
+	 * 8 source host isolated
+	 * 9 destination network administratively prohibited
+	 * 10 destination host administratively prohibited
+	 * 11 network unreachable for requested type of service
+	 * 12 host unreachable for requested type of service
+	 * 13 communication administratively prohibited by filtering
+	 * 14 host precedence violation
+	 * 15 precedence cutoff in effect
+	 */
+	
+	/**
+	 * Ping package
+	 * @param timestamp time the package was sent
+	 * @param source source of the package
+	 * @param destination destination of the package
+	 * @param type type, should be EchoRequest, EchoReply
+	 * @param identifier number in the sequence, specified by sender
+	 * @param sequenceNumber number in the sequence, specified by sender
+	 */
+	public Ping_packet(long timestamp, Port source, Port destination, byte type, short identifier, short sequenceNumber) {
+		super(timestamp, source, destination);
+		this.type = type;
+		this.id = new byte[2];
+		id[0] =  (byte)(identifier & 0xff);
+		id[1] =  (byte)((identifier>>8) & 0xff);
+		this.sequenceNumber[0] = (byte)(sequenceNumber & 0xff);
+		this.sequenceNumber[1] = (byte)((sequenceNumber >> 8) & 0xff);
+	}
+	
+	/**
+	 * Ping package without identifier
+	 * @param timestamp time the package was sent
+	 * @param source source of the package
+	 * @param destination destination of the package
+	 * @param type type, should be EchoRequest, EchoReply
+	 * @param sequenceNumber number in the sequence, specified by sender
+	 */
+	public Ping_packet(long timestamp, Port source, Port destination, byte type, short sequenceNumber) {
+		super(timestamp, source, destination);
+		this.type = type;
+		this.id = new byte[]{0x00, 0x00};
+		this.sequenceNumber[0] = (byte)(sequenceNumber & 0xff);
+		this.sequenceNumber[1] = (byte)((sequenceNumber >> 8) & 0xff);
+	}
+
+	@Override
+	public byte[] dumpBytes() {
+		byte[] bytes = new byte[8+data.length];
+		//Checksum cleared for calculation
+		byte[] header = new byte[]{type,code,0x00,0x00,id[0],id[1],sequenceNumber[0],sequenceNumber[1]};
+		int i;
+		for(i = 0; i < 8; i++)
+			bytes[i] = header[i];
+		for(int j=0;j<data.length;j++){
+			bytes[i]=data[j];
+			i++;
+		}
+		/**
+		 * checksum
+		 */
+		long sum = ICMPv6Checksum.calculateChecksum(bytes);
+		checksum[0] = (byte)(sum & 0xff);
+		checksum[1] = (byte)(sum>>8 & 0xff);
+		
+		bytes[2] = checksum[0];
+		bytes[3] = checksum[1];
+		
+		return bytes;
+	}
+
+	@Override
+	public String getTextualRepresentation() {
+		return "[Ping: "+getType()+"; time:"+timestamp+"; source:"+source.getOwner().getName()+"; destination:"+destination.getOwner().getName()+"; Payload: "+getPayload()+"]";
+	}
+
+	@Override
+	public String getPayload() {
+		return new String(data);
+	}
+	
+	/**
+	 * Type as String
+	 * 
+	 * @return String representation of the Type
+	 */
+	private String getType(){
+		if(type == EchoRequest)
+			return "Ping";
+		if(type == EchoReply)
+			return "Pong";
+		return "unknown";
+	}
+	
+	/**
+	 * Create package and checksum
+	 * @param args unused
+	 */
+	public static void main(String[] args) {
+		Ping_packet pinPacket = new Ping_packet(1000, null, null, EchoRequest, (short) 12);
+		byte[] bytes = pinPacket.dumpBytes();
+		for(int i = 0; i<bytes.length; i++)
+			System.out.println(bytes[i]);
+	}
+}

+ 70 - 0
src/main/java/de/tu_darmstadt/tk/SmartHomeNetworkSim/core/util/ICMPv6Checksum.java

@@ -0,0 +1,70 @@
+package de.tu_darmstadt.tk.SmartHomeNetworkSim.core.util;
+
+/**
+ * Class for calculating checksums, taken from stackoverflow 
+ * 
+ *
+ * @author Andreas T. Meyer-Berg
+ */
+public class ICMPv6Checksum {
+
+	/**
+	 * Calculate the Internet Checksum of a buffer (RFC 1071 -
+	 * http://www.faqs.org/rfcs/rfc1071.html) Algorithm is 1) apply a 16-bit 1's
+	 * complement sum over all octets (adjacent 8-bit pairs [A,B], final odd
+	 * length is [A,0]) 2) apply 1's complement to this final sum
+	 *
+	 * Notes: 1's complement is bitwise NOT of positive value. Ensure that any
+	 * carry bits are added back to avoid off-by-one errors
+	 *
+	 *
+	 * @param buf
+	 *            The message
+	 * @return The checksum
+	 * @author Gary Rowe (https://stackoverflow.com/users/396747/gary-rowe)
+	 * @see https://stackoverflow.com/questions/4113890/how-to-calculate-the-internet-checksum-from-a-byte-in-java
+	 */
+	public static long calculateChecksum(byte[] buf) {
+		int length = buf.length;
+		int i = 0;
+
+		long sum = 0;
+		long data;
+
+		// Handle all pairs
+		while (length > 1) {
+			// Corrected to include @Andy's edits and various comments on Stack
+			// Overflow
+			data = (((buf[i] << 8) & 0xFF00) | ((buf[i + 1]) & 0xFF));
+			sum += data;
+			// 1's complement carry bit correction in 16-bits (detecting sign
+			// extension)
+			if ((sum & 0xFFFF0000) > 0) {
+				sum = sum & 0xFFFF;
+				sum += 1;
+			}
+
+			i += 2;
+			length -= 2;
+		}
+
+		// Handle remaining byte in odd length buffers
+		if (length > 0) {
+			// Corrected to include @Andy's edits and various comments on Stack
+			// Overflow
+			sum += (buf[i] << 8 & 0xFF00);
+			// 1's complement carry bit correction in 16-bits (detecting sign
+			// extension)
+			if ((sum & 0xFFFF0000) > 0) {
+				sum = sum & 0xFFFF;
+				sum += 1;
+			}
+		}
+
+		// Final 1's complement value correction to 16-bits
+		sum = ~sum;
+		sum = sum & 0xFFFF;
+		return sum;
+
+	}
+}