Added Xor-Mapped-Address attribute

This commit is contained in:
Ludovic Chenut 2023-04-21 17:41:42 +02:00
parent 5bc19f3e03
commit 472306f5ce
No known key found for this signature in database
GPG Key ID: D9A59B1907F1D50C
3 changed files with 89 additions and 4 deletions

View File

@ -49,6 +49,7 @@ type
RawStunMessage = object RawStunMessage = object
msgType: uint16 msgType: uint16
# it.conten.len() + 8 Because the Fingerprint is added after the encoding
length* {.bin_value: it.content.len() + 8.}: uint16 length* {.bin_value: it.content.len() + 8.}: uint16
magicCookie: uint32 magicCookie: uint32
transactionId: array[12, byte] transactionId: array[12, byte]
@ -89,7 +90,9 @@ proc encode*(msg: StunMessage): seq[byte] =
result.add(Binary.encode(Fingerprint.encode(result))) result.add(Binary.encode(Fingerprint.encode(result)))
proc getResponse*(T: typedesc[Stun], msg: seq[byte], proc getResponse*(T: typedesc[Stun], msg: seq[byte],
address: TransportAddress): Option[StunMessage] = ta: TransportAddress): Option[StunMessage] =
if ta.family != AddressFamily.IPv4 and ta.family != AddressFamily.IPv6:
return none(StunMessage)
let sm = let sm =
try: try:
StunMessage.decode(msg) StunMessage.decode(msg)
@ -112,7 +115,8 @@ proc getResponse*(T: typedesc[Stun], msg: seq[byte],
res.attributes.add(UnknownAttribute.encode(unknownAttr)) res.attributes.add(UnknownAttribute.encode(unknownAttr))
return some(res) return some(res)
#if sm.attributes.getAttribute()) res.attributes.add(XorMappedAddress.encode(ta, sm.transactionId))
return some(res)
proc new*(T: typedesc[Stun]): T = proc new*(T: typedesc[Stun]): T =
result = T() result = T()

View File

@ -1,8 +1,11 @@
import sequtils, typetraits
import binary_serialization, import binary_serialization,
stew/byteutils stew/byteutils,
chronos
import utils import utils
type type
StunAttributeEncodingError* = object of CatchableError
# Stun Attribute # Stun Attribute
# 0 1 2 3 # 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 # 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
@ -100,12 +103,50 @@ proc encode*(T: typedesc[UnknownAttribute], unknownAttr: seq[uint16]): RawStunAt
length: value.len().uint16, length: value.len().uint16,
value: value) value: value)
# Fingerprint
type type
Fingerprint* = object Fingerprint* = object
crc32: uint32 crc32: uint32
proc encode*(T: typedesc[Fingerprint], msg: seq[byte]): RawStunAttribute = proc encode*(T: typedesc[Fingerprint], msg: seq[byte]): RawStunAttribute =
let value = Binary.encode(Fingerprint(crc32: crc32(msg) xor 0x5354554e'u32)) let value = Binary.encode(T(crc32: crc32(msg) xor 0x5354554e'u32))
result = RawStunAttribute(attributeType: AttrFingerprint.uint16, result = RawStunAttribute(attributeType: AttrFingerprint.uint16,
length: value.len().uint16, length: value.len().uint16,
value: value) value: value)
# Xor Mapped Address
type
MappedAddressFamily {.size: 1.} = enum
MAFIPv4 = 0x01
MAFIPv6 = 0x02
XorMappedAddress* = object
reserved: uint8 # should be 0
family: MappedAddressFamily
port: uint16
address: seq[byte]
proc encode*(T: typedesc[XorMappedAddress], ta: TransportAddress,
tid: array[12, byte]): RawStunAttribute =
const magicCookie = @[ 0x21'u8, 0x12, 0xa4, 0x42 ]
let
address =
if ta.family == AddressFamily.IPv4:
var s = newSeq[uint8](4)
for i in 0..3:
s[i] = ta.address_v4[i] xor magicCookie[i]
s
else:
let magicCookieTid = magicCookie.concat(@tid)
var s = newSeq[uint8](16)
for i in 0..15:
s[i] = ta.address_v6[i] xor magicCookieTid[i]
s
xma = T(family: if ta.family == AddressFamily.IPv4: MAFIPv4 else: MAFIPv6,
port: ta.port.distinctBase xor 0x2112'u16, address: address)
value = Binary.encode(xma)
result = RawStunAttribute(attributeType: AttrXORMappedAddress.uint16,
length: value.len().uint16,
value: value)

40
webrtc/webrtc.nim Normal file
View File

@ -0,0 +1,40 @@
import chronos, chronicles
import stun
logScope:
topics = "webrtc"
let fut = newFuture[void]()
type
WebRTC* = object
udp: DatagramTransport
proc new*(T: typedesc[WebRTC], port: uint16 = 42657): T =
logScope: topics = "webrtc"
var webrtc = T()
proc onReceive(udp: DatagramTransport, address: TransportAddress) {.async, gcsafe.} =
let
msg = udp.getMessage()
if Stun.isMessage(msg):
let res = Stun.getResponse(msg, address)
echo res
if res.isSome():
await udp.sendTo(address, res.get().encode())
trace "onReceive", isStun = Stun.isMessage(msg)
if not fut.completed(): fut.complete()
let
laddr = initTAddress("127.0.0.1:" & $port)
udp = newDatagramTransport(onReceive, local = laddr)
trace "local address", laddr
webrtc.udp = udp
return webrtc
#
#proc main {.async.} =
# echo "/ip4/127.0.0.1/udp/42657/webrtc/certhash/uEiDKBGpmOW3zQhiCHagHZ8igwfKNIp8rQCJWd5E5mIhGHw/p2p/12D3KooWFjMiMZLaCKEZRvMqKp5qUGduS6iBZ9RWQgYZXYtAAaPC"
# discard WebRTC.new()
# await fut
# await sleepAsync(10.seconds)
#
#waitFor(main())