Add getInterfaces() and getBestRoute().
Add IpNet and IpMask. Add TTL setting for UDP transports with {Broadcast}. Fix comments. Add tests. Bump version to 2.2.5.
This commit is contained in:
parent
1ffa329fe1
commit
2c2e2f7fad
|
@ -1,5 +1,5 @@
|
||||||
packageName = "chronos"
|
packageName = "chronos"
|
||||||
version = "2.2.4"
|
version = "2.2.5"
|
||||||
author = "Status Research & Development GmbH"
|
author = "Status Research & Development GmbH"
|
||||||
description = "Chronos"
|
description = "Chronos"
|
||||||
license = "Apache License 2.0 or MIT"
|
license = "Apache License 2.0 or MIT"
|
||||||
|
|
|
@ -721,14 +721,14 @@ proc removeTimer*(at: uint64, cb: CallbackFunc, udata: pointer = nil) {.
|
||||||
inline, deprecated: "Use removeTimer(Duration, cb, udata)".} =
|
inline, deprecated: "Use removeTimer(Duration, cb, udata)".} =
|
||||||
removeTimer(Moment.init(int64(at), Millisecond), cb, udata)
|
removeTimer(Moment.init(int64(at), Millisecond), cb, udata)
|
||||||
|
|
||||||
proc sleepAsync*(ms: Duration): Future[void] =
|
proc sleepAsync*(duration: Duration): Future[void] =
|
||||||
## Suspends the execution of the current async procedure for the next
|
## Suspends the execution of the current async procedure for the next
|
||||||
## ``ms`` milliseconds.
|
## ``duration`` time.
|
||||||
var retFuture = newFuture[void]("sleepAsync")
|
var retFuture = newFuture[void]("sleepAsync")
|
||||||
proc completion(data: pointer) =
|
proc completion(data: pointer) =
|
||||||
if not retFuture.finished:
|
if not retFuture.finished:
|
||||||
retFuture.complete()
|
retFuture.complete()
|
||||||
addTimer(Moment.fromNow(ms), completion, cast[pointer](retFuture))
|
addTimer(Moment.fromNow(duration), completion, cast[pointer](retFuture))
|
||||||
return retFuture
|
return retFuture
|
||||||
|
|
||||||
proc sleepAsync*(ms: int): Future[void] {.
|
proc sleepAsync*(ms: int): Future[void] {.
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
# MIT license (LICENSE-MIT)
|
# MIT license (LICENSE-MIT)
|
||||||
|
|
||||||
import transports/[datagram, stream, common]
|
import transports/[datagram, stream, common, ipnet, osnet]
|
||||||
export datagram, common, stream
|
export datagram, common, stream, ipnet, osnet
|
||||||
|
|
|
@ -15,6 +15,10 @@ when defined(windows):
|
||||||
import winlean
|
import winlean
|
||||||
else:
|
else:
|
||||||
import posix
|
import posix
|
||||||
|
var IP_MULTICAST_TTL* {.importc: "IP_MULTICAST_TTL",
|
||||||
|
header: "<netinet/in.h>".}: cint
|
||||||
|
var IPV6_MULTICAST_HOPS* {.importc: "IPV6_MULTICAST_HOPS",
|
||||||
|
header: "<netinet/in.h>".}: cint
|
||||||
|
|
||||||
type
|
type
|
||||||
VectorKind = enum
|
VectorKind = enum
|
||||||
|
@ -105,6 +109,8 @@ when defined(windows):
|
||||||
const
|
const
|
||||||
IOC_VENDOR = DWORD(0x18000000)
|
IOC_VENDOR = DWORD(0x18000000)
|
||||||
SIO_UDP_CONNRESET = DWORD(winlean.IOC_IN) or IOC_VENDOR or DWORD(12)
|
SIO_UDP_CONNRESET = DWORD(winlean.IOC_IN) or IOC_VENDOR or DWORD(12)
|
||||||
|
IPPROTO_IP = DWORD(0)
|
||||||
|
IP_TTL = DWORD(4)
|
||||||
|
|
||||||
proc writeDatagramLoop(udata: pointer) =
|
proc writeDatagramLoop(udata: pointer) =
|
||||||
var bytesCount: int32
|
var bytesCount: int32
|
||||||
|
@ -250,7 +256,8 @@ when defined(windows):
|
||||||
flags: set[ServerFlags],
|
flags: set[ServerFlags],
|
||||||
udata: pointer,
|
udata: pointer,
|
||||||
child: DatagramTransport,
|
child: DatagramTransport,
|
||||||
bufferSize: int): DatagramTransport =
|
bufferSize: int,
|
||||||
|
ttl: int): DatagramTransport =
|
||||||
var localSock: AsyncFD
|
var localSock: AsyncFD
|
||||||
doAssert(remote.family == local.family)
|
doAssert(remote.family == local.family)
|
||||||
doAssert(not isNil(cbproc))
|
doAssert(not isNil(cbproc))
|
||||||
|
@ -287,6 +294,13 @@ when defined(windows):
|
||||||
closeSocket(localSock)
|
closeSocket(localSock)
|
||||||
raiseTransportOsError(err)
|
raiseTransportOsError(err)
|
||||||
|
|
||||||
|
if ttl > 0:
|
||||||
|
if not setSockOpt(localSock, IPPROTO_IP, IP_TTL, DWORD(ttl)):
|
||||||
|
let err = osLastError()
|
||||||
|
if sock == asyncInvalidSocket:
|
||||||
|
closeSocket(localSock)
|
||||||
|
raiseTransportOsError(err)
|
||||||
|
|
||||||
## Fix for Q263823.
|
## Fix for Q263823.
|
||||||
var bytesRet: DWORD
|
var bytesRet: DWORD
|
||||||
var bval = WINBOOL(0)
|
var bval = WINBOOL(0)
|
||||||
|
@ -437,7 +451,8 @@ else:
|
||||||
flags: set[ServerFlags],
|
flags: set[ServerFlags],
|
||||||
udata: pointer,
|
udata: pointer,
|
||||||
child: DatagramTransport = nil,
|
child: DatagramTransport = nil,
|
||||||
bufferSize: int): DatagramTransport =
|
bufferSize: int,
|
||||||
|
ttl: int): DatagramTransport =
|
||||||
var localSock: AsyncFD
|
var localSock: AsyncFD
|
||||||
doAssert(remote.family == local.family)
|
doAssert(remote.family == local.family)
|
||||||
doAssert(not isNil(cbproc))
|
doAssert(not isNil(cbproc))
|
||||||
|
@ -478,6 +493,20 @@ else:
|
||||||
closeSocket(localSock)
|
closeSocket(localSock)
|
||||||
raiseTransportOsError(err)
|
raiseTransportOsError(err)
|
||||||
|
|
||||||
|
if ttl > 0:
|
||||||
|
var res: bool
|
||||||
|
if local.family == AddressFamily.IPv4:
|
||||||
|
res = setSockOpt(localSock, posix.IPPROTO_IP, IP_MULTICAST_TTL,
|
||||||
|
cint(ttl))
|
||||||
|
elif local.family == AddressFamily.IPv6:
|
||||||
|
res = setSockOpt(localSock, posix.IPPROTO_IP, IPV6_MULTICAST_HOPS,
|
||||||
|
cint(ttl))
|
||||||
|
if not res:
|
||||||
|
let err = osLastError()
|
||||||
|
if sock == asyncInvalidSocket:
|
||||||
|
closeSocket(localSock)
|
||||||
|
raiseTransportOsError(err)
|
||||||
|
|
||||||
if local.port != Port(0):
|
if local.port != Port(0):
|
||||||
var saddr: Sockaddr_storage
|
var saddr: Sockaddr_storage
|
||||||
var slen: SockLen
|
var slen: SockLen
|
||||||
|
@ -550,7 +579,8 @@ proc newDatagramTransport*(cbproc: DatagramCallback,
|
||||||
flags: set[ServerFlags] = {},
|
flags: set[ServerFlags] = {},
|
||||||
udata: pointer = nil,
|
udata: pointer = nil,
|
||||||
child: DatagramTransport = nil,
|
child: DatagramTransport = nil,
|
||||||
bufSize: int = DefaultDatagramBufferSize
|
bufSize: int = DefaultDatagramBufferSize,
|
||||||
|
ttl: int = 0
|
||||||
): DatagramTransport =
|
): DatagramTransport =
|
||||||
## Create new UDP datagram transport (IPv4).
|
## Create new UDP datagram transport (IPv4).
|
||||||
##
|
##
|
||||||
|
@ -561,9 +591,11 @@ proc newDatagramTransport*(cbproc: DatagramCallback,
|
||||||
## ``sock`` - application-driven socket to use.
|
## ``sock`` - application-driven socket to use.
|
||||||
## ``flags`` - flags that will be applied to socket.
|
## ``flags`` - flags that will be applied to socket.
|
||||||
## ``udata`` - custom argument which will be passed to ``cbproc``.
|
## ``udata`` - custom argument which will be passed to ``cbproc``.
|
||||||
## ``bufSize`` - size of internal buffer
|
## ``bufSize`` - size of internal buffer.
|
||||||
|
## ``ttl`` - TTL for UDP datagram packet (only usable when flags has
|
||||||
|
## ``Broadcast`` option).
|
||||||
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
||||||
flags, udata, child, bufSize)
|
flags, udata, child, bufSize, ttl)
|
||||||
|
|
||||||
proc newDatagramTransport*[T](cbproc: DatagramCallback,
|
proc newDatagramTransport*[T](cbproc: DatagramCallback,
|
||||||
udata: ref T,
|
udata: ref T,
|
||||||
|
@ -572,13 +604,14 @@ proc newDatagramTransport*[T](cbproc: DatagramCallback,
|
||||||
sock: AsyncFD = asyncInvalidSocket,
|
sock: AsyncFD = asyncInvalidSocket,
|
||||||
flags: set[ServerFlags] = {},
|
flags: set[ServerFlags] = {},
|
||||||
child: DatagramTransport = nil,
|
child: DatagramTransport = nil,
|
||||||
bufSize: int = DefaultDatagramBufferSize
|
bufSize: int = DefaultDatagramBufferSize,
|
||||||
|
ttl: int = 0
|
||||||
): DatagramTransport =
|
): DatagramTransport =
|
||||||
var fflags = flags + {GCUserData}
|
var fflags = flags + {GCUserData}
|
||||||
GC_ref(udata)
|
GC_ref(udata)
|
||||||
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
||||||
fflags, cast[pointer](udata),
|
fflags, cast[pointer](udata),
|
||||||
child, bufSize)
|
child, bufSize, ttl)
|
||||||
|
|
||||||
proc newDatagramTransport6*(cbproc: DatagramCallback,
|
proc newDatagramTransport6*(cbproc: DatagramCallback,
|
||||||
remote: TransportAddress = AnyAddress6,
|
remote: TransportAddress = AnyAddress6,
|
||||||
|
@ -587,7 +620,8 @@ proc newDatagramTransport6*(cbproc: DatagramCallback,
|
||||||
flags: set[ServerFlags] = {},
|
flags: set[ServerFlags] = {},
|
||||||
udata: pointer = nil,
|
udata: pointer = nil,
|
||||||
child: DatagramTransport = nil,
|
child: DatagramTransport = nil,
|
||||||
bufSize: int = DefaultDatagramBufferSize
|
bufSize: int = DefaultDatagramBufferSize,
|
||||||
|
ttl: int = 0
|
||||||
): DatagramTransport =
|
): DatagramTransport =
|
||||||
## Create new UDP datagram transport (IPv6).
|
## Create new UDP datagram transport (IPv6).
|
||||||
##
|
##
|
||||||
|
@ -599,8 +633,10 @@ proc newDatagramTransport6*(cbproc: DatagramCallback,
|
||||||
## ``flags`` - flags that will be applied to socket.
|
## ``flags`` - flags that will be applied to socket.
|
||||||
## ``udata`` - custom argument which will be passed to ``cbproc``.
|
## ``udata`` - custom argument which will be passed to ``cbproc``.
|
||||||
## ``bufSize`` - size of internal buffer.
|
## ``bufSize`` - size of internal buffer.
|
||||||
|
## ``ttl`` - TTL for UDP datagram packet (only usable when flags has
|
||||||
|
## ``Broadcast`` option).
|
||||||
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
||||||
flags, udata, child, bufSize)
|
flags, udata, child, bufSize, ttl)
|
||||||
|
|
||||||
proc newDatagramTransport6*[T](cbproc: DatagramCallback,
|
proc newDatagramTransport6*[T](cbproc: DatagramCallback,
|
||||||
udata: ref T,
|
udata: ref T,
|
||||||
|
@ -609,13 +645,14 @@ proc newDatagramTransport6*[T](cbproc: DatagramCallback,
|
||||||
sock: AsyncFD = asyncInvalidSocket,
|
sock: AsyncFD = asyncInvalidSocket,
|
||||||
flags: set[ServerFlags] = {},
|
flags: set[ServerFlags] = {},
|
||||||
child: DatagramTransport = nil,
|
child: DatagramTransport = nil,
|
||||||
bufSize: int = DefaultDatagramBufferSize
|
bufSize: int = DefaultDatagramBufferSize,
|
||||||
|
ttl: int = 0
|
||||||
): DatagramTransport =
|
): DatagramTransport =
|
||||||
var fflags = flags + {GCUserData}
|
var fflags = flags + {GCUserData}
|
||||||
GC_ref(udata)
|
GC_ref(udata)
|
||||||
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
result = newDatagramTransportCommon(cbproc, remote, local, sock,
|
||||||
fflags, cast[pointer](udata),
|
fflags, cast[pointer](udata),
|
||||||
child, bufSize)
|
child, bufSize, ttl)
|
||||||
|
|
||||||
proc join*(transp: DatagramTransport): Future[void] =
|
proc join*(transp: DatagramTransport): Future[void] =
|
||||||
## Wait until the transport ``transp`` will be closed.
|
## Wait until the transport ``transp`` will be closed.
|
||||||
|
|
|
@ -0,0 +1,712 @@
|
||||||
|
#
|
||||||
|
# Chronos IP Network
|
||||||
|
# (c) Copyright 2018-Present
|
||||||
|
# Status Research & Development GmbH
|
||||||
|
#
|
||||||
|
# Licensed under either of
|
||||||
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
|
|
||||||
|
## This module implements various IP network utility procedures.
|
||||||
|
import endians, strutils
|
||||||
|
import common
|
||||||
|
export common
|
||||||
|
|
||||||
|
type
|
||||||
|
IpMask* = object
|
||||||
|
case family*: AddressFamily
|
||||||
|
of AddressFamily.None, AddressFamily.Unix:
|
||||||
|
discard
|
||||||
|
of AddressFamily.IPv4:
|
||||||
|
mask4*: uint32
|
||||||
|
of AddressFamily.IPv6:
|
||||||
|
mask6*: array[2, uint64]
|
||||||
|
|
||||||
|
IpNet* = object
|
||||||
|
host*: TransportAddress
|
||||||
|
mask*: IpMask
|
||||||
|
|
||||||
|
proc toNetworkOrder(mask: IpMask): IpMask {.inline.} =
|
||||||
|
## Converts ``mask`` from host order (which can be big/little-endian) to
|
||||||
|
## network order (which is big-endian) representation.
|
||||||
|
result = IpMask(family: mask.family)
|
||||||
|
if mask.family == AddressFamily.IPv4:
|
||||||
|
bigEndian32(cast[pointer](addr result.mask4),
|
||||||
|
cast[pointer](unsafeAddr mask.mask4))
|
||||||
|
elif mask.family == AddressFamily.IPv6:
|
||||||
|
bigEndian64(cast[pointer](addr result.mask6[0]),
|
||||||
|
cast[pointer](unsafeAddr mask.mask6[0]))
|
||||||
|
bigEndian64(cast[pointer](addr result.mask6[1]),
|
||||||
|
cast[pointer](unsafeAddr mask.mask6[1]))
|
||||||
|
|
||||||
|
proc toHostOrder(mask: IpMask): IpMask {.inline.} =
|
||||||
|
## Converts ``mask`` from network order (which is big-endian) back to
|
||||||
|
## host representation (which can be big/little-endian).
|
||||||
|
when system.cpuEndian == bigEndian:
|
||||||
|
result = mask
|
||||||
|
else:
|
||||||
|
result = IpMask(family: mask.family)
|
||||||
|
if mask.family == AddressFamily.IPv4:
|
||||||
|
swapEndian32(cast[pointer](addr result.mask4),
|
||||||
|
cast[pointer](unsafeAddr mask.mask4))
|
||||||
|
elif mask.family == AddressFamily.IPv6:
|
||||||
|
swapEndian64(cast[pointer](addr result.mask6[0]),
|
||||||
|
cast[pointer](unsafeAddr mask.mask6[0]))
|
||||||
|
swapEndian64(cast[pointer](addr result.mask6[1]),
|
||||||
|
cast[pointer](unsafeAddr mask.mask6[1]))
|
||||||
|
|
||||||
|
proc `==`*(m1, m2: IpMask): bool {.inline.} =
|
||||||
|
## Returns ``true`` if masks ``m1`` and ``m2`` are equal in IP family and
|
||||||
|
## by value.
|
||||||
|
if m1.family == m2.family:
|
||||||
|
if m1.family == AddressFamily.IPv4:
|
||||||
|
result = (m1.mask4 == m2.mask4)
|
||||||
|
elif m1.family == AddressFamily.IPv6:
|
||||||
|
result = ((m1.mask6[0] == m2.mask6[0]) and (m1.mask6[1] == m2.mask6[1]))
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpMask], family: AddressFamily, prefix: int): IpMask =
|
||||||
|
## Initialize mask of IP family ``family`` from prefix length ``prefix``.
|
||||||
|
if family == AddressFamily.IPv4:
|
||||||
|
result = IpMask(family: AddressFamily.IPv4)
|
||||||
|
if prefix <= 0:
|
||||||
|
result.mask4 = 0x00'u32
|
||||||
|
else:
|
||||||
|
result.mask4 = 0xFFFF_FFFF'u32
|
||||||
|
if prefix > 0 and prefix < 32:
|
||||||
|
result.mask4 = 0xFFFF_FFFF'u32
|
||||||
|
result.mask4 = cast[uint32](result.mask4 shl (32 - prefix))
|
||||||
|
elif family == AddressFamily.IPv6:
|
||||||
|
result = IpMask(family: AddressFamily.IPv6)
|
||||||
|
if prefix <= 0:
|
||||||
|
result.mask6[0] = 0x00'u64
|
||||||
|
result.mask6[1] = 0x00'u64
|
||||||
|
elif prefix >= 128:
|
||||||
|
result.mask6[0] = 0xFFFF_FFFF_FFFF_FFFF'u64
|
||||||
|
result.mask6[1] = 0xFFFF_FFFF_FFFF_FFFF'u64
|
||||||
|
else:
|
||||||
|
result.mask6[0] = 0xFFFF_FFFF_FFFF_FFFF'u64
|
||||||
|
if prefix > 64:
|
||||||
|
result.mask6[1] = 0xFFFF_FFFF_FFFF_FFFF'u64
|
||||||
|
result.mask6[1] = result.mask6[1] shl (128 - prefix)
|
||||||
|
elif prefix == 64:
|
||||||
|
result.mask6[1] = 0x00'u64
|
||||||
|
else:
|
||||||
|
result.mask6[0] = result.mask6[0] shl (64 - prefix)
|
||||||
|
result.mask6[1] = 0x00'u64
|
||||||
|
result = result.toNetworkOrder()
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpMask], netmask: TransportAddress): IpMask =
|
||||||
|
## Initialize network mask using address ``netmask``.
|
||||||
|
if netmask.family == AddressFamily.IPv4:
|
||||||
|
result.family = netmask.family
|
||||||
|
result.mask4 = cast[ptr uint32](unsafeAddr netmask.address_v4[0])[]
|
||||||
|
elif netmask.family == AddressFamily.IPv6:
|
||||||
|
result.family = netmask.family
|
||||||
|
result.mask6[0] = cast[ptr uint64](unsafeAddr netmask.address_v6[0])[]
|
||||||
|
result.mask6[1] = cast[ptr uint64](unsafeAddr netmask.address_v6[8])[]
|
||||||
|
|
||||||
|
proc initIp*(t: typedesc[IpMask], netmask: string): IpMask =
|
||||||
|
## Initialize network mask using IPv4 or IPv6 address in text representation
|
||||||
|
## ``netmask``.
|
||||||
|
##
|
||||||
|
## If ``netmask`` address string is invalid, result IpMask.family will be
|
||||||
|
## set to ``AddressFamily.None``.
|
||||||
|
try:
|
||||||
|
var ip = parseIpAddress(netmask)
|
||||||
|
var tip = initTAddress(ip, Port(0))
|
||||||
|
result = t.init(tip)
|
||||||
|
except ValueError:
|
||||||
|
discard
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpMask], netmask: string): IpMask =
|
||||||
|
## Initialize network mask using hexadecimal string representation
|
||||||
|
## ``netmask``.
|
||||||
|
##
|
||||||
|
## If ``netmask`` mask is invalid, result IpMask.family will be set to
|
||||||
|
## ``AddressFamily.None``.
|
||||||
|
const
|
||||||
|
hexNumbers = {'0'..'9'}
|
||||||
|
hexCapitals = {'A'..'F'}
|
||||||
|
hexLowers = {'a'..'f'}
|
||||||
|
let length = len(netmask)
|
||||||
|
if length == 8 or length == (2 + 8):
|
||||||
|
## IPv4 mask
|
||||||
|
var offset = 0
|
||||||
|
if length == 2 + 8:
|
||||||
|
offset = 2
|
||||||
|
var res = IpMask(family: AddressFamily.IPv4)
|
||||||
|
var r, v: uint32
|
||||||
|
for i in 0..<8:
|
||||||
|
if netmask[offset + i] in hexNumbers:
|
||||||
|
v = cast[uint32](ord(netmask[offset + i]) - ord('0'))
|
||||||
|
elif netmask[offset + i] in hexCapitals:
|
||||||
|
v = cast[uint32](ord(netmask[offset + i]) - ord('A') + 10)
|
||||||
|
elif netmask[offset + i] in hexLowers:
|
||||||
|
v = cast[uint32](ord(netmask[offset + i]) - ord('a') + 10)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
r = (r shl 4) or v
|
||||||
|
bigEndian32(addr res.mask4, addr r)
|
||||||
|
result = res
|
||||||
|
elif length == 32 or length == (2 + 32):
|
||||||
|
## IPv6 mask
|
||||||
|
var offset = 0
|
||||||
|
if length == 2 + 32:
|
||||||
|
offset = 2
|
||||||
|
var res = IpMask(family: AddressFamily.IPv6)
|
||||||
|
for i in 0..1:
|
||||||
|
var r, v: uint64
|
||||||
|
for i in 0..<16:
|
||||||
|
if netmask[offset + i] in hexNumbers:
|
||||||
|
v = cast[uint64](ord(netmask[offset + i]) - ord('0'))
|
||||||
|
elif netmask[offset + i] in hexCapitals:
|
||||||
|
v = cast[uint64](ord(netmask[offset + i]) - ord('A') + 10)
|
||||||
|
elif netmask[offset + i] in hexLowers:
|
||||||
|
v = cast[uint64](ord(netmask[offset + i]) - ord('a') + 10)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
r = (r shl 4) or v
|
||||||
|
offset += 16
|
||||||
|
bigEndian64(addr res.mask6[i], addr r)
|
||||||
|
result = res
|
||||||
|
|
||||||
|
proc toIPv6*(address: TransportAddress): TransportAddress =
|
||||||
|
## Map IPv4 ``address`` to IPv6 address.
|
||||||
|
##
|
||||||
|
## If ``address`` is IPv4 address then it will be mapped as:
|
||||||
|
## <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
|
||||||
|
##
|
||||||
|
## If ``address`` is IPv6 address it will be returned without any changes.
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = TransportAddress(family: AddressFamily.IPv6)
|
||||||
|
result.address_v6[10] = 0xFF'u8
|
||||||
|
result.address_v6[11] = 0xFF'u8
|
||||||
|
let data = cast[ptr uint32](unsafeAddr address.address_v4[0])[]
|
||||||
|
cast[ptr uint32](addr result.address_v6[12])[] = data
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = address
|
||||||
|
|
||||||
|
proc isV4Mapped*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is (IPv4 to IPv6) mapped address, e.g.
|
||||||
|
## 0000:0000:0000:0000:0000:FFFF:xxxx:xxxx
|
||||||
|
##
|
||||||
|
## Procedure returns ``false`` if ``address`` family is IPv4.
|
||||||
|
if address.family == AddressFamily.IPv6:
|
||||||
|
let data0 = cast[ptr uint64](unsafeAddr address.address_v6[0])[]
|
||||||
|
let data1 = cast[ptr uint16](unsafeAddr address.address_v6[8])[]
|
||||||
|
let data2 = cast[ptr uint16](unsafeAddr address.address_v6[10])[]
|
||||||
|
result = (data0 == 0'u64) and (data1 == 0x00'u16) and (data2 == 0xFFFF'u16)
|
||||||
|
|
||||||
|
proc toIPv4*(address: TransportAddress): TransportAddress =
|
||||||
|
## Get IPv4 from (IPv4 to IPv6) mapped address.
|
||||||
|
##
|
||||||
|
## If ``address`` is IPv4 address it will be returned without any changes.
|
||||||
|
##
|
||||||
|
## If ``address`` is not IPv4 to IPv6 mapped address, then result family will
|
||||||
|
## be set to AddressFamily.None.
|
||||||
|
if address.family == AddressFamily.IPv6:
|
||||||
|
if isV4Mapped(address):
|
||||||
|
result = TransportAddress(family: AddressFamily.IPv4)
|
||||||
|
let data = cast[ptr uint32](unsafeAddr address.address_v6[12])[]
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = data
|
||||||
|
elif address.family == AddressFamily.IPv4:
|
||||||
|
result = address
|
||||||
|
|
||||||
|
proc mask*(a: TransportAddress, m: IpMask): TransportAddress =
|
||||||
|
## Apply IP mask ``m`` to address ``a`` and return result address.
|
||||||
|
##
|
||||||
|
## If ``a`` family is IPv4 and ``m`` family is IPv6, masking is still
|
||||||
|
## possible when ``m`` has ``FFFF:FFFF:FFFF:FFFF:FFFF:FFFF`` prefix. Returned
|
||||||
|
## value will be IPv4 address.
|
||||||
|
##
|
||||||
|
## If ``a`` family is IPv6 and ``m`` family is IPv4, masking is still
|
||||||
|
## possible when ``a`` holds (IPv4 to IPv6) mapped address. Returned value
|
||||||
|
## will be IPv6 address.
|
||||||
|
##
|
||||||
|
## If ``a`` family is IPv4 and ``m`` family is IPv4, returned value will be
|
||||||
|
## IPv4 address.
|
||||||
|
##
|
||||||
|
## If ``a`` family is IPv6 and ``m`` family is IPv6, returned value will be
|
||||||
|
## IPv6 address.
|
||||||
|
##
|
||||||
|
## In all other cases returned address will have ``AddressFamily.None``.
|
||||||
|
if a.family == AddressFamily.IPv4 and m.family == AddressFamily.IPv6:
|
||||||
|
if (m.mask6[0] == 0xFFFF_FFFF_FFFF_FFFF'u64) and
|
||||||
|
(m.mask6[1] and 0xFFFF_FFFF'u64) == 0xFFFF_FFFF'u64:
|
||||||
|
result = TransportAddress(family: a.family)
|
||||||
|
let mask = cast[uint32](m.mask6[1] shr 32)
|
||||||
|
let data = cast[ptr uint32](unsafeAddr a.address_v4[0])[]
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = data and mask
|
||||||
|
result.port = a.port
|
||||||
|
elif a.family == AddressFamily.IPv6 and m.family == AddressFamily.IPv4:
|
||||||
|
var ip = a.toIPv4()
|
||||||
|
if ip.family == AddressFamily.IPv4:
|
||||||
|
let data = cast[ptr uint32](addr ip.address_v4[0])[]
|
||||||
|
cast[ptr uint32](addr ip.address_v4[0])[] = data and m.mask4
|
||||||
|
result = ip.toIPv6()
|
||||||
|
result.port = a.port
|
||||||
|
elif a.family == AddressFamily.IPv4 and m.family == AddressFamily.IPv4:
|
||||||
|
result = TransportAddress(family: AddressFamily.IPv4)
|
||||||
|
let data = cast[ptr uint32](unsafeAddr a.address_v4[0])[]
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = data and m.mask4
|
||||||
|
result.port = a.port
|
||||||
|
elif a.family == AddressFamily.IPv6 and m.family == AddressFamily.IPv6:
|
||||||
|
result = TransportAddress(family: AddressFamily.IPv6)
|
||||||
|
let data0 = cast[ptr uint64](unsafeAddr a.address_v6[0])[]
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr a.address_v6[8])[]
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = data0 and m.mask6[0]
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = data1 and m.mask6[1]
|
||||||
|
result.port = a.port
|
||||||
|
|
||||||
|
proc prefix*(mask: IpMask): int =
|
||||||
|
## Returns number of bits set `1` in IP mask ``mask``.
|
||||||
|
##
|
||||||
|
## Procedure returns ``-1`` if mask is not canonical, e.g. has holes with
|
||||||
|
## ``0`` bits between ``1`` bits.
|
||||||
|
var hmask = mask.toHostOrder()
|
||||||
|
if hmask.family == AddressFamily.IPv4:
|
||||||
|
var n = hmask.mask4
|
||||||
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000'u32) == 0'u32:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
|
n = n shl 1
|
||||||
|
inc(result)
|
||||||
|
elif hmask.family == AddressFamily.IPv6:
|
||||||
|
if hmask.mask6[0] == 0xFFFF_FFFF_FFFF_FFFF'u64:
|
||||||
|
result += 64
|
||||||
|
if hmask.mask6[1] == 0xFFFF_FFFF_FFFF_FFFF'u64:
|
||||||
|
result += 64:
|
||||||
|
else:
|
||||||
|
var n = hmask.mask6[1]
|
||||||
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000_0000_0000'u64) == 0'u64:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
|
n = n shl 1
|
||||||
|
inc(result)
|
||||||
|
else:
|
||||||
|
var n = hmask.mask6[0]
|
||||||
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000_0000_0000'u64) == 0'u64:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
|
n = n shl 1
|
||||||
|
inc(result)
|
||||||
|
if hmask.mask6[1] != 0x00'u64:
|
||||||
|
result = -1
|
||||||
|
|
||||||
|
proc subnetMask*(mask: IpMask): TransportAddress =
|
||||||
|
## Returns TransportAddress representation of IP mask ``mask``.
|
||||||
|
result = TransportAddress(family: mask.family)
|
||||||
|
if mask.family == AddressFamily.IPv4:
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = mask.mask4
|
||||||
|
elif mask.family == AddressFamily.IPv6:
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = mask.mask6[0]
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = mask.mask6[1]
|
||||||
|
|
||||||
|
proc `$`*(mask: IpMask, include0x = false): string =
|
||||||
|
## Returns hexadecimal string representation of IP mask ``mask``.
|
||||||
|
var host = mask.toHostOrder()
|
||||||
|
result = ""
|
||||||
|
if host.family == AddressFamily.IPv4:
|
||||||
|
result = if include0x: "0x" else: ""
|
||||||
|
var n = 32
|
||||||
|
var m = host.mask4
|
||||||
|
while n > 0:
|
||||||
|
n -= 4
|
||||||
|
var c = cast[int]((m shr n) and 0x0F)
|
||||||
|
if c < 10:
|
||||||
|
result.add(chr(ord('0') + c))
|
||||||
|
else:
|
||||||
|
result.add(chr(ord('A') + (c - 10)))
|
||||||
|
elif host.family == AddressFamily.IPv6:
|
||||||
|
result = if include0x: "0x" else: ""
|
||||||
|
for i in 0..1:
|
||||||
|
var n = 64
|
||||||
|
var m = host.mask6[i]
|
||||||
|
while n > 0:
|
||||||
|
n -= 4
|
||||||
|
var c = cast[int]((m shr n) and 0x0F)
|
||||||
|
if c < 10:
|
||||||
|
result.add(chr(ord('0') + c))
|
||||||
|
else:
|
||||||
|
result.add(chr(ord('A') + (c - 10)))
|
||||||
|
else:
|
||||||
|
raise newException(ValueError, "Invalid mask")
|
||||||
|
|
||||||
|
proc ip*(mask: IpMask): string =
|
||||||
|
## Returns IP address text representation of IP mask ``mask``.
|
||||||
|
if mask.family == AddressFamily.IPv4:
|
||||||
|
var ip = IpAddress(family: IpAddressFamily.IPv4)
|
||||||
|
copyMem(addr ip.address_v4[0], unsafeAddr mask.mask4, sizeof(uint32))
|
||||||
|
result = $ip
|
||||||
|
elif mask.family == AddressFamily.IPv6:
|
||||||
|
var ip = IpAddress(family: IpAddressFamily.IPv6)
|
||||||
|
copyMem(addr ip.address_v6[0], unsafeAddr mask.mask6[0], 16)
|
||||||
|
result = $ip
|
||||||
|
else:
|
||||||
|
raise newException(ValueError, "Invalid mask")
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpNet], host: TransportAddress,
|
||||||
|
prefix: int): IpNet {.inline.} =
|
||||||
|
## Initialize IP Network using host address ``host`` and prefix length
|
||||||
|
## ``prefix``.
|
||||||
|
result.mask = IpMask.init(host.family, prefix)
|
||||||
|
result.host = host
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpNet], host, mask: TransportAddress): IpNet {.inline.} =
|
||||||
|
## Initialize IP Network using host address ``host`` and network mask
|
||||||
|
## address ``mask``.
|
||||||
|
##
|
||||||
|
## Note that ``host`` and ``mask`` must be from the same IP family.
|
||||||
|
if host.family == mask.family:
|
||||||
|
result.mask = IpMask.init(mask)
|
||||||
|
result.host = host
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpNet], host: TransportAddress,
|
||||||
|
mask: IpMask): IpNet {.inline.} =
|
||||||
|
## Initialize IP Network using host address ``host`` and network mask
|
||||||
|
## ``mask``.
|
||||||
|
result.mask = mask
|
||||||
|
result.host = host
|
||||||
|
|
||||||
|
proc init*(t: typedesc[IpNet], network: string): IpNet =
|
||||||
|
## Initialize IP Network from string representation in format
|
||||||
|
## <address>/<prefix length> or <address>/<netmask address>.
|
||||||
|
var parts = network.rsplit("/", maxsplit = 1)
|
||||||
|
var host, mhost: TransportAddress
|
||||||
|
var ipaddr: IpAddress
|
||||||
|
var mask: IpMask
|
||||||
|
var prefix: int
|
||||||
|
try:
|
||||||
|
ipaddr = parseIpAddress(parts[0])
|
||||||
|
if ipaddr.family == IpAddressFamily.IPv4:
|
||||||
|
host = TransportAddress(family: AddressFamily.IPv4)
|
||||||
|
host.address_v4 = ipaddr.address_v4
|
||||||
|
prefix = 32
|
||||||
|
elif ipaddr.family == IpAddressFamily.IPv6:
|
||||||
|
host = TransportAddress(family: AddressFamily.IPv6)
|
||||||
|
host.address_v6 = ipaddr.address_v6
|
||||||
|
prefix = 128
|
||||||
|
if len(parts) > 1:
|
||||||
|
try:
|
||||||
|
prefix = parseInt(parts[1])
|
||||||
|
except:
|
||||||
|
prefix = -1
|
||||||
|
if prefix == -1:
|
||||||
|
ipaddr = parseIpAddress(parts[1])
|
||||||
|
if ipaddr.family == IpAddressFamily.IPv4:
|
||||||
|
mhost = TransportAddress(family: AddressFamily.IPv4)
|
||||||
|
mhost.address_v4 = ipaddr.address_v4
|
||||||
|
elif ipaddr.family == IpAddressFamily.IPv6:
|
||||||
|
mhost = TransportAddress(family: AddressFamily.IPv6)
|
||||||
|
mhost.address_v6 = ipaddr.address_v6
|
||||||
|
mask = IpMask.init(mhost)
|
||||||
|
if mask.family != host.family:
|
||||||
|
raise newException(TransportAddressError,
|
||||||
|
"Incorrect network address!")
|
||||||
|
else:
|
||||||
|
if (ipaddr.family == IpAddressFamily.IPv4 and
|
||||||
|
(prefix < 0 or prefix > 32)) or
|
||||||
|
(ipaddr.family == IpAddressFamily.IPv6 and
|
||||||
|
(prefix < 0 or prefix > 128)):
|
||||||
|
raise newException(TransportAddressError,
|
||||||
|
"Incorrect network address!")
|
||||||
|
if prefix == -1:
|
||||||
|
result = t.init(host, mask)
|
||||||
|
else:
|
||||||
|
result = t.init(host, prefix)
|
||||||
|
except:
|
||||||
|
raise newException(TransportAddressError, "Incorrect network address!")
|
||||||
|
|
||||||
|
proc `==`*(n1, n2: IpNet): bool {.inline.} =
|
||||||
|
## Returns ``true`` if networks ``n1`` and ``n2`` are equal in IP family and
|
||||||
|
## by value.
|
||||||
|
if n1.host.family == n2.host.family:
|
||||||
|
if n1.host.family == AddressFamily.IPv4:
|
||||||
|
result = (n1.host.address_v4 == n2.host.address_v4) and
|
||||||
|
(n1.mask == n2.mask)
|
||||||
|
elif n1.host.family == AddressFamily.IPv6:
|
||||||
|
result = (n1.host.address_v6 == n2.host.address_v6) and
|
||||||
|
(n1.mask == n2.mask)
|
||||||
|
|
||||||
|
proc contains*(net: IpNet, address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` belongs to IP Network ``net``
|
||||||
|
if net.host.family == address.family:
|
||||||
|
var host1 = mask(address, net.mask)
|
||||||
|
var host2 = mask(net.host, net.mask)
|
||||||
|
host2.port = host1.port
|
||||||
|
result = (host1 == host2)
|
||||||
|
|
||||||
|
proc broadcast*(net: IpNet): TransportAddress =
|
||||||
|
## Returns broadcast address for IP Network ``net``.
|
||||||
|
result = TransportAddress(family: net.host.family)
|
||||||
|
if result.family == AddressFamily.IPv4:
|
||||||
|
let address = cast[ptr uint32](unsafeAddr net.host.address_v4[0])[]
|
||||||
|
let mask = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = address or (not(mask))
|
||||||
|
elif result.family == AddressFamily.IPv6:
|
||||||
|
let address0 = cast[ptr uint64](unsafeAddr net.host.address_v6[0])[]
|
||||||
|
let address1 = cast[ptr uint64](unsafeAddr net.host.address_v6[8])[]
|
||||||
|
let data0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr net.mask.mask6[1])[]
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = address0 or (not(data0))
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = address1 or (not(data1))
|
||||||
|
|
||||||
|
proc subnetMask*(net: IpNet): TransportAddress =
|
||||||
|
## Returns netmask address for IP Network ``net``.
|
||||||
|
result = TransportAddress(family: net.host.family)
|
||||||
|
if result.family == AddressFamily.IPv4:
|
||||||
|
let address = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = address
|
||||||
|
elif result.family == AddressFamily.IPv6:
|
||||||
|
let address0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
||||||
|
let address1 = cast[ptr uint64](unsafeAddr net.mask.mask6[1])[]
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = address0
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = address1
|
||||||
|
|
||||||
|
proc network*(net: IpNet): TransportAddress {.inline.} =
|
||||||
|
## Returns network address (host address masked with network mask) for
|
||||||
|
## IP Network ``net``.
|
||||||
|
result = mask(net.host, net.mask)
|
||||||
|
|
||||||
|
proc `and`*(address1, address2: TransportAddress): TransportAddress =
|
||||||
|
## Bitwise ``and`` operation for ``address1 and address2``.
|
||||||
|
##
|
||||||
|
## Note only IPv4 and IPv6 addresses are supported. ``address1`` and
|
||||||
|
## ``address2`` must be in equal IP family
|
||||||
|
if address1.family == address2.family:
|
||||||
|
if address1.family == AddressFamily.IPv4:
|
||||||
|
let data1 = cast[ptr uint32](unsafeAddr address1.address_v4[0])[]
|
||||||
|
let data2 = cast[ptr uint32](unsafeAddr address2.address_v4[0])[]
|
||||||
|
result = TransportAddress(family: address1.family)
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = data1 and data2
|
||||||
|
elif address1.family == AddressFamily.IPv6:
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr address1.address_v6[0])[]
|
||||||
|
let data2 = cast[ptr uint64](unsafeAddr address1.address_v6[8])[]
|
||||||
|
let data3 = cast[ptr uint64](unsafeAddr address2.address_v6[0])[]
|
||||||
|
let data4 = cast[ptr uint64](unsafeAddr address2.address_v6[8])[]
|
||||||
|
result = TransportAddress(family: address1.family)
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = data1 and data3
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = data2 and data4
|
||||||
|
|
||||||
|
proc `or`*(address1, address2: TransportAddress): TransportAddress =
|
||||||
|
## Bitwise ``or`` operation for ``address1 or address2``.
|
||||||
|
##
|
||||||
|
## Note only IPv4 and IPv6 addresses are supported. ``address1`` and
|
||||||
|
## ``address2`` must be in equal IP family
|
||||||
|
if address1.family == address2.family:
|
||||||
|
if address1.family == AddressFamily.IPv4:
|
||||||
|
let data1 = cast[ptr uint32](unsafeAddr address1.address_v4[0])[]
|
||||||
|
let data2 = cast[ptr uint32](unsafeAddr address2.address_v4[0])[]
|
||||||
|
result = TransportAddress(family: address1.family)
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = data1 or data2
|
||||||
|
elif address1.family == AddressFamily.IPv6:
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr address1.address_v6[0])[]
|
||||||
|
let data2 = cast[ptr uint64](unsafeAddr address1.address_v6[8])[]
|
||||||
|
let data3 = cast[ptr uint64](unsafeAddr address2.address_v6[0])[]
|
||||||
|
let data4 = cast[ptr uint64](unsafeAddr address2.address_v6[8])[]
|
||||||
|
result = TransportAddress(family: address1.family)
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = data1 or data3
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = data2 or data4
|
||||||
|
|
||||||
|
proc `not`*(address: TransportAddress): TransportAddress =
|
||||||
|
## Bitwise ``not`` operation for ``address``.
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
let data = cast[ptr uint32](unsafeAddr address.address_v4[0])[]
|
||||||
|
result = TransportAddress(family: address.family)
|
||||||
|
cast[ptr uint32](addr result.address_v4[0])[] = not(data)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr address.address_v6[0])[]
|
||||||
|
let data2 = cast[ptr uint64](unsafeAddr address.address_v6[8])[]
|
||||||
|
result = TransportAddress(family: address.family)
|
||||||
|
cast[ptr uint64](addr result.address_v6[0])[] = not(data1)
|
||||||
|
cast[ptr uint64](addr result.address_v6[8])[] = not(data2)
|
||||||
|
|
||||||
|
proc `+`*(address: TransportAddress, v: uint): TransportAddress =
|
||||||
|
## Add to IPv4/IPv6 transport ``address`` unsigned integer ``v``.
|
||||||
|
result = TransportAddress(family: address.family)
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
var a: uint64
|
||||||
|
let data = cast[ptr uint32](unsafeAddr address.address_v4[0])
|
||||||
|
when system.cpuEndian == bigEndian:
|
||||||
|
a = data
|
||||||
|
else:
|
||||||
|
swapEndian32(addr a, data)
|
||||||
|
a = a + v
|
||||||
|
bigEndian32(cast[pointer](addr result.address_v4[0]), addr a)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
var a1, a2: uint64
|
||||||
|
let data1 = cast[ptr uint64](unsafeAddr address.address_v6[0])
|
||||||
|
let data2 = cast[ptr uint64](unsafeAddr address.address_v6[8])
|
||||||
|
when system.cpuEndian == bigEndian:
|
||||||
|
a1 = data1
|
||||||
|
a2 = data2
|
||||||
|
else:
|
||||||
|
swapEndian64(addr a1, data1)
|
||||||
|
swapEndian64(addr a2, data2)
|
||||||
|
var a3 = a2 + v
|
||||||
|
if a3 < a2:
|
||||||
|
## Overflow
|
||||||
|
a1 = a1 + 1
|
||||||
|
bigEndian64(cast[pointer](addr result.address_v6[0]), addr a1)
|
||||||
|
bigEndian64(cast[pointer](addr result.address_v6[8]), addr a3)
|
||||||
|
|
||||||
|
proc inc*(address: var TransportAddress, v: uint = 1'u) =
|
||||||
|
## Increment IPv4/IPv6 transport ``address`` by unsigned integer ``v``.
|
||||||
|
address = address + v
|
||||||
|
|
||||||
|
proc `$`*(net: IpNet): string =
|
||||||
|
## Return string representation of IP network in format:
|
||||||
|
## <IPv4 or IPv6 address>/<prefix length>.
|
||||||
|
if net.host.family == AddressFamily.IPv4:
|
||||||
|
var a = IpAddress(family: IpAddressFamily.IPv4,
|
||||||
|
address_v4: net.host.address_v4)
|
||||||
|
result = $a
|
||||||
|
result.add("/")
|
||||||
|
let prefix = net.mask.prefix()
|
||||||
|
if prefix == -1:
|
||||||
|
result.add(net.mask.ip())
|
||||||
|
else:
|
||||||
|
result.add($prefix)
|
||||||
|
elif net.host.family == AddressFamily.IPv6:
|
||||||
|
var a = IpAddress(family: IpAddressFamily.IPv6,
|
||||||
|
address_v6: net.host.address_v6)
|
||||||
|
result = $a
|
||||||
|
result.add("/")
|
||||||
|
let prefix = net.mask.prefix()
|
||||||
|
if prefix == -1:
|
||||||
|
result.add(net.mask.ip())
|
||||||
|
else:
|
||||||
|
result.add($prefix)
|
||||||
|
|
||||||
|
proc isUnspecified*(address: TransportAddress): bool {.inline.} =
|
||||||
|
## Returns ``true`` if ``address`` is not specified yet, e.g. its ``family``
|
||||||
|
## field is not set or equal to ``AddressFamily.None``.
|
||||||
|
if address.family == AddressFamily.None:
|
||||||
|
result = true
|
||||||
|
|
||||||
|
proc isZero*(address: TransportAddress): bool {.inline.} =
|
||||||
|
## Returns ``true`` if ``address`` is full of zeros, but its ``family`` is
|
||||||
|
## not ``AddressFamily.None``.
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = cast[ptr uint32](unsafeAddr address.address_v4[0])[] == 0'u32
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
let r1 = cast[ptr uint64](unsafeAddr address.address_v6[0])[] == 0'u64
|
||||||
|
let r2 = cast[ptr uint64](unsafeAddr address.address_v6[8])[] == 0'u64
|
||||||
|
result = r1 and r2
|
||||||
|
elif address.family == AddressFamily.Unix:
|
||||||
|
result = len($cast[cstring](unsafeAddr address.address_un[0])) == 0
|
||||||
|
|
||||||
|
proc isMulticast*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is a multicast address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 224.0.0.0 - 239.255.255.255
|
||||||
|
##
|
||||||
|
## ``IPv6``: FF00:: - FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = ((address.address_v4[0] and 0xF0'u8) == 0xE0'u8)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFF'u8)
|
||||||
|
|
||||||
|
proc isInterfaceLocalMulticast*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is interface local multicast address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: N/A (always returns ``false``)
|
||||||
|
if address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFF'u8) and
|
||||||
|
((address.address_v6[1] and 0x0F'u8) == 0x01'u8)
|
||||||
|
|
||||||
|
proc isLinkLocalMulticast*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address` is link local multicast address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 224.0.0.0 - 224.0.0.255
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = (address.address_v4[0] == 224'u8) and
|
||||||
|
(address.address_v4[1] == 0'u8) and
|
||||||
|
(address.address_v4[2] == 0'u8)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFF'u8) and
|
||||||
|
((address.address_v6[1] and 0x0F'u8) == 0x02'u8)
|
||||||
|
|
||||||
|
proc isLoopback*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is loopback address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 127.0.0.0 - 127.255.255.255
|
||||||
|
##
|
||||||
|
## ``IPv6``: ::1
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = (address.address_v4[0] == 127'u8)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
var test = 0
|
||||||
|
for i in 0..<(len(address.address_v6) - 1):
|
||||||
|
test = test or cast[int](address.address_v6[i])
|
||||||
|
result = (test == 0) and (address.address_v6[15] == 1'u8)
|
||||||
|
|
||||||
|
proc isAnyLocal*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is a wildcard address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 0.0.0.0
|
||||||
|
##
|
||||||
|
## ``IPv6``: ::
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
let data = cast[ptr uint32](unsafeAddr address.address_v4[0])[]
|
||||||
|
result = (data == 0'u32)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
let data1 = cast[ptr uint32](unsafeAddr address.address_v6[0])[]
|
||||||
|
let data2 = cast[ptr uint32](unsafeAddr address.address_v6[4])[]
|
||||||
|
let data3 = cast[ptr uint32](unsafeAddr address.address_v6[8])[]
|
||||||
|
let data4 = cast[ptr uint32](unsafeAddr address.address_v6[12])[]
|
||||||
|
result = ((data1 or data2 or data3 or data4) == 0'u32)
|
||||||
|
|
||||||
|
proc isLinkLocal*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is link local address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 169.254.0.0 - 169.254.255.255
|
||||||
|
##
|
||||||
|
## ``IPv6``: FE80:: - FEBF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = (address.address_v4[0] == 169'u8) and
|
||||||
|
(address.address_v4[1] == 254'u8)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFE'u8) and
|
||||||
|
((address.address_v6[1] and 0xC0'u8) == 0x80'u8)
|
||||||
|
|
||||||
|
proc isLinkLocalUnicast*(address: TransportAddress): bool {.inline.} =
|
||||||
|
result = isLinkLocal(address)
|
||||||
|
|
||||||
|
proc isSiteLocal*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if ``address`` is site local address.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 10.0.0.0 - 10.255.255.255, 172.16.0.0 - 172.31.255.255,
|
||||||
|
## 192.168.0.0 - 192.168.255.255
|
||||||
|
##
|
||||||
|
## ``IPv6``: FEC0:: - FEFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = (address.address_v4[0] == 10'u8) or
|
||||||
|
((address.address_v4[0] == 172'u8) and
|
||||||
|
((address.address_v4[1] and 0xF0) == 16)) or
|
||||||
|
((address.address_v4[0] == 192'u8) and
|
||||||
|
((address.address_v4[1] == 168'u8)))
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFE'u8) and
|
||||||
|
((address.address_v6[1] and 0xC0'u8) == 0xC0'u8)
|
||||||
|
|
||||||
|
proc isGlobalMulticast*(address: TransportAddress): bool =
|
||||||
|
## Returns ``true`` if the multicast address has global scope.
|
||||||
|
##
|
||||||
|
## ``IPv4``: 224.0.1.0 - 238.255.255.255
|
||||||
|
##
|
||||||
|
## ``IPv6``: FF0E:: - FFFE:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
|
||||||
|
if address.family == AddressFamily.IPv4:
|
||||||
|
result = (address.address_v4[0] >= 224'u8) and
|
||||||
|
(address.address_v4[0] <= 238'u8) and
|
||||||
|
not(
|
||||||
|
(address.address_v4[0] == 224'u8) and
|
||||||
|
(address.address_v4[1] == 0'u8) and
|
||||||
|
(address.address_v4[2] == 0'u8)
|
||||||
|
)
|
||||||
|
elif address.family == AddressFamily.IPv6:
|
||||||
|
result = (address.address_v6[0] == 0xFF'u8) and
|
||||||
|
((address.address_v6[1] and 0x0F'u8) == 0x0E'u8)
|
File diff suppressed because it is too large
Load Diff
|
@ -6,4 +6,4 @@
|
||||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
# MIT license (LICENSE-MIT)
|
# MIT license (LICENSE-MIT)
|
||||||
import testsync, testsoon, testtime, testfut, testsignal, testaddress,
|
import testsync, testsoon, testtime, testfut, testsignal, testaddress,
|
||||||
testdatagram, teststream, testserver, testbugs
|
testdatagram, teststream, testserver, testbugs, testnet
|
||||||
|
|
|
@ -476,7 +476,7 @@ suite "Datagram Transport test suite":
|
||||||
inc(res)
|
inc(res)
|
||||||
transp.close()
|
transp.close()
|
||||||
var dgram1 = newDatagramTransport(clientMark, local = ta1,
|
var dgram1 = newDatagramTransport(clientMark, local = ta1,
|
||||||
flags = {Broadcast})
|
flags = {Broadcast}, ttl = 2)
|
||||||
await dgram1.sendTo(bta, expectMessage)
|
await dgram1.sendTo(bta, expectMessage)
|
||||||
await wait(dgram1.join(), 5.seconds)
|
await wait(dgram1.join(), 5.seconds)
|
||||||
result = res
|
result = res
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
# Chronos Test Suite
|
||||||
|
# (c) Copyright 2018-Present
|
||||||
|
# Status Research & Development GmbH
|
||||||
|
#
|
||||||
|
# Licensed under either of
|
||||||
|
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||||
|
# MIT license (LICENSE-MIT)
|
||||||
|
import unittest
|
||||||
|
import ../chronos
|
||||||
|
|
||||||
|
suite "Network utilities test suite":
|
||||||
|
test "IPv4 networks test":
|
||||||
|
var a: TransportAddress
|
||||||
|
check:
|
||||||
|
a.isUnspecified() == true
|
||||||
|
initTAddress("0.0.0.0:0").isUnspecified() == false
|
||||||
|
|
||||||
|
initTAddress("0.0.0.0:0").isZero() == true
|
||||||
|
initTAddress("1.0.0.0:0").isZero() == false
|
||||||
|
|
||||||
|
initTAddress("127.0.0.0:0").isLoopback() == true
|
||||||
|
initTAddress("127.255.255.255:0").isLoopback() == true
|
||||||
|
initTAddress("128.0.0.0:0").isLoopback() == false
|
||||||
|
initTAddress("126.0.0.0:0").isLoopback() == false
|
||||||
|
|
||||||
|
initTAddress("224.0.0.0:0").isMulticast() == true
|
||||||
|
initTAddress("230.0.0.0:0").isMulticast() == true
|
||||||
|
initTAddress("239.255.255.255:0").isMulticast() == true
|
||||||
|
initTAddress("240.0.0.0:0").isMulticast() == false
|
||||||
|
initTAddress("223.0.0.0:0").isMulticast() == false
|
||||||
|
|
||||||
|
initTAddress("224.0.0.0:0").isLinkLocalMulticast() == true
|
||||||
|
initTAddress("224.0.0.255:0").isLinkLocalMulticast() == true
|
||||||
|
initTAddress("225.0.0.0:0").isLinkLocalMulticast() == false
|
||||||
|
initTAddress("224.0.1.0:0").isLinkLocalMulticast() == false
|
||||||
|
|
||||||
|
initTAddress("0.0.0.0:0").isAnyLocal() == true
|
||||||
|
initTAddress("1.0.0.0:0").isAnyLocal() == false
|
||||||
|
|
||||||
|
initTAddress("169.254.0.0:0").isLinkLocal() == true
|
||||||
|
initTAddress("169.254.255.255:0").isLinkLocal() == true
|
||||||
|
initTAddress("169.255.0.0:0").isLinkLocal() == false
|
||||||
|
initTAddress("169.253.0.0:0").isLinkLocal() == false
|
||||||
|
|
||||||
|
initTAddress("10.0.0.0:0").isSiteLocal() == true
|
||||||
|
initTAddress("10.255.255.255:0").isSiteLocal() == true
|
||||||
|
initTAddress("11.0.0.0:0").isSiteLocal() == false
|
||||||
|
initTAddress("9.0.0.0:0").isSiteLocal() == false
|
||||||
|
initTAddress("172.16.0.0:0").isSiteLocal() == true
|
||||||
|
initTAddress("172.31.255.255:0").isSiteLocal() == true
|
||||||
|
initTAddress("172.15.0.0:0").isSiteLocal() == false
|
||||||
|
initTAddress("172.32.0.0:0").isSiteLocal() == false
|
||||||
|
initTAddress("192.168.0.0:0").isSiteLocal() == true
|
||||||
|
initTAddress("192.168.255.255:0").isSiteLocal() == true
|
||||||
|
initTAddress("192.167.0.0:0").isSiteLocal() == false
|
||||||
|
initTAddress("192.169.0.0:0").isSiteLocal() == false
|
||||||
|
|
||||||
|
initTAddress("224.0.1.0:0").isGlobalMulticast() == true
|
||||||
|
initTAddress("238.255.255.255:0").isGlobalMulticast() == true
|
||||||
|
initTAddress("224.0.0.0:0").isGlobalMulticast() == false
|
||||||
|
initTAddress("239.0.0.0:0").isGlobalMulticast() == false
|
||||||
|
|
||||||
|
test "IPv6 networks test":
|
||||||
|
check:
|
||||||
|
initTAddress("[::]:0").isUnspecified() == false
|
||||||
|
|
||||||
|
initTAddress("[::]:0").isZero() == true
|
||||||
|
initTAddress("[::1]:0").isZero() == false
|
||||||
|
|
||||||
|
initTAddress("[::1]:0").isLoopback() == true
|
||||||
|
initTAddress("[::2]:0").isLoopback() == false
|
||||||
|
|
||||||
|
initTAddress("[FF00::]:0").isMulticast() == true
|
||||||
|
initTAddress("[FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]:0").isMulticast() == true
|
||||||
|
initTAddress("[F000::]:0").isMulticast() == false
|
||||||
|
|
||||||
|
initTAddress("[::]:0").isAnyLocal() == true
|
||||||
|
initTAddress("[::1]:0").isAnyLocal() == false
|
||||||
|
|
||||||
|
initTAddress("[FE80::]:0").isLinkLocal() == true
|
||||||
|
initTAddress("[FEBF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]:0").isLinkLocal() == true
|
||||||
|
initTAddress("[FE7F::]:0").isLinkLocal() == false
|
||||||
|
initTAddress("[FEC0::]:0").isLinkLocal() == false
|
||||||
|
|
||||||
|
initTAddress("[FEC0::]:0").isSiteLocal() == true
|
||||||
|
initTAddress("[FEFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]:0").isSiteLocal() == true
|
||||||
|
initTAddress("[FEBF::]:0").isSiteLocal() == false
|
||||||
|
initTAddress("[FF00::]:0").isSiteLocal() == false
|
||||||
|
|
||||||
|
initTAddress("[FF0E::]:0").isGlobalMulticast() == true
|
||||||
|
initTAddress("[FFFE:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF]:0").isGlobalMulticast() == true
|
||||||
|
initTAddress("[FF0D::]:0").isGlobalMulticast() == false
|
||||||
|
initTAddress("[FFFF::]:0").isGlobalMulticast() == false
|
||||||
|
|
||||||
|
test "IP masks test":
|
||||||
|
check:
|
||||||
|
$IpMask.init(AddressFamily.IPv4, -1) == "00000000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 0) == "00000000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 4) == "F0000000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 8) == "FF000000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 12) == "FFF00000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 16) == "FFFF0000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 20) == "FFFFF000"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 24) == "FFFFFF00"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 28) == "FFFFFFF0"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 32) == "FFFFFFFF"
|
||||||
|
$IpMask.init(AddressFamily.IPv4, 33) == "FFFFFFFF"
|
||||||
|
|
||||||
|
IpMask.init(AddressFamily.IPv4, -1) == IpMask.init("00000000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 0) == IpMask.init("00000000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 4) == IpMask.init("F0000000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 8) == IpMask.init("FF000000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 12) == IpMask.init("FFF00000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 16) == IpMask.init("FFFF0000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 20) == IpMask.init("FFFFF000")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 24) == IpMask.init("FFFFFF00")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 28) == IpMask.init("FFFFFFF0")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 32) == IpMask.init("FFFFFFFF")
|
||||||
|
IpMask.init(AddressFamily.IPv4, 33) == IpMask.init("FFFFFFFF")
|
||||||
|
|
||||||
|
IpMask.init(initTAddress("255.0.0.0:0")) == IpMask.initIp("255.0.0.0")
|
||||||
|
IpMask.init(initTAddress("255.255.0.0:0")) == IpMask.initIp("255.255.0.0")
|
||||||
|
IpMask.init(initTAddress("255.255.255.0:0")) ==
|
||||||
|
IpMask.initIp("255.255.255.0")
|
||||||
|
IpMask.init(initTAddress("255.255.255.255:0")) ==
|
||||||
|
IpMask.initIp("255.255.255.255")
|
||||||
|
|
||||||
|
IpMask.init("00000000").prefix() == 0
|
||||||
|
IpMask.init("F0000000").prefix() == 4
|
||||||
|
IpMask.init("FF000000").prefix() == 8
|
||||||
|
IpMask.init("FFF00000").prefix() == 12
|
||||||
|
IpMask.init("FFFF0000").prefix() == 16
|
||||||
|
IpMask.init("FFFFF000").prefix() == 20
|
||||||
|
IpMask.init("FFFFFF00").prefix() == 24
|
||||||
|
IpMask.init("FFFFFFF0").prefix() == 28
|
||||||
|
IpMask.init("FFFFFFFF").prefix() == 32
|
||||||
|
|
||||||
|
IpMask.init("00000000").subnetMask() == initTAddress("0.0.0.0:0")
|
||||||
|
IpMask.init("F0000000").subnetMask() == initTAddress("240.0.0.0:0")
|
||||||
|
IpMask.init("FF000000").subnetMask() == initTAddress("255.0.0.0:0")
|
||||||
|
IpMask.init("FFF00000").subnetMask() == initTAddress("255.240.0.0:0")
|
||||||
|
IpMask.init("FFFF0000").subnetMask() == initTAddress("255.255.0.0:0")
|
||||||
|
IpMask.init("FFFFF000").subnetMask() == initTAddress("255.255.240.0:0")
|
||||||
|
IpMask.init("FFFFFF00").subnetMask() == initTAddress("255.255.255.0:0")
|
||||||
|
IpMask.init("FFFFFFF0").subnetMask() == initTAddress("255.255.255.240:0")
|
||||||
|
IpMask.init("FFFFFFFF").subnetMask() == initTAddress("255.255.255.255:0")
|
||||||
|
|
||||||
|
IpMask.init("00000000").ip() == "0.0.0.0"
|
||||||
|
IpMask.init("F0000000").ip() == "240.0.0.0"
|
||||||
|
IpMask.init("FF000000").ip() == "255.0.0.0"
|
||||||
|
IpMask.init("FFF00000").ip() == "255.240.0.0"
|
||||||
|
IpMask.init("FFFF0000").ip() == "255.255.0.0"
|
||||||
|
IpMask.init("FFFFF000").ip() == "255.255.240.0"
|
||||||
|
IpMask.init("FFFFFF00").ip() == "255.255.255.0"
|
||||||
|
IpMask.init("FFFFFFF0").ip() == "255.255.255.240"
|
||||||
|
IpMask.init("FFFFFFFF").ip() == "255.255.255.255"
|
||||||
|
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("00000000")) ==
|
||||||
|
initTAddress("0.0.0.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("F0000000")) ==
|
||||||
|
initTAddress("240.0.0.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FF000000")) ==
|
||||||
|
initTAddress("241.0.0.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFF00000")) ==
|
||||||
|
initTAddress("241.240.0.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFFF0000")) ==
|
||||||
|
initTAddress("241.241.0.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFFFF000")) ==
|
||||||
|
initTAddress("241.241.240.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFFFFF00")) ==
|
||||||
|
initTAddress("241.241.241.0:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFFFFFF0")) ==
|
||||||
|
initTAddress("241.241.241.240:0")
|
||||||
|
initTAddress("241.241.241.241:0").mask(IpMask.init("FFFFFFFF")) ==
|
||||||
|
initTAddress("241.241.241.241:0")
|
||||||
|
|
||||||
|
test "IP networks test":
|
||||||
|
check:
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 0) ==
|
||||||
|
IpNet.init("192.168.0.1/0.0.0.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 4) ==
|
||||||
|
IpNet.init("192.168.0.1/240.0.0.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 8) ==
|
||||||
|
IpNet.init("192.168.0.1/255.0.0.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 12) ==
|
||||||
|
IpNet.init("192.168.0.1/255.240.0.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 16) ==
|
||||||
|
IpNet.init("192.168.0.1/255.255.0.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 20) ==
|
||||||
|
IpNet.init("192.168.0.1/255.255.240.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 24) ==
|
||||||
|
IpNet.init("192.168.0.1/255.255.255.0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 28) ==
|
||||||
|
IpNet.init("192.168.0.1/255.255.255.240")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 32) ==
|
||||||
|
IpNet.init("192.168.0.1/255.255.255.255")
|
||||||
|
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 0) ==
|
||||||
|
IpNet.init("192.168.0.1/0")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 4) ==
|
||||||
|
IpNet.init("192.168.0.1/4")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 8) ==
|
||||||
|
IpNet.init("192.168.0.1/8")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 12) ==
|
||||||
|
IpNet.init("192.168.0.1/12")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 16) ==
|
||||||
|
IpNet.init("192.168.0.1/16")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 20) ==
|
||||||
|
IpNet.init("192.168.0.1/20")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 24) ==
|
||||||
|
IpNet.init("192.168.0.1/24")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 28) ==
|
||||||
|
IpNet.init("192.168.0.1/28")
|
||||||
|
IpNet.init(initTAddress("192.168.0.1:0"), 32) ==
|
||||||
|
IpNet.init("192.168.0.1/32")
|
||||||
|
|
||||||
|
IpNet.init("192.168.0.1/24").contains(initTAddress("192.168.0.1:0")) ==
|
||||||
|
true
|
||||||
|
IpNet.init("192.168.0.1/24").contains(initTAddress("192.168.0.128:0")) ==
|
||||||
|
true
|
||||||
|
IpNet.init("192.168.0.1/24").contains(initTAddress("192.168.0.255:0")) ==
|
||||||
|
true
|
||||||
|
IpNet.init("192.168.0.1/24").contains(initTAddress("192.168.1.0:0")) ==
|
||||||
|
false
|
||||||
|
IpNet.init("192.168.0.1/0").contains(initTAddress("1.1.1.1:0")) ==
|
||||||
|
true
|
||||||
|
IpNet.init("192.168.0.1/32").contains(initTAddress("192.168.0.1:0")) ==
|
||||||
|
true
|
||||||
|
IpNet.init("192.168.0.1/32").contains(initTAddress("192.168.0.2:0")) ==
|
||||||
|
false
|
||||||
|
|
||||||
|
test "IPv4 <-> IPv6 mapping test":
|
||||||
|
check:
|
||||||
|
initTAddress("255.255.255.255:0").toIPv6() ==
|
||||||
|
initTAddress("[::FFFF:FFFF:FFFF]:0")
|
||||||
|
initTAddress("128.128.128.128:0").toIPv6() ==
|
||||||
|
initTAddress("[::FFFF:8080:8080]:0")
|
||||||
|
initTAddress("1.1.1.1:0").toIPv6() == initTAddress("[::FFFF:0101:0101]:0")
|
||||||
|
initTAddress("0.0.0.0:0").toIPv6() == initTAddress("[::FFFF:0000:0000]:0")
|
||||||
|
initTAddress("[::FFFF:FFFF:FFFF]:0").isV4Mapped() == true
|
||||||
|
initTAddress("[::FFFF:8080:8080]:0").isV4Mapped() == true
|
||||||
|
initTAddress("[::FFFF:0101:0101]:0").isV4Mapped() == true
|
||||||
|
initTAddress("[::FFFF:0000:0000]:0").isV4Mapped() == true
|
||||||
|
initTAddress("[::FFFF:FFFF:FFFF]:0").toIPv4() ==
|
||||||
|
initTAddress("255.255.255.255:0")
|
||||||
|
initTAddress("[::FFFF:8080:8080]:0").toIPv4() ==
|
||||||
|
initTAddress("128.128.128.128:0")
|
||||||
|
initTAddress("[::FFFF:0101:0101]:0").toIPv4() == initTAddress("1.1.1.1:0")
|
||||||
|
initTAddress("[::FFFF:0000:0000]:0").toIPv4() == initTAddress("0.0.0.0:0")
|
||||||
|
|
||||||
|
test "getInterfaces() test":
|
||||||
|
var ifaces = getInterfaces()
|
||||||
|
check:
|
||||||
|
len(ifaces) > 0
|
||||||
|
for item in ifaces:
|
||||||
|
echo item
|
||||||
|
|
||||||
|
test "getBestRoute() test":
|
||||||
|
var route = getBestRoute(initTAddress("8.8.8.8:0"))
|
||||||
|
check:
|
||||||
|
route.source.isUnspecified() == false
|
||||||
|
route.dest.isUnspecified() == false
|
||||||
|
route.ifIndex != 0
|
||||||
|
echo route
|
Loading…
Reference in New Issue