Stun attributes
This commit is contained in:
parent
2e26deb377
commit
2521ed9f84
|
@ -7,7 +7,7 @@ suite "Stun suite":
|
|||
let msg = @[ 0x00'u8, 0x01, 0x00, 0xa4, 0x21, 0x12, 0xa4, 0x42, 0x75, 0x6a, 0x58, 0x46, 0x42, 0x58, 0x4e, 0x72, 0x6a, 0x50, 0x4d, 0x2b, 0x00, 0x06, 0x00, 0x63, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2b, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2b, 0x76, 0x31, 0x2f, 0x62, 0x71, 0x36, 0x67, 0x69, 0x43, 0x75, 0x4a, 0x38, 0x6e, 0x78, 0x59, 0x46, 0x4a, 0x36, 0x43, 0x63, 0x67, 0x45, 0x59, 0x58, 0x58, 0x2f, 0x78, 0x51, 0x58, 0x56, 0x4c, 0x74, 0x39, 0x71, 0x7a, 0x3a, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2b, 0x77, 0x65, 0x62, 0x72, 0x74, 0x63, 0x2b, 0x76, 0x31, 0x2f, 0x62, 0x71, 0x36, 0x67, 0x69, 0x43, 0x75, 0x4a, 0x38, 0x6e, 0x78, 0x59, 0x46, 0x4a, 0x36, 0x43, 0x63, 0x67, 0x45, 0x59, 0x58, 0x58, 0x2f, 0x78, 0x51, 0x58, 0x56, 0x4c, 0x74, 0x39, 0x71, 0x7a, 0x00, 0xc0, 0x57, 0x00, 0x04, 0x00, 0x00, 0x03, 0xe7, 0x80, 0x2a, 0x00, 0x08, 0x86, 0x63, 0xfd, 0x45, 0xa9, 0xe5, 0x4c, 0xdb, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x00, 0x1e, 0xff, 0x00, 0x08, 0x00, 0x14, 0x16, 0xff, 0x70, 0x8d, 0x97, 0x0b, 0xd6, 0xa3, 0x5b, 0xac, 0x8f, 0x4c, 0x85, 0xe6, 0xa6, 0xac, 0xaa, 0x7a, 0x68, 0x27, 0x80, 0x28, 0x00, 0x04, 0x79, 0x5e, 0x03, 0xd8 ]
|
||||
check msg == encode(StunMessage.decode(msg))
|
||||
|
||||
test "Error while encoding":
|
||||
test "Error while decoding":
|
||||
let msgLengthFailed = @[ 0x00'u8, 0x01, 0x00, 0xa4, 0x21, 0x12, 0xa4, 0x42, 0x75, 0x6a, 0x58, 0x46, 0x42, 0x58, 0x4e, 0x72, 0x6a, 0x50, 0x4d ]
|
||||
expect AssertionDefect: discard StunMessage.decode(msgLengthFailed)
|
||||
let msgAttrFailed = @[ 0x00'u8, 0x01, 0x00, 0x08, 0x21, 0x12, 0xa4, 0x42, 0x75, 0x6a, 0x58, 0x46, 0x42, 0x58, 0x4e, 0x72, 0x6a, 0x50, 0x4d, 0x2b, 0x28, 0x00, 0x05, 0x79, 0x5e, 0x03, 0xd8 ]
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import bitops
|
||||
import chronos, chronicles
|
||||
import binary_serialization
|
||||
import chronos,
|
||||
chronicles,
|
||||
binary_serialization,
|
||||
stew/objects
|
||||
import stunattributes
|
||||
|
||||
export binary_serialization
|
||||
|
||||
logScope:
|
||||
topics = "webrtc stun"
|
||||
|
@ -9,34 +14,18 @@ const
|
|||
msgHeaderSize = 20
|
||||
magicCookieSeq = @[ 0x21'u8, 0x12, 0xa4, 0x42 ]
|
||||
magicCookie = 0x2112a442
|
||||
BindingRequest = 0x0001'u16
|
||||
BindingResponse = 0x0101'u16
|
||||
|
||||
type
|
||||
# Stun Attribute
|
||||
# 0 1 2 3
|
||||
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
# | Type | Length |
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
# | Value (variable) ....
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
StunAttribute* = object
|
||||
attributeType*: uint16
|
||||
length* {.bin_value: it.value.len.}: uint16
|
||||
value* {.bin_len: it.length.}: seq[byte]
|
||||
|
||||
proc decode(T: typedesc[StunAttribute], cnt: seq[byte]): seq[StunAttribute] =
|
||||
proc decode(T: typedesc[RawStunAttribute], cnt: seq[byte]): seq[RawStunAttribute] =
|
||||
const val = @[0, 3, 2, 1]
|
||||
var padding = 0
|
||||
while padding < cnt.len():
|
||||
let attr = Binary.decode(cnt[padding ..^ 1], StunAttribute)
|
||||
let attr = Binary.decode(cnt[padding ..^ 1], RawStunAttribute)
|
||||
result.add(attr)
|
||||
padding += 4 + attr.value.len()
|
||||
padding += val[padding mod 4]
|
||||
|
||||
proc seqAttrLen(s: seq[StunAttribute]): uint16 =
|
||||
for it in s:
|
||||
result = it.length + 4
|
||||
|
||||
type
|
||||
# Stun Header
|
||||
# 0 1 2 3
|
||||
|
@ -50,32 +39,46 @@ type
|
|||
# | Transaction ID (96 bits) |
|
||||
# | |
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
StunMessageInner = object
|
||||
# Message type:
|
||||
# 0x0001: Binding Request
|
||||
# 0x0101: Binding Response
|
||||
# 0x0111: Binding Error Response
|
||||
# 0x0002: Shared Secret Request
|
||||
# 0x0102: Shared Secret Response
|
||||
# 0x0112: Shared Secret Error Response
|
||||
|
||||
RawStunMessage = object
|
||||
msgType: uint16
|
||||
length* {.bin_value: it.content.len().}: uint16
|
||||
magicCookie: uint32
|
||||
transactionId: array[12, byte]
|
||||
content* {.bin_len: it.length.}: seq[byte]
|
||||
|
||||
|
||||
StunMessage* = object
|
||||
msgType*: uint16
|
||||
transactionId*: array[12, byte]
|
||||
attributes*: seq[StunAttribute]
|
||||
attributes*: seq[RawStunAttribute]
|
||||
|
||||
Stun* = object
|
||||
|
||||
proc getAttribute(attrs: seq[RawStunAttribute], typ: uint16): Option[seq[byte]] =
|
||||
for attr in attrs:
|
||||
if attr.attributeType == typ:
|
||||
return some(attr.value)
|
||||
return none(seq[byte])
|
||||
|
||||
proc isMessage*(T: typedesc[Stun], msg: seq[byte]): bool =
|
||||
msg.len >= msgHeaderSize and msg[4..<8] == magicCookie and bitand(0xC0'u8, msg[0]) == 0'u8
|
||||
msg.len >= msgHeaderSize and msg[4..<8] == magicCookieSeq and bitand(0xC0'u8, msg[0]) == 0'u8
|
||||
|
||||
proc decode*(T: typedesc[StunMessage], msg: seq[byte]): StunMessage =
|
||||
let smi = Binary.decode(msg, StunMessageInner)
|
||||
let smi = Binary.decode(msg, RawStunMessage)
|
||||
return T(msgType: smi.msgType,
|
||||
transactionId: smi.transactionId,
|
||||
attributes: StunAttribute.decode(smi.content))
|
||||
attributes: RawStunAttribute.decode(smi.content))
|
||||
|
||||
proc encode*(msg: StunMessage): seq[byte] =
|
||||
const val = @[0, 3, 2, 1]
|
||||
var smi = StunMessageInner(msgType: msg.msgType,
|
||||
var smi = RawStunMessage(msgType: msg.msgType,
|
||||
magicCookie: magicCookie,
|
||||
transactionId: msg.transactionId)
|
||||
for attr in msg.attributes:
|
||||
|
@ -84,5 +87,31 @@ proc encode*(msg: StunMessage): seq[byte] =
|
|||
|
||||
return Binary.encode(smi)
|
||||
|
||||
proc getResponse*(T: typedesc[Stun], msg: seq[byte],
|
||||
address: TransportAddress): Option[StunMessage] =
|
||||
let sm =
|
||||
try:
|
||||
StunMessage.decode(msg)
|
||||
except CatchableError as exc:
|
||||
return none(StunMessage)
|
||||
|
||||
if sm.msgType != BindingRequest:
|
||||
return none(StunMessage)
|
||||
|
||||
var res = StunMessage(msgType: BindingResponse,
|
||||
transactionId: sm.transactionId)
|
||||
|
||||
var unknownAttr: seq[uint16]
|
||||
for attr in sm.attributes:
|
||||
let typ = attr.attributeType
|
||||
if typ.isRequired() and typ notin StunAttributeEnum:
|
||||
unknownAttr.add(typ)
|
||||
if unknownAttr.len() > 0:
|
||||
res.attributes.add(ErrorCode.encode(ECUnknownAttribute))
|
||||
res.attributes.add(UnknownAttribute.encode(unknownAttr))
|
||||
return some(res)
|
||||
|
||||
#if sm.attributes.getAttribute())
|
||||
|
||||
proc new*(T: typedesc[Stun]): T =
|
||||
result = T()
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import binary_serialization,
|
||||
stew/byteutils
|
||||
|
||||
type
|
||||
# Stun Attribute
|
||||
# 0 1 2 3
|
||||
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
# | Type | Length |
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
# | Value (variable) ....
|
||||
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
RawStunAttribute* = object
|
||||
attributeType*: uint16
|
||||
length* {.bin_value: it.value.len.}: uint16
|
||||
value* {.bin_len: it.length.}: seq[byte]
|
||||
|
||||
StunAttributeEnum* = enum
|
||||
AttrMappedAddress = 0x0001
|
||||
AttrChangeRequest = 0x0003 # RFC5780 Nat Behavior Discovery
|
||||
AttrSourceAddress = 0x0004 # Deprecated
|
||||
AttrChangedAddress = 0x0005 # Deprecated
|
||||
AttrUsername = 0x0006
|
||||
AttrMessageIntegrity = 0x0008
|
||||
AttrErrorCode = 0x0009
|
||||
AttrUnknownAttributes = 0x000A
|
||||
AttrChannelNumber = 0x000C # RFC5766 TURN
|
||||
AttrLifetime = 0x000D # RFC5766 TURN
|
||||
AttrXORPeerAddress = 0x0012 # RFC5766 TURN
|
||||
AttrData = 0x0013 # RFC5766 TURN
|
||||
AttrRealm = 0x0014
|
||||
AttrNonce = 0x0015
|
||||
AttrXORRelayedAddress = 0x0016 # RFC5766 TURN
|
||||
AttrRequestedAddressFamily = 0x0017 # RFC6156
|
||||
AttrEvenPort = 0x0018 # RFC5766 TURN
|
||||
AttrRequestedTransport = 0x0019 # RFC5766 TURN
|
||||
AttrDontFragment = 0x001A # RFC5766 TURN
|
||||
AttrMessageIntegritySHA256 = 0x001C # RFC8489 STUN (v2)
|
||||
AttrPasswordAlgorithm = 0x001D # RFC8489 STUN (v2)
|
||||
AttrUserhash = 0x001E # RFC8489 STUN (v2)
|
||||
AttrXORMappedAddress = 0x0020
|
||||
AttrReservationToken = 0x0022 # RFC5766 TURN
|
||||
AttrPriority = 0x0024 # RFC5245 ICE
|
||||
AttrUseCandidate = 0x0025 # RFC5245 ICE
|
||||
AttrPadding = 0x0026 # RFC5780 Nat Behavior Discovery
|
||||
AttrResponsePort = 0x0027 # RFC5780 Nat Behavior Discovery
|
||||
AttrConnectionID = 0x002a # RFC6062 TURN Extensions
|
||||
AttrPasswordAlgorithms = 0x8002 # RFC8489 STUN (v2)
|
||||
AttrAlternateDomain = 0x8003 # RFC8489 STUN (v2)
|
||||
AttrSoftware = 0x8022
|
||||
AttrAlternateServer = 0x8023
|
||||
AttrCacheTimeout = 0x8027 # RFC5780 Nat Behavior Discovery
|
||||
AttrFingerprint = 0x8028
|
||||
AttrICEControlled = 0x8029 # RFC5245 ICE
|
||||
AttrICEControlling = 0x802A # RFC5245 ICE
|
||||
AttrResponseOrigin = 0x802b # RFC5780 Nat Behavior Discovery
|
||||
AttrOtherAddress = 0x802C # RFC5780 Nat Behavior Discovery
|
||||
AttrOrigin = 0x802F
|
||||
|
||||
proc isRequired*(typ: uint16): bool = typ <= 0x7FFF'u16
|
||||
proc isOptional*(typ: uint16): bool = typ >= 0x8000'u16
|
||||
|
||||
# Error Code
|
||||
type
|
||||
ErrorCodeEnum* = enum
|
||||
ECTryAlternate = 300
|
||||
ECBadRequest = 400
|
||||
ECUnauthenticated = 401
|
||||
ECUnknownAttribute = 420
|
||||
ECStaleNonce = 438
|
||||
ECServerError = 500
|
||||
ErrorCode* = object
|
||||
reserved1: uint16 # should be 0
|
||||
reserved2 {.bin_bitsize: 5.}: uint8 # should be 0
|
||||
class {.bin_bitsize: 3.}: uint8
|
||||
number: uint8
|
||||
reason: seq[byte]
|
||||
|
||||
proc encode*(T: typedesc[ErrorCode], code: ErrorCodeEnum, reason: string = ""): RawStunAttribute =
|
||||
let
|
||||
ec = T(class: (code.uint16 div 100'u16).uint8,
|
||||
number: (code.uint16 mod 100'u16).uint8,
|
||||
reason: reason.toBytes())
|
||||
value = Binary.encode(ec)
|
||||
result = RawStunAttribute(attributeType: AttrErrorCode.uint16,
|
||||
length: value.len().uint16,
|
||||
value: value)
|
||||
|
||||
# Unknown Attribute
|
||||
type
|
||||
UnknownAttribute* = object
|
||||
unknownAttr: seq[uint16]
|
||||
|
||||
proc encode*(T: typedesc[UnknownAttribute], unknownAttr: seq[uint16]): RawStunAttribute =
|
||||
let
|
||||
ua = T(unknownAttr: unknownAttr)
|
||||
value = Binary.encode(ua)
|
||||
result = RawStunAttribute(attributeType: AttrUnknownAttributes.uint16,
|
||||
length: value.len().uint16,
|
||||
value: value)
|
|
@ -9,7 +9,7 @@ const usrsctpInclude = root/"usrsctp"/"usrsctplib"
|
|||
|
||||
{.passc: fmt"-I{usrsctpInclude}".}
|
||||
|
||||
# Generated @ 2022-11-23T14:21:00+01:00
|
||||
# Generated @ 2023-03-30T13:55:23+02:00
|
||||
# Command line:
|
||||
# /home/lchenut/.nimble/pkgs/nimterop-0.6.13/nimterop/toast --compile=./usrsctp/usrsctplib/netinet/sctp_input.c --compile=./usrsctp/usrsctplib/netinet/sctp_asconf.c --compile=./usrsctp/usrsctplib/netinet/sctp_pcb.c --compile=./usrsctp/usrsctplib/netinet/sctp_usrreq.c --compile=./usrsctp/usrsctplib/netinet/sctp_cc_functions.c --compile=./usrsctp/usrsctplib/netinet/sctp_auth.c --compile=./usrsctp/usrsctplib/netinet/sctp_userspace.c --compile=./usrsctp/usrsctplib/netinet/sctp_output.c --compile=./usrsctp/usrsctplib/netinet/sctp_callout.c --compile=./usrsctp/usrsctplib/netinet/sctp_crc32.c --compile=./usrsctp/usrsctplib/netinet/sctp_sysctl.c --compile=./usrsctp/usrsctplib/netinet/sctp_sha1.c --compile=./usrsctp/usrsctplib/netinet/sctp_timer.c --compile=./usrsctp/usrsctplib/netinet/sctputil.c --compile=./usrsctp/usrsctplib/netinet/sctp_bsd_addr.c --compile=./usrsctp/usrsctplib/netinet/sctp_peeloff.c --compile=./usrsctp/usrsctplib/netinet/sctp_indata.c --compile=./usrsctp/usrsctplib/netinet/sctp_ss_functions.c --compile=./usrsctp/usrsctplib/user_socket.c --compile=./usrsctp/usrsctplib/netinet6/sctp6_usrreq.c --compile=./usrsctp/usrsctplib/user_mbuf.c --compile=./usrsctp/usrsctplib/user_environment.c --compile=./usrsctp/usrsctplib/user_recv_thread.c --pnim --preprocess --noHeader --defines=SCTP_PROCESS_LEVEL_LOCKS --defines=SCTP_SIMPLE_ALLOCATOR --defines=__Userspace__ --defines=STDC_HEADERS=1 --defines=HAVE_SYS_TYPES_H=1 --defines=HAVE_SYS_STAT_H=1 --defines=HAVE_STDLIB_H=1 --defines=HAVE_STRING_H=1 --defines=HAVE_MEMORY_H=1 --defines=HAVE_STRINGS_H=1 --defines=HAVE_INTTYPES_H=1 --defines=HAVE_STDINT_H=1 --defines=HAVE_UNISTD_H=1 --defines=HAVE_DLFCN_H=1 --defines=LT_OBJDIR=".libs/" --defines=SCTP_DEBUG=1 --defines=INET=1 --defines=INET6=1 --defines=HAVE_SOCKET=1 --defines=HAVE_INET_ADDR=1 --defines=HAVE_STDATOMIC_H=1 --defines=HAVE_SYS_QUEUE_H=1 --defines=HAVE_LINUX_IF_ADDR_H=1 --defines=HAVE_LINUX_RTNETLINK_H=1 --defines=HAVE_NETINET_IP_ICMP_H=1 --defines=HAVE_NET_ROUTE_H=1 --defines=_GNU_SOURCE --replace=sockaddr=SockAddr --replace=SockAddr_storage=Sockaddr_storage --replace=SockAddr_in=Sockaddr_in --replace=SockAddr_conn=Sockaddr_conn --replace=socklen_t=SockLen --includeDirs=./usrsctp/usrsctplib ./usrsctp/usrsctplib/usrsctp.h
|
||||
|
||||
|
|
Loading…
Reference in New Issue