Unsupported library that attempts to punch holes through NAT
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

NatTraverser.java 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * To change this template, choose Tools | Templates
  3. * and open the template in the editor.
  4. */
  5. package com.md87.nat;
  6. import de.javawi.jstun.attribute.MappedAddress;
  7. import de.javawi.jstun.attribute.MessageAttribute;
  8. import de.javawi.jstun.attribute.MessageAttributeException;
  9. import de.javawi.jstun.attribute.MessageAttributeParsingException;
  10. import de.javawi.jstun.header.MessageHeader;
  11. import de.javawi.jstun.header.MessageHeaderParsingException;
  12. import de.javawi.jstun.test.DiscoveryInfo;
  13. import de.javawi.jstun.test.DiscoveryTest;
  14. import de.javawi.jstun.util.UtilityException;
  15. import java.io.IOException;
  16. import java.net.DatagramPacket;
  17. import java.net.DatagramSocket;
  18. import java.net.InetAddress;
  19. import java.net.InetSocketAddress;
  20. import java.net.NetworkInterface;
  21. import java.net.SocketException;
  22. import java.util.Enumeration;
  23. import java.util.HashMap;
  24. import java.util.Map;
  25. import java.util.concurrent.Semaphore;
  26. /**
  27. *
  28. * @author chris
  29. */
  30. public class NatTraverser {
  31. protected final CommsAgent agent;
  32. protected InetAddress address;
  33. protected DiscoveryInfo result;
  34. protected NatType theirType;
  35. protected NatType ourType;
  36. public NatTraverser(final CommsAgent agent) {
  37. this.agent = agent;
  38. }
  39. public void setInetAddress(final InetAddress address) {
  40. this.address = address;
  41. this.result = getDiscoveryInfo(address);
  42. addressUpdated();
  43. }
  44. public void findBestInetAddress() {
  45. final Semaphore threadSem = new Semaphore(0);
  46. NatType bestType = null;
  47. Map.Entry<InetAddress, DiscoveryInfo> best = null;
  48. for (final Map.Entry<InetAddress, DiscoveryInfo> info : getDiscoveryInfos().entrySet()) {
  49. if (info.getValue() == null) {
  50. return;
  51. }
  52. final NatType thisType = getTypeFromDI(info.getValue());
  53. if (thisType != null &&
  54. (bestType == null || thisType.ordinal() < bestType.ordinal())) {
  55. bestType = thisType;
  56. best = info;
  57. }
  58. }
  59. if (best != null) {
  60. this.address = best.getKey();
  61. this.result = best.getValue();
  62. addressUpdated();
  63. }
  64. }
  65. protected void addressUpdated() {
  66. try {
  67. ourType = getTypeFromDI(result);
  68. System.out.println("Using local IP: " + result.getLocalIP().getHostAddress()
  69. + " (remote: " + result.getPublicIP().getHostAddress() + "; iface: "
  70. + NetworkInterface.getByInetAddress(result.getLocalIP()).getName()
  71. + "; type: " + ourType + ")");
  72. agent.sendNATType(ourType);
  73. theirType = agent.readNATType();
  74. } catch (SocketException ex) {
  75. // Meh
  76. }
  77. }
  78. public DatagramSocket traverse() throws UnsupportedOperationException,
  79. SocketException, UtilityException, IOException,
  80. MessageHeaderParsingException, MessageAttributeParsingException, InterruptedException {
  81. if (!getTypeFromDI(result).canTraverseWith(theirType)) {
  82. throw new UnsupportedOperationException("Cannot traverse "
  83. + "between a " + ourType + " network and a "
  84. + theirType + " network.");
  85. }
  86. final DatagramSocket sock
  87. = new DatagramSocket(new InetSocketAddress(address, 0));
  88. sock.connect(InetAddress.getByName("stun.dmdirc.com"), 3478);
  89. MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
  90. sendMH.generateTransactionID();
  91. byte[] data = sendMH.getBytes();
  92. DatagramPacket send = new DatagramPacket(data, data.length);
  93. sock.send(send);
  94. MessageHeader receiveMH = new MessageHeader();
  95. while (!(receiveMH.equalTransactionID(sendMH))) {
  96. DatagramPacket receive = new DatagramPacket(new byte[200], 200);
  97. sock.receive(receive);
  98. receiveMH = MessageHeader.parseHeader(receive.getData());
  99. receiveMH.parseAttributes(receive.getData());
  100. }
  101. final MappedAddress ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
  102. System.out.println("I'm listening on " + address.getHostAddress() + ":"
  103. + sock.getLocalPort() + ". STUN server says I'm sending packets from "
  104. + ma.getAddress().getInetAddress().getHostAddress() + ":"
  105. + ma.getPort());
  106. agent.sendAddress(ma.getAddress().getInetAddress());
  107. agent.sendPort(ma.getPort());
  108. final InetAddress raddr = agent.readAddress();
  109. final int rport = agent.readPort();
  110. sock.disconnect();
  111. sock.connect(raddr, rport);
  112. boolean cont;
  113. do {
  114. cont = false;
  115. DatagramPacket p = new DatagramPacket("NatTraverser!".getBytes(), 13);
  116. try {
  117. sock.send(p);
  118. p = new DatagramPacket(new byte[13], 13);
  119. sock.receive(p);
  120. } catch (IOException ex) {
  121. ex.printStackTrace();
  122. cont = true;
  123. Thread.sleep(500);
  124. }
  125. } while (cont);
  126. return sock;
  127. }
  128. public static NatType getTypeFromDI(final DiscoveryInfo info) {
  129. if (info.isFullCone()) {
  130. return NatType.FULL_CONE;
  131. } else if (info.isOpenAccess()) {
  132. return NatType.OPEN;
  133. } else if (info.isPortRestrictedCone()) {
  134. return NatType.PORT_RESTRICTED_CONE;
  135. } else if (info.isRestrictedCone()) {
  136. return NatType.RESTRICTED_CONE;
  137. } else if (info.isSymmetric()) {
  138. return NatType.SYMMETRIC;
  139. } else {
  140. return null;
  141. }
  142. }
  143. protected Map<InetAddress, DiscoveryInfo> getDiscoveryInfos() {
  144. final Map<InetAddress, DiscoveryInfo> res
  145. = new HashMap<InetAddress, DiscoveryInfo>();
  146. try {
  147. final Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
  148. while (en.hasMoreElements()) {
  149. final Enumeration<InetAddress> inen = en.nextElement().getInetAddresses();
  150. while (inen.hasMoreElements()) {
  151. final InetAddress ia = inen.nextElement();
  152. res.put(ia, getDiscoveryInfo(ia));
  153. }
  154. }
  155. } catch (SocketException ex) {
  156. // Meh
  157. }
  158. return res;
  159. }
  160. protected DiscoveryInfo getDiscoveryInfo(final InetAddress iaddress) {
  161. try {
  162. return new DiscoveryTest(iaddress, "stun.dmdirc.com", 3478).test();
  163. } catch (IOException ex) {
  164. // Meh
  165. } catch (UtilityException ex) {
  166. // Meh
  167. } catch (MessageAttributeException ex) {
  168. // Meh
  169. } catch (MessageHeaderParsingException ex) {
  170. // Meh
  171. }
  172. return null;
  173. }
  174. }