Simple STUN client in Java

I have found several Java STUN implementations

Java and which Stun libraries should I use?

Exist

See also: STUN, TURN, ICE library for Java

But these are banks with many classes. I want to find something simple in the form of a single method or at least one small class. Like the following python code.

https://github.com/jtriley/pystun/blob/develop/stun/ init .py

A reasonable answer to why STUN in Java is so huge is also acceptable.

+3


source to share


2 answers


A reasonable answer to why STUN in Java is so huge is also acceptable.

This is a reasonable question. 99% of what STUN is just an echo / response protocol for the client to self-detect IP and port mapping as a result of NAT between it and the public Internet. Having created the STUN library in C ++ , I have some understanding.

Think about what is required of the STUN library:

  • A message writer that generates STUN messages using an attribute field schema that not only allows you to create fields in any order, but also allows you to add custom attributes.

  • A message parser that can read such messages and transform the data is a structure that makes sense for code to use. You must do this safely and avoid unhandled exceptions.

  • Socket networking code for sending / receiving such messages. And STUN servers are technically needed to listen on 2 IPs and 2 ports, which makes the networking code for the server more complex.

  • If we just care about binding requests and associated responses, we'll be done. But STUN RFCs also define a suite of NAT classification tests. Therefore, additional state machine logic is needed to make any such library complete.

  • And if the STUN library is fully protected by the security settings provided by the protocol, a certain amount of cryptocodes will be required to encrypt and sign messages.

So by putting it all together into a library that anyone can use for all of STUN's purposes, including mapping address discovery, NAT classification, and ICE negotiation, it starts to evolve rapidly.

You can just compile some socket code that hardcodes the bytes of the bind request and then some hacky parsing to parse the response. It might suit your own needs, but a well-known open source library would never be written that way.



JSTUN is a good start. I have shared some bug fixes and bug fixes with the original author. It doesn't actively support it, but it's a good RFC 3489 implementation. I even hacked it once to work on Android.

To create a STUN binding request in JSTUN.

MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
sendMH.generateTransactionID();

// add an empty ChangeRequest attribute. Not required by the standard, but JSTUN server requires it
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);

byte[] data = sendMH.getBytes();

// not shown - sending the message

      

Then to parse the response back:

byte [] receivedData = new byte[500];

// not shown - socket code that receives the messages into receivedData
receiveMH.parseAttributes(receivedData);
MappedAddress ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);    

      

Then combine the above with some socket code. The best example of combining the above socket code can be found in the source file DiscoveryTest.java. You really need the code in the method of test1()

this class.

+3


source


    MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
    // sendMH.generateTransactionID();

    // add an empty ChangeRequest attribute. Not required by the
    // standard,
    // but JSTUN server requires it

    ChangeRequest changeRequest = new ChangeRequest();
    sendMH.addMessageAttribute(changeRequest);

    byte[] data = sendMH.getBytes();


    s = new DatagramSocket();
    s.setReuseAddress(true);

    DatagramPacket p = new DatagramPacket(data, data.length, InetAddress.getByName("stun.l.google.com"), 19302);
    s.send(p);

    DatagramPacket rp;

    rp = new DatagramPacket(new byte[32], 32);

    s.receive(rp);
    MessageHeader receiveMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingResponse);
    // System.out.println(receiveMH.getTransactionID().toString() + "Size:"
    // + receiveMH.getTransactionID().length);
    receiveMH.parseAttributes(rp.getData());
    MappedAddress ma = (MappedAddress) receiveMH
            .getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
    System.out.println(ma.getAddress()+" "+ma.getPort());

      



+1


source







All Articles