HTTP.java 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. package de.tudarmstadt.informatik.hostage.protocol;
  2. import java.io.BufferedReader;
  3. import java.io.InputStreamReader;
  4. import java.net.Socket;
  5. import java.security.SecureRandom;
  6. import java.text.SimpleDateFormat;
  7. import java.util.ArrayList;
  8. import java.util.Calendar;
  9. import java.util.List;
  10. import java.util.Locale;
  11. import java.util.TimeZone;
  12. import android.content.Context;
  13. import android.os.AsyncTask;
  14. import de.tudarmstadt.informatik.hostage.Hostage;
  15. import de.tudarmstadt.informatik.hostage.R;
  16. import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
  17. import de.tudarmstadt.informatik.hostage.wrapper.Packet;
  18. /**
  19. * HTTP protocol. Implementation of RFC document 1945. It can handle the
  20. * following requests: GET, HEAD, TRACE, POST, DELETE. For all other requests
  21. * '400 Bad Request' will be replied.
  22. *
  23. * @author Wulf Pfeiffer
  24. */
  25. public class HTTP implements Protocol {
  26. public HTTP() {
  27. checkProfile();
  28. }
  29. /**
  30. * Get the current time in html header format.
  31. *
  32. * @return the formatted server time.
  33. */
  34. private String getServerTime() {
  35. Calendar calendar = Calendar.getInstance();
  36. SimpleDateFormat dateFormat = new SimpleDateFormat(
  37. "EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
  38. dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
  39. return dateFormat.format(calendar.getTime());
  40. }
  41. /** Whole request that was sent by the client */
  42. private String request = "";
  43. // version stuff
  44. private String[][][] possibleHttpVersions = {
  45. {
  46. { "Apache/2.0." },
  47. { "28", "32", "35", "36", "39", "40", "42", "43", "44",
  48. "45", "46", "47", "48", "49", "50", "51", "52",
  49. "53", "54", "55", "58", "59", "61", "63", "64",
  50. "65" } },
  51. {
  52. { "Apache/2.2." },
  53. { "0", "2", "3", "4", "6", "8", "9", "10", "11", "12",
  54. "13", "14", "15", "16", "17", "18", "19", "20",
  55. "21", "22", "23", "24", "25" } },
  56. { { "Apache/2.3." },
  57. { "4", "5", "6", "8", "10", "11", "12", "14", "15", "16" } },
  58. { { "Apache/2.4." }, { "1", "2", "3", "4", "6" } },
  59. { { "Microsoft-IIS/" }, { "5.1", "7.0", "8.0" } } };
  60. private String serverVersion = initServerVersion();
  61. private String initServerVersion() {
  62. SecureRandom rndm = new SecureRandom();
  63. int majorVersion = rndm.nextInt(possibleHttpVersions.length);
  64. checkProfile();
  65. String version;
  66. String sharedPreferencePath = Hostage.getContext().getString(
  67. R.string.shared_preference_path);
  68. String profile = Hostage
  69. .getContext()
  70. .getSharedPreferences(sharedPreferencePath,
  71. Context.MODE_PRIVATE).getString("os", "");
  72. if (profile.equals("Windows 7") || profile.equals("Windows Server 2008")) {
  73. version = "Microsoft-IIS/7.5";
  74. } else if (profile.equals("Windows Server 2012") || profile.equals("Windows 8")) {
  75. version = "Microsoft-IIS/8.0";
  76. } else if (profile.equals("Windows XP")) {
  77. version = "Microsoft-IIS/5.1";
  78. } else {
  79. version = possibleHttpVersions[majorVersion][0][0]
  80. + possibleHttpVersions[majorVersion][1][rndm
  81. .nextInt(possibleHttpVersions[majorVersion][1].length)];
  82. }
  83. return version;
  84. }
  85. private String httpVersion = "HTTP/1.1";
  86. private static String htmlDocumentContent = HelperUtils.getRandomString(32, false);
  87. private static String htmlTitleContent = HelperUtils.getRandomString(32, false);
  88. // request codes
  89. private static final String OPTIONS = "OPTIONS";
  90. private static final String GET = "GET";
  91. private static final String HEAD = "HEAD";
  92. private static final String POST = "POST";
  93. private static final String PUT = "PUT";
  94. private static final String DELETE = "DELETE";
  95. private static final String TRACE = "TRACE";
  96. private static final String CONNECT = "CONNECT";
  97. private static final String STATUS_CODE_200 = "200 OK\r\n";
  98. private static final String STATUS_CODE_400 = "400 Bad Request\r\n";
  99. private static final String STATUS_CODE_505 = "505 HTTP Version not supported\r\n";
  100. /**
  101. * Sets the html document content for HTTP and HTTPS.
  102. *
  103. * @param htmlDocumentContent
  104. */
  105. public static void setHtmlDocumentContent(String htmlDocumentContent,String htmlTitleContent) {
  106. HTTP.htmlDocumentContent= htmlDocumentContent;
  107. HTTP.htmlTitleContent = htmlTitleContent;
  108. }
  109. // html header pre and suffix
  110. private String headerPrefix = "Date: " + getServerTime() + "\r\n"
  111. + "Server: " + serverVersion + " \r\n"
  112. + "Vary: Accept-Encoding\r\n" + "Content-Length: ";
  113. private String headerSuffix = "\r\n" + "Keep-Alive: timeout=5, max=100\r\n"
  114. + "Connection: Keep-Alive\r\n" + "Content-Type: text/html\r\n"
  115. + "\r\n";
  116. // html website
  117. private String htmlDocument = "<!doctype html>\n" + "<html lang=\"en\">\n"
  118. + "<head>\n" + "<meta charset=\"UTF-8\">\n" + "<title>"
  119. + htmlTitleContent + "</title>\n" + "<body>"
  120. + htmlDocumentContent + "</body>\n" + "</head>\n" + "</html>";
  121. // html error pre and suffix
  122. private String errorHtmlPrefix = "<!doctype html>\n"
  123. + "<html lang=\"en\">\n" + "<head>\n"
  124. + "<meta charset=\"UTF-8\">\n" + "<title>";
  125. private String errorHtmlSuffix = "</title>\n" + "</head>\n" + "</html>";
  126. @Override
  127. public int getPort() {
  128. return 80;
  129. }
  130. @Override
  131. public boolean isClosed() {
  132. return true;
  133. }
  134. @Override
  135. public boolean isSecure() {
  136. return false;
  137. }
  138. @Override
  139. public List<Packet> processMessage(Packet requestPacket) {
  140. String request = null;
  141. if (requestPacket != null) {
  142. request = requestPacket.toString();
  143. }
  144. List<Packet> responsePackets = new ArrayList<Packet>();
  145. this.request = request;
  146. if (request.startsWith("G")) {
  147. //weird if clause but required for https
  148. responsePackets.add(buildPacket(STATUS_CODE_200, GET));
  149. checkProfile();
  150. } else if (!request.contains(httpVersion)) {
  151. responsePackets.add(buildPacket(STATUS_CODE_505, ""));
  152. checkProfile();
  153. } else if (request.contains(GET)) {
  154. checkProfile();
  155. responsePackets.add(buildPacket(STATUS_CODE_200, GET));
  156. } else if (request.contains(HEAD)) {
  157. responsePackets.add(buildPacket(STATUS_CODE_200, HEAD));
  158. checkProfile();
  159. } else if (request.contains(TRACE)) {
  160. responsePackets.add(buildPacket(STATUS_CODE_200, TRACE));
  161. checkProfile();
  162. } else if (request.contains(OPTIONS)) {
  163. responsePackets.add(buildPacket(STATUS_CODE_400, OPTIONS));
  164. } else if (request.contains(POST)) {
  165. responsePackets.add(buildPacket(STATUS_CODE_200, POST));
  166. } else if (request.contains(PUT)) {
  167. responsePackets.add(buildPacket(STATUS_CODE_400, PUT));
  168. } else if (request.contains(DELETE)) {
  169. responsePackets.add(buildPacket(STATUS_CODE_200, DELETE));
  170. } else if (request.contains(CONNECT)) {
  171. responsePackets.add(buildPacket(STATUS_CODE_400, CONNECT));
  172. } else {
  173. responsePackets.add(buildPacket(STATUS_CODE_400, ""));
  174. }
  175. checkProfile();
  176. return responsePackets;
  177. }
  178. private void checkProfile() {
  179. String sharedPreferencePath = Hostage.getContext().getString(
  180. R.string.shared_preference_path);
  181. String profile = Hostage
  182. .getContext()
  183. .getSharedPreferences(sharedPreferencePath,
  184. Context.MODE_PRIVATE).getString("os", "");
  185. //Dynamically changing the landing site based on the nuclear power plant profile
  186. if (profile.equals("Nuclear Power Plant")) {
  187. htmlDocumentContent = "<font color=\"339966\"> <b>Welcome to Siemens Simatic S7 200 Management Portal</b>\n" +
  188. "<img src=\"http://jewishbusinessnews.com/wp-content/uploads/2014/04/siemens-logo.jpg\"alt=\"Siemens Logo\">\n" +
  189. "\n" +
  190. "<form>\n" +
  191. "Username <input type='text' name = 'username'> <br>\n" +
  192. "Password <input type='password' name = 'password'><br>\n" +
  193. "\n" +
  194. "<input type ='button' value='Login'>\n";
  195. htmlTitleContent="Siemens Simatic S7 200 Home";
  196. HTTP.setHtmlDocumentContent(htmlDocumentContent,htmlTitleContent);
  197. }
  198. else {
  199. boolean useQotd = Hostage.getContext().getSharedPreferences(Hostage.getContext().getString(R.string.shared_preference_path), Hostage.MODE_PRIVATE).getBoolean("useQotd", true);
  200. if (useQotd) {
  201. new QotdTask().execute(new String[]{});
  202. }
  203. }
  204. }
  205. @Override
  206. public String toString() {
  207. return "HTTP";
  208. }
  209. @Override
  210. public TALK_FIRST whoTalksFirst() {
  211. return TALK_FIRST.CLIENT;
  212. }
  213. /**
  214. * Builds a html response that can be sent
  215. *
  216. * @param code
  217. * response code that was determined
  218. * @param type
  219. * request type that was sent by the client
  220. * @return the html response
  221. */
  222. private Packet buildPacket(String code, String type) {
  223. String document = "";
  224. if (type.equals(GET)) {
  225. document = htmlDocument;
  226. } else if (type.equals(HEAD) || type.equals(DELETE)) {
  227. document = "";
  228. } else if (type.equals(TRACE)) {
  229. document = request;
  230. } else {
  231. document = errorHtmlPrefix + " " + code + errorHtmlSuffix;
  232. }
  233. return new Packet(httpVersion + " " + code + headerPrefix
  234. + document.length() + headerSuffix + document, toString());
  235. }
  236. /**
  237. * Task for accuiring a qotd from one of four possible servers.
  238. *
  239. * @author Wulf Pfeiffer
  240. */
  241. private class QotdTask extends AsyncTask<String, Void, String> {
  242. @Override
  243. protected String doInBackground(String... unused) {
  244. StringBuffer sb = new StringBuffer();
  245. String sharedPreferencePath = Hostage.getContext().getString(
  246. R.string.shared_preference_path);
  247. String profile = Hostage
  248. .getContext()
  249. .getSharedPreferences(sharedPreferencePath,
  250. Context.MODE_PRIVATE).getString("os", "");
  251. String[] sources = new String[]{"djxmmx.net"}; //, "alpha.mike-r.com"};
  252. SecureRandom rndm = new SecureRandom();
  253. try {
  254. sb.equals("");
  255. Socket client = new Socket(sources[rndm.nextInt(sources.length)], 17);
  256. BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
  257. while (!in.ready())
  258. ;
  259. while (in.ready()) {
  260. sb.append(in.readLine());
  261. }
  262. in.close();
  263. client.close();
  264. } catch (Exception e) {
  265. e.printStackTrace();
  266. }
  267. return sb.toString();
  268. }
  269. @Override
  270. protected void onPostExecute(String result) {
  271. checkProfile();
  272. if (result != null)
  273. HTTP.setHtmlDocumentContent(result,result);
  274. else
  275. HTTP.setHtmlDocumentContent(HelperUtils.getRandomString(32, false),HelperUtils.getRandomString(32, false));
  276. }
  277. }
  278. }