stun
stun copied to clipboard
Low-level Session Traversal Utilities for NAT (STUN) client and server
stun
Session Traversal Utilities for NAT (STUN) server. Implements RFC5389 with partial support RFC5766, RFC5245, RFC5780.
Support
Install
npm i stun
Usage
const stun = require('stun');
stun.request('stun.l.google.com:19302', (err, res) => {
if (err) {
console.error(err);
} else {
const { address } = res.getXorAddress();
console.log('your ip', address);
}
});
// or with promise
const res = await stun.request('stun.l.google.com:19302');
console.log('your ip', res.getXorAddress().address);
CLI
$ npm i -g stun
$ stun # started on udp/0.0.0.0:3478
API
-
createMessage(type: number [, transaction: Buffer]): StunRequest
-
createTransaction(): Buffer
-
createServer(options: Object): StunServer
-
validateFingerprint(message: StunMessage): bool
-
validateMessageIntegrity(message: StunMessage, key: string): bool
-
request(url: string, [options: RequestOptions], callback: function): void
-
encode(message: StunMessage): Buffer
-
decode(message: Buffer): StunResponse
-
class StunRequest
-
setType(type)
-
setTransactionId(transaction: Buffer): bool
-
addAttribute(type, address: string, port: number)
-
addAttribute(type, value: String|Buffer[, encoding: string = 'utf8'])
-
addAttribute(type, value: number)
-
addAttribute(type, value: array<number>)
-
addAttribute(type, code: number, reason: string)
-
addAddress(ip: string, port: number): StunAddressAttribute
-
addAlternateServer(ip: string, port: number): StunAddressAttribute
-
addXorAddress(ip: string, port: number): StunXorAddressAttribute
-
addUsername(username: string): StunByteStringAttribute
-
addRealm(realm: string): StunByteStringAttribute
-
addNonce(nonce: string): StunByteStringAttribute
-
addSoftware(software: string): StunByteStringAttribute
-
addUnknownAttributes(attributes: number[]): StunUInt16ListAttribute
-
addError(code: number, reason: string): StunErrorCodeAttribute
-
addPriority(priority: number): StunUInt32Attribute
-
addUseCandidate(): StunByteStringAttribute
-
addIceControlled(tiebreaker: Buffer): StunByteStringAttribute
-
addIceControlling(tiebreaker: Buffer): StunByteStringAttribute
-
removeAttribute(type): bool
-
addMessageIntegrity(key: string)
-
addFingerprint()
-
toBuffer(): Buffer
-
-
class StunResponse
-
getAddress(): Object
-
getXorAddress(): Object
-
getAlternateServer(): Object
-
getUsername(): string
-
getError(): Object
-
getRealm(): string
-
getNonce(): string
-
getSoftware(): string
-
getUnknownAttributes(): number[]
-
getMessageIntegrity(): Buffer
-
getFingerprint(): number
-
getPriority(): number
-
getIceControlled(): Buffer
-
getIceControlling(): Buffer
-
-
class StunMessage
-
get type
-
get transactionId
-
isLegacy(): bool
-
getAttribute(type): StunAttribute
-
hasAttribute(type): bool
-
get count: number
-
-
class StunServer
-
new StunServer(socket: dgram.Socket)
-
send(message: StunMessage, port: number, address: string[, cb: function])
-
close()
-
listen(port: number, [address: string], [callback: function()])
-
Event: bindingRequest
-
Event: bindingIndication
-
Event: bindingResponse
-
Event: bindingError
-
Event: close
-
Event: error
-
Event: listening
-
-
class StunAttribute
-
get type
-
get value
-
-
constants: Object
-
class StunError
-
class StunMessageError
-
class StunResponseError
createMessage(type: number [, transaction: Buffer]): StunRequest
Creates an StunRequest
object of the specified type
with random transaction
field. The type
argument is a number that should be a message type. See constants
below.
createTransaction(): Buffer
Create transaction id for STUN message. Follow RFC5389.
createServer(options: Object): StunServer
-
options.type: string
The type of socket. Must be 'udp4' or 'udp6'. Required.
-
options.socket: dgram.Socket
Creates a StunServer
object of the specified type. The type
argument should be 'udp' at the moment. An optional socket
argument should be instance of dgram.Socket
. If socket
is not specifed, the dgram.Socket
will be created with udp4
type and will bound to the "all interfaces" address on a random port.
validateFingerprint(message: StunMessage): bool
Check a FINGERPRINT
attribute if it is specifed.
validateMessageIntegrity(message: StunMessage, key: string): bool
Check a MESSAGE_INTEGRITY
attribute if it is specifed.
stunServer.on('bindingResponse', (msg) => {
if (!stun.validateFingerprint(msg)) {
// do stuff..
}
if (!stun.validateMessageIntegrity(msg, icePassword)) {
// do stuff...
}
})
request(url: string, [options: RequestOptions], callback: function): void
request(url: string, [options: RequestOptions]): Promise
Create a request STUN_BINDING_REQUEST
to stun server, follow RFC5389. The first argument may be a host (stun.example.com
), host with port (stun.example.com:1234
) or host with port and protocol (stun://stun.example.com:1234
). By default, port is 3478.
All options described below are optional.
-
options.server: StunServer
- A stun server to receive responses. -
options.socket: dgram.Socket
- A UDP socket over which the message will be send. -
options.message: StunMessage
- ASTUN_BINDING_REQUEST
message to send. -
options.timeout: number
- Initial retransmission timeout (RTO) in ms, default is 500ms. -
options.maxTimeout: number
- Maximal RTO, default is infinity. -
options.retries: number
- Maximal the number of retries, default is 6
The last argument is a function with 2 arguments err
and res
. It's follow nodejs callback style. The second argument is instance of StunMessage
.
encode(message: StunMessage): Buffer
Encode StunRequest
or StunResponse
into the Buffer.
decode(message: Buffer): StunResponse
Decode the Buffer into a StunResponse
.
const socket = dgram.createSocket({ type: 'udp4' });
socket.on('message', (message) => {
const response = stun.decode(message);
// do stuff ...
});
class StunMessage
The StunMessage
class is an utility that encapsulates the STUN
protocol. This is a base class for StunRequest
and StunResponse
.
-
get
type
-
get
transactionId
Returns the type
and transactionId
fields from the current message.
-
isLegacy(): bool
Returns true if the message confirms to RFC3489 rather than RFC5389.
-
getAttribute(type): StunAttribute
Returns the StunAttribute
attribute of the specified type
. The type
argument is a number that should be an attribute type. See constants
below. Return undefined
if attribute is not exist.
N.B. This method return only first matched attribute. If you want to get another one, try this:
const attributes = Array.from(stunMessage).filter(attribute => attribute.type === STUN_ATTR_MAPPED_ADDRESS);
-
get
count: number
Returns the number of an attributes in the current message.
class StunRequest
The StunRequest
encapsulates outgoing messages of the STUN
protocol. Instances of the StunRequest
can be created using the createMessage()
.
-
setType(type)
Set the type of the message. The type
argument is a number that should be a message type. See constants
below.
-
setTransactionId(transaction: Buffer): bool
Set the transaction id of the message. The transaction
argument should be a Buffer
and have length 12 bytes.
-
addAttribute(type, address: string, port: number)
Adds a type
attribute to the current message. The type
argument should be one of:
-
STUN_ATTR_MAPPED_ADDRESS
-
STUN_ATTR_ALTERNATE_SERVER
-
STUN_ATTR_XOR_MAPPED_ADDRESS
-
STUN_ATTR_RESPONSE_ORIGIN
-
STUN_ATTR_OTHER_ADDRESS
-
STUN_ATTR_XOR_PEER_ADDRESS
-
STUN_ATTR_XOR_RELAYED_ADDRESS
.
stunMsg.addAttribute(STUN_ATTR_XOR_MAPPED_ADDRESS, '8.8.8.8', 19302)
-
addAttribute(type, value: String|Buffer[, encoding: string = 'utf8'])
Adds a type
attribute to the current message. The type
argument should be one of:
-
STUN_ATTR_USERNAME
-
STUN_ATTR_REALM
-
STUN_ATTR_NONCE
-
STUN_ATTR_SOFTWARE
-
STUN_ATTR_ORIGIN
-
STUN_ATTR_USE_CANDIDATE
-
STUN_ATTR_ICE_CONTROLLED
-
STUN_ATTR_ICE_CONTROLLING
-
STUN_ATTR_DATA
-
STUN_ATTR_EVEN_PORT
-
STUN_ATTR_RESERVATION_TOKEN
-
STUN_ATTR_DONT_FRAGMENT
-
STUN_ATTR_PADDING
.
stunMsg.addAttribute(STUN_ATTR_SOFTWARE, 'node/8.2.0 stun/1.0.0')
-
addAttribute(type, value: number)
Adds a type
attribute to the current message. The type
argument should be one of:
-
STUN_ATTR_RETRANSMIT_COUNT
-
STUN_ATTR_PRIORITY
-
STUN_ATTR_NETWORK_INFO
-
STUN_ATTR_NOMINATION
-
STUN_ATTR_CHANNEL_NUMBER
-
STUN_ATTR_LIFETIME
-
STUN_ATTR_REQUESTED_TRANSPORT
-
STUN_ATTR_CHANGE_REQUEST
-
STUN_ATTR_RESPONSE_PORT
.
stunMsg.addAttribute(STUN_ATTR_PRIORITY, 123)
-
addAttribute(type, value: array<number>)
Adds a type
attribute to the current message. The type
argument should be STUN_ATTR_UNKNOWN_ATTRIBUTES
.
stunMsg.addAttribute(STUN_ATTR_UNKNOWN_ATTRIBUTES, [2, 3, 4])
-
addAttribute(type, code: number, reason: string)
Adds a type
attribute to the current message. The type
argument should be STUN_ATTR_ERROR_CODE
.
stunMsg.addAttribute(STUN_ATTR_ERROR_CODE, STUN_CODE_UNAUTHORIZED, STUN_REASON_UNAUTHORIZED)
-
addAddress(ip: string, port: number): StunAddressAttribute
Adds a MAPPED-ADDRESS
attribute to the message.
See RFC5389
-
addAlternateServer(ip: string, port: number): StunAddressAttribute
Adds a ALTERNATE-SERVER
attribute to the message.
See RFC5389
-
addXorAddress(ip: string, port: number): StunXorAddressAttribute
Adds a XOR-MAPPED-ADDRESS
attribute to the message.
See RFC5389
-
addUsername(username: string): StunByteStringAttribute
Adds a USERNAME
attribute to the message.
See RFC5389
-
addRealm(realm: string): StunByteStringAttribute
Adds a REALM
attribute to the message.
See RFC5389
-
addNonce(nonce: string): StunByteStringAttribute
Adds a NONCE
attribute to the message.
See RFC5389
-
addSoftware(software: string): StunByteStringAttribute
Adds a SOFTWARE
attribute to the message.
See RFC5389
-
addUnknownAttributes(attributes: number[]): StunUInt16ListAttribute
Adds a UNKNOWN-ATTRIBUTES
attribute to the message.
See RFC5389
-
addError(code: number, reason: string): StunErrorCodeAttribute
Adds a ERROR-CODE
attribute to the message.
See RFC5389
-
addPriority(priority: number): StunUInt32Attribute
Adds a PRIORITY
attribute to the message.
See RFC8445
-
addUseCandidate(): StunByteStringAttribute
Adds a USE-CANDIDATE
attribute to the message.
See RFC8445
-
addIceControlled(tiebreaker: Buffer): StunByteStringAttribute
Adds a ICE-CONTROLLED
attribute to the message.
See RFC8445
-
addIceControlling(tiebreaker: Buffer): StunByteStringAttribute
Adds a ICE-CONTROLLING
attribute to the message.
See RFC8445
-
removeAttribute(type): bool
Remove a type
attribute from the current message. Returns true if an attribute was removed. The type
argument is a number that should be an attribute type. See constants
below.
-
addMessageIntegrity(key: string)
Adds a MESSAGE-INTEGRITY
attribute that is valid for the current message. The key
is the HMAC key used to generate the cryptographic HMAC hash.
-
addFingerprint()
Adds a FINGERPRINT
attribute that is valid for the current message.
-
toBuffer(): Buffer
Converts a StunMessage
object to the buffer.
class StunServer
The StunServer
class is an EventEmitter that encapsulates a STUN server.
-
new StunServer(socket: dgram.Socket)
Creates a new StunServer
object. The socket
argument should be an instance of dgram.Socket
. The incoming message is silently ignored when it is not a stun
one.
-
send(message: StunMessage, port: number, address: string[, cb: function])
Sends the StunMessage
message on the socket. The destination port
and address
must be specified. An optional callback
function will be called when the message has been sent.
-
close()
Stops the processing of the incoming messages and emits close
event.
-
listen(port: number, [address: string], [callback: function()])
Attempt to listen for messages on a named port
and optional address
. For UDP servers calls socket.bind
under the hood.
-
Event:
bindingRequest
Emitted when the STUN_BINDING_REQUEST
message is available on a socket.
-
Event:
bindingIndication
Emitted when the STUN_BINDING_INDICATION
message is available on a socket.
-
Event:
bindingResponse
Emitted when the STUN_BINDING_RESPONSE
message is available on a socket.
-
Event:
bindingError
Emitted when the STUN_BINDING_ERROR_RESPONSE
message is available on a socket.
-
Event:
close
Emitted when the server closes.
-
Event:
error
Emitted when the server got an invalid message.
-
Event:
listening
The 'listening'
event is emitted whenever a socket begins listening for messages.
class StunAttribute
The StunAttribute
class is an utility for adding an attributes to the StunMessage
message.
-
get
type
Returns the attribute type. See constants
below.
-
get
value
Returns the value of the attribute. It depends on the value type of the attribute.
stunMsg.getAttribute(STUN_ATTR_USERNAME).value // string
stunMsg.getAttribute(STUN_ATTR_PRIORITY).value // number
stunMsg.getAttribute(STUN_ATTR_MAPPED_ADDRESS).value // object
constants: object
These are the types of STUN messages defined in RFC5389:
-
STUN_BINDING_REQUEST
-
STUN_BINDING_INDICATION
-
STUN_BINDING_RESPONSE
-
STUN_BINDING_ERROR_RESPONSE
These are the event names for STUN messages above:
-
STUN_EVENT_BINDING_REQUEST
-
STUN_EVENT_BINDING_INDICATION
-
STUN_EVENT_BINDING_RESPONSE
-
STUN_EVENT_BINDING_ERROR_RESPONSE
These are the types of STUN messages defined in RFC5766:
-
STUN_ALLOCATE_REQUEST
-
STUN_ALLOCATE_RESPONSE
-
STUN_ALLOCATE_ERROR_RESPONSE
-
STUN_REFRESH_REQUEST
-
STUN_REFRESH_RESPONSE
-
STUN_REFRESH_ERROR_RESPONSE
-
STUN_SEND_INDICATION
-
STUN_DATA_INDICATION
-
STUN_CREATE_PERMISSION_REQUEST
-
STUN_CREATE_PERMISSION_RESPONSE
-
STUN_CREATE_PERMISSION_ERROR_RESPONSE
-
STUN_CHANNEL_BIND_REQUEST
-
STUN_CHANNEL_BIND_RESPONSE
-
STUN_CHANNEL_BIND_ERROR_RESPONSE
Thsese are all known STUN attributes, defined in RFC5389 and elsewhere:
-
STUN_ATTR_MAPPED_ADDRESS
-
STUN_ATTR_USERNAME
-
STUN_ATTR_MESSAGE_INTEGRITY
-
STUN_ATTR_ERROR_CODE
-
STUN_ATTR_UNKNOWN_ATTRIBUTES
-
STUN_ATTR_REALM
-
STUN_ATTR_NONCE
-
STUN_ATTR_XOR_MAPPED_ADDRESS
-
STUN_ATTR_SOFTWARE
-
STUN_ATTR_ALTERNATE_SERVER
-
STUN_ATTR_FINGERPRINT
-
STUN_ATTR_ORIGIN
-
STUN_ATTR_RETRANSMIT_COUNT
-
STUN_ATTR_PRIORITY
-
STUN_ATTR_USE_CANDIDATE
-
STUN_ATTR_ICE_CONTROLLED
-
STUN_ATTR_ICE_CONTROLLING
-
STUN_ATTR_NOMINATION
-
STUN_ATTR_NETWORK_INFO
-
STUN_ATTR_CHANNEL_NUMBER
-
STUN_ATTR_LIFETIME
-
STUN_ATTR_XOR_PEER_ADDRESS
-
STUN_ATTR_DATA
-
STUN_ATTR_XOR_RELAYED_ADDRESS
-
STUN_ATTR_EVEN_PORT
-
STUN_ATTR_REQUESTED_TRANSPORT
-
STUN_ATTR_DONT_FRAGMENT
-
STUN_ATTR_RESERVATION_TOKEN
-
STUN_ATTR_CHANGE_REQUEST
-
STUN_ATTR_PADDING
-
STUN_ATTR_RESPONSE_PORT
-
STUN_ATTR_RESPONSE_ORIGIN
-
STUN_ATTR_OTHER_ADDRESS
These are the types of STUN error codes defined in RFC5389 and elsewhere:
-
STUN_CODE_TRY_ALTERNATE
-
STUN_CODE_BAD_REQUEST
-
STUN_CODE_UNAUTHORIZED
-
STUN_CODE_UNKNOWN_ATTRIBUTE
-
STUN_CODE_STALE_CREDENTIALS
-
STUN_CODE_STALE_NONCE
-
STUN_CODE_SERVER_ERROR
-
STUN_CODE_GLOBAL_FAILURE
-
STUN_CODE_ROLE_CONFLICT
-
STUN_CODE_FORBIDDEN
-
STUN_CODE_ALLOCATION_MISMATCH
-
STUN_CODE_WRONG_CREDENTIALS
-
STUN_CODE_UNSUPPORTED_PROTOCOL
-
STUN_CODE_ALLOCATION_QUOTA
-
STUN_CODE_INSUFFICIENT_CAPACITY
These are the strings for the error codes above:
-
STUN_REASON_TRY_ALTERNATE
-
STUN_REASON_BAD_REQUEST
-
STUN_REASON_UNAUTHORIZED
-
STUN_REASON_UNKNOWN_ATTRIBUTE
-
STUN_REASON_STALE_CREDENTIALS
-
STUN_REASON_STALE_NONCE
-
STUN_REASON_SERVER_ERROR
-
STUN_REASON_ROLE_CONFLICT
-
STUN_REASON_FORBIDDEN
-
STUN_REASON_ALLOCATION_MISMATCH
-
STUN_REASON_WRONG_CREDENTIALS
-
STUN_REASON_UNSUPPORTED_PROTOCOL
-
STUN_REASON_ALLOCATION_QUOTA
-
STUN_REASON_INSUFFICIENT_CAPACITY
class StunError
Base class for all generated errors.
-
get
packet: Buffer|StunMessage
Received data.
-
get
sender: object
For UDP, this is an rinfo
attribute.
class StunMessageError
The STUN server may receive invalid messages. This error class represent ones. Inherits from StunError
.
-
get
packet: Buffer
See above.
class StunResponseError
This class represent protocol level errors, for messages with class type ERROR
. Inherits from StunError
.
-
get
packet: StunMessage
See above.
License
MIT, 2017-2019 (c) Dmitriy Tsvettsikh