package de.tudarmstadt.informatik.hostage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.List; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.preference.PreferenceManager; import android.util.Log; import de.tudarmstadt.informatik.hostage.io.ByteArrayReaderWriter; import de.tudarmstadt.informatik.hostage.io.ReaderWriter; import de.tudarmstadt.informatik.hostage.io.StringReaderWriter; import de.tudarmstadt.informatik.hostage.logging.Logger; import de.tudarmstadt.informatik.hostage.logging.MyLocationManager; import de.tudarmstadt.informatik.hostage.logging.Record; import de.tudarmstadt.informatik.hostage.logging.Record.TYPE; import de.tudarmstadt.informatik.hostage.protocol.Protocol; import de.tudarmstadt.informatik.hostage.protocol.Protocol.TALK_FIRST; import de.tudarmstadt.informatik.hostage.wrapper.Packet; /** * Abstract class for a connection handler using a given protocol. * * @author Mihai Plasoianu * @author Wulf Pfeiffer */ public class HoneyHandler implements Runnable { /** Time until the socket throws a time out. The time is in milliseconds. */ private int TIMEOUT; /** * Time that a inputstream waits if no content is available to read again * from stream. */ private int SLEEPTIME; private HoneyService service; protected Protocol protocol; private Socket client; protected Thread thread; private int attack_id; private int message_id = 0; private String externalIP; private String BSSID; private String SSID; private HoneyListener listener; /** * Constructor of the class. Initializes class variables for communication * and logging. Then starts itself in a new Thread. * * @param service * The background service. * @param listener * The Listener that called the service. * @param protocol * The protocol on which the handler is running. * @param client * A Socket for the communication with a remote client. */ public HoneyHandler(HoneyService service, HoneyListener listener, Protocol protocol, Socket client) { this.service = service; this.listener = listener; this.protocol = protocol; this.client = client; this.thread = new Thread(this); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(service); SLEEPTIME = pref.getInt("sleeptime", 1); // 1 ms already removes ressource leak TIMEOUT = pref.getInt("timeout", 30) * 1000; // TODO ThreadSicher? getAndIncrementAttackID(pref); SharedPreferences connInfo = service.getSharedPreferences(service.getString(R.string.connection_info), Context.MODE_PRIVATE); BSSID = connInfo.getString(service.getString(R.string.connection_info_bssid), null); SSID = connInfo.getString(service.getString(R.string.connection_info_ssid), null); externalIP = connInfo.getString(service.getString(R.string.connection_info_external_ip), null); setSoTimeout(client); thread.start(); } /** * Set the timeout of the socket to the hard coded time out variable. * * @param client * The socket * @see #TIMEOUT */ private void setSoTimeout(Socket client) { try { client.setSoTimeout(TIMEOUT); } catch (Exception e) { e.printStackTrace(); } } /** * Creates InputStream and OutputStream for the socket. Starts communication * with client. When the client closes the connection or a time out occurs * the handler is finished. */ @Override public void run() { service.notifyUI(this.getClass().getName(), new String[]{service.getString(R.string.broadcast_started), protocol.toString(), Integer.toString(listener.getPort())}); InputStream in; OutputStream out; try { in = client.getInputStream(); out = client.getOutputStream(); talkToClient(in, out); } catch (Exception e) { e.printStackTrace(); } kill(); } /** * Sets the interrupt flag of the thread and tries to close the socket. */ public void kill() { service.notifyUI(this.getClass().getName(), new String[]{service.getString(R.string.broadcast_started),protocol.toString() ,Integer.toString(listener.getPort())}); thread.interrupt(); try { client.close(); Log.i("HoneyHandler", "Socket closed: " + client.isClosed()); } catch (Exception e) { e.printStackTrace(); } finally { } listener.refreshHandlers(); } /** * Determines if the interrupt flag of the thread is set. * * @return True when the flag is set, else false. */ public boolean isTerminated() { return thread.isInterrupted(); } /** * Communicates with a client using the corresponding protocol * implementation. * * @param in * InputStream of the socket. * @param out * OutputStream of the socket. * @throws IOException */ protected void talkToClient(InputStream in, OutputStream out) throws IOException { ReaderWriter stream; if (protocol.getType().equals(byte[].class)) { stream = new ByteArrayReaderWriter(in, out, SLEEPTIME); } else { stream = new StringReaderWriter(in, out); } Packet inputLine; List outputLine; if (protocol.whoTalksFirst() == TALK_FIRST.SERVER) { outputLine = protocol.processMessage(null); stream.write(outputLine); for (Packet o : outputLine) { Logger.log(HoneyService.getContext(), createRecord(TYPE.SEND, o.toString())); } } while (!thread.isInterrupted() && (inputLine = stream.read()) != null) { outputLine = protocol.processMessage(inputLine); Logger.log(HoneyService.getContext(), createRecord(TYPE.RECEIVE, inputLine.toString())); if (outputLine != null) { stream.write(outputLine); for (Packet o : outputLine) { Logger.log(HoneyService.getContext(), createRecord(TYPE.SEND, o.toString())); } } if (protocol.isClosed()) { break; } } } /** * Creates a Record for a message exchanged with a client. * * @param type * The type of the message. * @param packet * The content of the message. * @return The Record representing the communication message. */ protected Record createRecord(TYPE type, String packet) { Record record = new Record(); record.setId(message_id++); record.setAttack_id(attack_id); record.setProtocol(protocol.toString()); record.setType(type); record.setTimestamp(System.currentTimeMillis()); record.setExternalIP(externalIP); record.setLocalIP(client.getLocalAddress().getHostAddress()); record.setLocalHost(client.getLocalAddress().getHostName()); record.setLocalPort(protocol.getDefaultPort()); record.setRemoteIP(client.getInetAddress().getHostAddress()); record.setRemoteHost(client.getInetAddress().getHostName()); record.setRemotePort(client.getPort()); record.setBssid(BSSID); record.setSsid(SSID); record.setPacket(packet); if (MyLocationManager.getNewestLocation() != null) { record.setLatitude(MyLocationManager.getNewestLocation() .getLatitude()); record.setLongitude(MyLocationManager.getNewestLocation() .getLongitude()); record.setAccuracy(MyLocationManager.getNewestLocation() .getAccuracy()); record.setTimestampLocation(MyLocationManager.getNewestLocation() .getTime()); } else { record.setLatitude(0.0); record.setLongitude(0.0); record.setAccuracy(Float.MAX_VALUE); record.setTimestampLocation(0); } return record; } /** * Gets attack ID for the attack. Also increases the attack ID counter by * one. Method is synchronized for thread safety. * * @param pref * The default SharedPreference of the application * @return Unique integer attack ID */ private synchronized void getAndIncrementAttackID(SharedPreferences pref) { Editor editor = pref.edit(); attack_id = pref.getInt("ATTACK_ID_COUNTER", 0); editor.putInt("ATTACK_ID_COUNTER", attack_id + 1); editor.commit(); } }