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.location.MyLocationManager; import de.tudarmstadt.informatik.hostage.logging.AttackRecord; import de.tudarmstadt.informatik.hostage.logging.Logger; import de.tudarmstadt.informatik.hostage.logging.MessageRecord; import de.tudarmstadt.informatik.hostage.logging.MessageRecord.TYPE; import de.tudarmstadt.informatik.hostage.logging.NetworkRecord; import de.tudarmstadt.informatik.hostage.nio.Reader; import de.tudarmstadt.informatik.hostage.nio.Writer; import de.tudarmstadt.informatik.hostage.protocol.GHOST; 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 Handler implements Runnable { /** Time until the socket throws a time out. The time is in milliseconds. */ private int TIMEOUT; private Hostage 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 Listener 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 Handler(Hostage service, Listener listener, Protocol protocol, Socket client) { this.service = service; this.listener = listener; this.protocol = protocol; if (protocol.toString().equals("GHOST")) { ((GHOST) protocol).setAttackerIP(client.getInetAddress()); ((GHOST) protocol).setCurrentPort(listener.getPort()); } this.client = client; this.thread = new Thread(this); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(service); TIMEOUT = pref.getInt("timeout", 30) * 1000; 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); Logger.log(Hostage.getContext(), createNetworkRecord()); Logger.log(Hostage.getContext(), createAttackRecord()); thread.start(); } /** * 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(); } /** * 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) { } listener.refreshHandlers(); } /** * 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(); } /** * 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(); } /** * 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 a MessageRecord 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 MessageRecord createMessageRecord(TYPE type, String packet) { MessageRecord record = new MessageRecord(); record.setId(message_id++); record.setAttack_id(attack_id); record.setType(type); record.setTimestamp(System.currentTimeMillis()); record.setPacket(packet); return record; } /** * Creates a AttackRecord for a specific attack from a client. * * @return The AttackRecord representing the attack. */ protected AttackRecord createAttackRecord() { AttackRecord record = new AttackRecord(); record.setAttack_id(attack_id); record.setProtocol(protocol.toString()); record.setExternalIP(externalIP); record.setLocalIP(client.getLocalAddress().getHostAddress()); record.setLocalPort(protocol.getPort()); record.setRemoteIP(client.getInetAddress().getHostAddress()); record.setRemotePort(client.getPort()); record.setBssid(BSSID); return record; } /** * Creates a NetworkRecord containing information about the current network. * * @return The NetworkRecord representing the current network. */ protected NetworkRecord createNetworkRecord() { NetworkRecord record = new NetworkRecord(); record.setBssid(BSSID); record.setSsid(SSID); 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; } /** * 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 { Reader reader = new Reader(in, protocol.toString()); Writer writer = new Writer(out); Packet inputLine; List outputLine; if (protocol.whoTalksFirst() == TALK_FIRST.SERVER) { outputLine = protocol.processMessage(null); writer.write(outputLine); for (Packet o : outputLine) { Logger.log(Hostage.getContext(), createMessageRecord(TYPE.SEND, o.toString())); } } while (!thread.isInterrupted() && (inputLine = reader.read()) != null) { outputLine = protocol.processMessage(inputLine); Logger.log(Hostage.getContext(), createMessageRecord(TYPE.RECEIVE, inputLine.toString())); if (outputLine != null) { writer.write(outputLine); for (Packet o : outputLine) { Logger.log(Hostage.getContext(), createMessageRecord(TYPE.SEND, o.toString())); } } if (protocol.isClosed()) { break; } } } }