Unsupported library that attempts to punch holes through NAT
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

StunServer.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * This file is part of JSTUN.
  3. *
  4. * Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
  5. * reserved.
  6. *
  7. * This software is licensed under either the GNU Public License (GPL),
  8. * or the Apache 2.0 license. Copies of both license agreements are
  9. * included in this distribution.
  10. */
  11. package de.javawi.jstun.test.demo;
  12. import java.io.IOException;
  13. import java.net.DatagramPacket;
  14. import java.net.DatagramSocket;
  15. import java.net.InetAddress;
  16. import java.net.SocketException;
  17. import java.net.UnknownHostException;
  18. import java.util.Vector;
  19. import java.util.logging.FileHandler;
  20. import java.util.logging.Handler;
  21. import java.util.logging.Level;
  22. import java.util.logging.Logger;
  23. import java.util.logging.SimpleFormatter;
  24. import de.javawi.jstun.attribute.ChangeRequest;
  25. import de.javawi.jstun.attribute.ChangedAddress;
  26. import de.javawi.jstun.attribute.MappedAddress;
  27. import de.javawi.jstun.attribute.MessageAttributeException;
  28. import de.javawi.jstun.attribute.MessageAttributeParsingException;
  29. import de.javawi.jstun.attribute.ResponseAddress;
  30. import de.javawi.jstun.attribute.SourceAddress;
  31. import de.javawi.jstun.attribute.UnknownAttribute;
  32. import de.javawi.jstun.attribute.UnknownMessageAttributeException;
  33. import de.javawi.jstun.attribute.MessageAttributeInterface.MessageAttributeType;
  34. import de.javawi.jstun.header.MessageHeader;
  35. import de.javawi.jstun.header.MessageHeaderParsingException;
  36. import de.javawi.jstun.header.MessageHeaderInterface.MessageHeaderType;
  37. import de.javawi.jstun.util.Address;
  38. import de.javawi.jstun.util.UtilityException;
  39. /*
  40. * This class implements a STUN server as described in RFC 3489.
  41. * The server requires a machine that is dual-homed to be functional.
  42. */
  43. public class StunServer {
  44. private static Logger logger = Logger.getLogger("de.javawi.stun.test.StunServer");
  45. Vector<DatagramSocket> sockets;
  46. public StunServer(int primaryPort, InetAddress primary, int secondaryPort, InetAddress secondary) throws SocketException {
  47. sockets = new Vector<DatagramSocket>();
  48. sockets.add(new DatagramSocket(primaryPort, primary));
  49. sockets.add(new DatagramSocket(secondaryPort, primary));
  50. sockets.add(new DatagramSocket(primaryPort, secondary));
  51. sockets.add(new DatagramSocket(secondaryPort, secondary));
  52. }
  53. public void start() throws SocketException {
  54. for (DatagramSocket socket : sockets) {
  55. socket.setReceiveBufferSize(2000);
  56. StunServerReceiverThread ssrt = new StunServerReceiverThread(socket);
  57. ssrt.start();
  58. }
  59. }
  60. /*
  61. * Inner class to handle incoming packets and react accordingly.
  62. * I decided not to start a thread for every received Binding Request, because the time
  63. * required to receive a Binding Request, parse it, generate a Binding Response and send
  64. * it varies only between 2 and 4 milliseconds. This amount of time is small enough so
  65. * that no extra thread is needed for incoming Binding Request.
  66. */
  67. class StunServerReceiverThread extends Thread {
  68. private DatagramSocket receiverSocket;
  69. private DatagramSocket changedPort;
  70. private DatagramSocket changedIP;
  71. private DatagramSocket changedPortIP;
  72. StunServerReceiverThread(DatagramSocket datagramSocket) {
  73. this.receiverSocket = datagramSocket;
  74. for (DatagramSocket socket : sockets) {
  75. if ((socket.getLocalPort() != receiverSocket.getLocalPort()) &&
  76. (socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
  77. changedPort = socket;
  78. if ((socket.getLocalPort() == receiverSocket.getLocalPort()) &&
  79. (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
  80. changedIP = socket;
  81. if ((socket.getLocalPort() != receiverSocket.getLocalPort()) &&
  82. (!socket.getLocalAddress().equals(receiverSocket.getLocalAddress())))
  83. changedPortIP = socket;
  84. }
  85. }
  86. public void run() {
  87. while (true) {
  88. try {
  89. DatagramPacket receive = new DatagramPacket(new byte[200], 200);
  90. receiverSocket.receive(receive);
  91. logger.finest(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " datagram received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort());
  92. MessageHeader receiveMH = MessageHeader.parseHeader(receive.getData());
  93. try {
  94. receiveMH.parseAttributes(receive.getData());
  95. if (receiveMH.getType() == MessageHeaderType.BindingRequest) {
  96. logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " Binding Request received from " + receive.getAddress().getHostAddress() + ":" + receive.getPort());
  97. ChangeRequest cr = (ChangeRequest) receiveMH.getMessageAttribute(MessageAttributeType.ChangeRequest);
  98. if (cr == null) throw new MessageAttributeException("Message attribute change request is not set.");
  99. ResponseAddress ra = (ResponseAddress) receiveMH.getMessageAttribute(MessageAttributeType.ResponseAddress);
  100. MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingResponse);
  101. sendMH.setTransactionID(receiveMH.getTransactionID());
  102. // Mapped address attribute
  103. MappedAddress ma = new MappedAddress();
  104. ma.setAddress(new Address(receive.getAddress().getAddress()));
  105. ma.setPort(receive.getPort());
  106. sendMH.addMessageAttribute(ma);
  107. // Changed address attribute
  108. ChangedAddress ca = new ChangedAddress();
  109. ca.setAddress(new Address(changedPortIP.getLocalAddress().getAddress()));
  110. ca.setPort(changedPortIP.getLocalPort());
  111. sendMH.addMessageAttribute(ca);
  112. if (cr.isChangePort() && (!cr.isChangeIP())) {
  113. logger.finer("Change port received in Change Request attribute");
  114. // Source address attribute
  115. SourceAddress sa = new SourceAddress();
  116. sa.setAddress(new Address(changedPort.getLocalAddress().getAddress()));
  117. sa.setPort(changedPort.getLocalPort());
  118. sendMH.addMessageAttribute(sa);
  119. byte[] data = sendMH.getBytes();
  120. DatagramPacket send = new DatagramPacket(data, data.length);
  121. if (ra != null) {
  122. send.setPort(ra.getPort());
  123. send.setAddress(ra.getAddress().getInetAddress());
  124. } else {
  125. send.setPort(receive.getPort());
  126. send.setAddress(receive.getAddress());
  127. }
  128. changedPort.send(send);
  129. logger.config(changedPort.getLocalAddress().getHostAddress() + ":" + changedPort.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
  130. } else if ((!cr.isChangePort()) && cr.isChangeIP()) {
  131. logger.finer("Change ip received in Change Request attribute");
  132. // Source address attribute
  133. SourceAddress sa = new SourceAddress();
  134. sa.setAddress(new Address(changedIP.getLocalAddress().getAddress()));
  135. sa.setPort(changedIP.getLocalPort());
  136. sendMH.addMessageAttribute(sa);
  137. byte[] data = sendMH.getBytes();
  138. DatagramPacket send = new DatagramPacket(data, data.length);
  139. if (ra != null) {
  140. send.setPort(ra.getPort());
  141. send.setAddress(ra.getAddress().getInetAddress());
  142. } else {
  143. send.setPort(receive.getPort());
  144. send.setAddress(receive.getAddress());
  145. }
  146. changedIP.send(send);
  147. logger.config(changedIP.getLocalAddress().getHostAddress() + ":" + changedIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
  148. } else if ((!cr.isChangePort()) && (!cr.isChangeIP())) {
  149. logger.finer("Nothing received in Change Request attribute");
  150. // Source address attribute
  151. SourceAddress sa = new SourceAddress();
  152. sa.setAddress(new Address(receiverSocket.getLocalAddress().getAddress()));
  153. sa.setPort(receiverSocket.getLocalPort());
  154. sendMH.addMessageAttribute(sa);
  155. byte[] data = sendMH.getBytes();
  156. DatagramPacket send = new DatagramPacket(data, data.length);
  157. if (ra != null) {
  158. send.setPort(ra.getPort());
  159. send.setAddress(ra.getAddress().getInetAddress());
  160. } else {
  161. send.setPort(receive.getPort());
  162. send.setAddress(receive.getAddress());
  163. }
  164. receiverSocket.send(send);
  165. logger.config(receiverSocket.getLocalAddress().getHostAddress() + ":" + receiverSocket.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
  166. } else if (cr.isChangePort() && cr.isChangeIP()) {
  167. logger.finer("Change port and ip received in Change Request attribute");
  168. // Source address attribute
  169. SourceAddress sa = new SourceAddress();
  170. sa.setAddress(new Address(changedPortIP.getLocalAddress().getAddress()));
  171. sa.setPort(changedPortIP.getLocalPort());
  172. sendMH.addMessageAttribute(sa);
  173. byte[] data = sendMH.getBytes();
  174. DatagramPacket send = new DatagramPacket(data, data.length);
  175. if (ra != null) {
  176. send.setPort(ra.getPort());
  177. send.setAddress(ra.getAddress().getInetAddress());
  178. } else {
  179. send.setPort(receive.getPort());
  180. send.setAddress(receive.getAddress());
  181. }
  182. changedPortIP.send(send);
  183. logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
  184. }
  185. }
  186. } catch (UnknownMessageAttributeException umae) {
  187. umae.printStackTrace();
  188. // Generate Binding error response
  189. MessageHeader sendMH = new MessageHeader(MessageHeaderType.BindingErrorResponse);
  190. sendMH.setTransactionID(receiveMH.getTransactionID());
  191. // Unknown attributes
  192. UnknownAttribute ua = new UnknownAttribute();
  193. ua.addAttribute(umae.getType());
  194. sendMH.addMessageAttribute(ua);
  195. byte[] data = sendMH.getBytes();
  196. DatagramPacket send = new DatagramPacket(data, data.length);
  197. send.setPort(receive.getPort());
  198. send.setAddress(receive.getAddress());
  199. receiverSocket.send(send);
  200. logger.config(changedPortIP.getLocalAddress().getHostAddress() + ":" + changedPortIP.getLocalPort() + " send Binding Error Response to " + send.getAddress().getHostAddress() + ":" + send.getPort());
  201. }
  202. } catch (IOException ioe) {
  203. ioe.printStackTrace();
  204. } catch (MessageAttributeParsingException mape) {
  205. mape.printStackTrace();
  206. } catch (MessageAttributeException mae) {
  207. mae.printStackTrace();
  208. } catch (MessageHeaderParsingException mhpe) {
  209. mhpe.printStackTrace();
  210. } catch (UtilityException ue) {
  211. ue.printStackTrace();
  212. } catch (ArrayIndexOutOfBoundsException aioobe) {
  213. aioobe.printStackTrace();
  214. }
  215. }
  216. }
  217. }
  218. /*
  219. * To invoke the STUN server two IP addresses and two ports are required.
  220. */
  221. public static void main(String args[]) {
  222. try {
  223. if (args.length != 4) {
  224. System.out.println("usage: java de.javawi.jstun.test.demo.StunServer PORT1 IP1 PORT2 IP2");
  225. System.out.println();
  226. System.out.println(" PORT1 - the first port that should be used by the server");
  227. System.out.println(" IP1 - the first ip address that should be used by the server");
  228. System.out.println(" PORT2 - the second port that should be used by the server");
  229. System.out.println(" IP2 - the second ip address that should be used by the server");
  230. System.exit(0);
  231. }
  232. Handler fh = new FileHandler("logging_server.txt");
  233. fh.setFormatter(new SimpleFormatter());
  234. Logger.getLogger("de.javawi.stun").addHandler(fh);
  235. Logger.getLogger("de.javawi.stun").setLevel(Level.ALL);
  236. StunServer ss = new StunServer(Integer.parseInt(args[0]),
  237. InetAddress.getByName(args[1]),
  238. Integer.parseInt(args[2]),
  239. InetAddress.getByName(args[3]));
  240. ss.start();
  241. } catch (SocketException se) {
  242. se.printStackTrace();
  243. } catch (UnknownHostException uhe) {
  244. uhe.printStackTrace();
  245. } catch (IOException ioe) {
  246. ioe.printStackTrace();
  247. }
  248. }
  249. }