Move iface.nim and ipnet.nim to proper place.
This commit is contained in:
parent
518d33e26c
commit
4fa5ee3c93
|
@ -1,6 +1,14 @@
|
||||||
import chronos
|
## Nim-LibP2P
|
||||||
|
## Copyright (c) 2018 Status Research & Development GmbH
|
||||||
|
## Licensed under either of
|
||||||
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||||
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||||
|
## at your option.
|
||||||
|
## This file may not be copied, modified, or distributed except according to
|
||||||
|
## those terms.
|
||||||
import algorithm
|
import algorithm
|
||||||
from strutils import toHex
|
from strutils import toHex
|
||||||
|
import ipnet
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxAdapterAddressLength* = 8
|
MaxAdapterAddressLength* = 8
|
||||||
|
@ -221,8 +229,8 @@ type
|
||||||
StatusLowerLayerDown
|
StatusLowerLayerDown
|
||||||
|
|
||||||
InterfaceAddress* = object
|
InterfaceAddress* = object
|
||||||
ifaddr*: TransportAddress
|
host*: TransportAddress
|
||||||
prefix*: int
|
net*: IpNet
|
||||||
|
|
||||||
NetworkInterface* = object
|
NetworkInterface* = object
|
||||||
ifIndex*: int
|
ifIndex*: int
|
||||||
|
@ -236,114 +244,31 @@ type
|
||||||
maclen*: int
|
maclen*: int
|
||||||
addresses*: seq[InterfaceAddress]
|
addresses*: seq[InterfaceAddress]
|
||||||
|
|
||||||
proc host*(ifa: InterfaceAddress): TransportAddress =
|
proc broadcast*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
||||||
## Return host address for ``ifa``.
|
|
||||||
result = ifa.ifaddr
|
|
||||||
|
|
||||||
template setBroadcast(b, nby, nbi) =
|
|
||||||
if nbi == 0:
|
|
||||||
for i in nby..<len(b):
|
|
||||||
b[i] = 0xFF'u8
|
|
||||||
else:
|
|
||||||
let bcast = not cast[byte](0xFF'u8 shl (8 - nbi))
|
|
||||||
b[nby] = b[nby] or bcast
|
|
||||||
for i in (nby + 1)..<len(b):
|
|
||||||
b[i] = 0xFF'u8
|
|
||||||
|
|
||||||
template setNetwork(b, nby, nbi) =
|
|
||||||
if nbi == 0:
|
|
||||||
for i in nby..<len(b):
|
|
||||||
b[i] = 0x00'u8
|
|
||||||
else:
|
|
||||||
let mask = cast[byte](0xFF'u8 shl (8 - nbi))
|
|
||||||
b[nby] = b[nby] and mask
|
|
||||||
for i in (nby + 1)..<len(b):
|
|
||||||
b[i] = 0x00'u8
|
|
||||||
|
|
||||||
template setNetmask(b, nby, nbi) =
|
|
||||||
var mask: byte
|
|
||||||
for i in 0..<nby:
|
|
||||||
b[i] = 0xFF'u8
|
|
||||||
if nbi > 0:
|
|
||||||
mask = cast[byte](0xFF'u8 shl (8 - nbi))
|
|
||||||
if nby < len(b):
|
|
||||||
b[nby] = b[nby] or mask
|
|
||||||
for i in (nby + 1)..<len(b):
|
|
||||||
b[i] = 0x00'u8
|
|
||||||
|
|
||||||
proc broadcast*(ifa: InterfaceAddress): TransportAddress =
|
|
||||||
## Return broadcast address for ``ifa``.
|
## Return broadcast address for ``ifa``.
|
||||||
let nbytes = ifa.prefix div 8
|
result = ifa.net.broadcast()
|
||||||
let nbits = ifa.prefix mod 8
|
|
||||||
result = ifa.ifaddr
|
|
||||||
if result.family == AddressFamily.IPv4:
|
|
||||||
setBroadcast(result.address_v4, nbytes, nbits)
|
|
||||||
elif result.family == AddressFamily.IPv6:
|
|
||||||
setBroadcast(result.address_v6, nbytes, nbits)
|
|
||||||
|
|
||||||
proc network*(ifa: InterfaceAddress): TransportAddress =
|
proc network*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
||||||
## Return network address for ``ifa``.
|
## Return network address for ``ifa``.
|
||||||
let nbytes = ifa.prefix div 8
|
result = ifa.net.network()
|
||||||
let nbits = ifa.prefix mod 8
|
|
||||||
result = ifa.ifaddr
|
|
||||||
if result.family == AddressFamily.IPv4:
|
|
||||||
setNetwork(result.address_v4, nbytes, nbits)
|
|
||||||
elif result.family == AddressFamily.IPv6:
|
|
||||||
setNetwork(result.address_v6, nbytes, nbits)
|
|
||||||
|
|
||||||
proc netmask*(ifa: InterfaceAddress): TransportAddress =
|
proc netmask*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
||||||
## Return network mask for ``ifa``.
|
## Return network mask for ``ifa``.
|
||||||
let nbytes = ifa.prefix div 8
|
result = ifa.net.subnetMask()
|
||||||
let nbits = ifa.prefix mod 8
|
|
||||||
result = TransportAddress(family: ifa.ifaddr.family)
|
|
||||||
if result.family == AddressFamily.IPv4:
|
|
||||||
setNetmask(result.address_v4, nbytes, nbits)
|
|
||||||
elif result.family == AddressFamily.IPv6:
|
|
||||||
setNetmask(result.address_v6, nbytes, nbits)
|
|
||||||
|
|
||||||
proc hostMin*(ifa: InterfaceAddress): TransportAddress =
|
|
||||||
## Return minimum allowed host address for ``ifa``
|
|
||||||
result = ifa.network()
|
|
||||||
if result.family == AddressFamily.IPv4:
|
|
||||||
let last = len(result.address_v4) - 1
|
|
||||||
result.address_v4[last] = result.address_v4[last] + 1
|
|
||||||
elif result.family == AddressFamily.IPv6:
|
|
||||||
let last = len(result.address_v6) - 1
|
|
||||||
result.address_v6[last] = result.address_v6[last] + 1
|
|
||||||
|
|
||||||
proc hostMax*(ifa: InterfaceAddress): TransportAddress =
|
|
||||||
## Return maximum allowed host address for ``ifa``.
|
|
||||||
result = ifa.broadcast()
|
|
||||||
if result.family == AddressFamily.IPv4:
|
|
||||||
let last = len(result.address_v4) - 1
|
|
||||||
result.address_v4[last] = result.address_v4[last] - 1
|
|
||||||
elif result.family == AddressFamily.IPv6:
|
|
||||||
let last = len(result.address_v6) - 1
|
|
||||||
result.address_v6[last] = result.address_v6[last] - 1
|
|
||||||
|
|
||||||
proc init*(ift: typedesc[InterfaceAddress], address: TransportAddress,
|
proc init*(ift: typedesc[InterfaceAddress], address: TransportAddress,
|
||||||
prefix: int): InterfaceAddress =
|
prefix: int): InterfaceAddress =
|
||||||
## Initialize ``InterfaceAddress`` using ``address`` and prefix length
|
## Initialize ``InterfaceAddress`` using ``address`` and prefix length
|
||||||
## ``prefix``.
|
## ``prefix``.
|
||||||
result.ifaddr = address
|
result.host = address
|
||||||
result.prefix = prefix
|
result.net = IpNet.init(address, prefix)
|
||||||
|
|
||||||
proc `$`*(ifa: InterfaceAddress): string =
|
proc `$`*(ifa: InterfaceAddress): string {.inline.} =
|
||||||
## Return string representation of ``ifa``.
|
## Return string representation of ``ifa``.
|
||||||
if ifa.ifaddr.family == AddressFamily.IPv4:
|
if ifa.host.family == AddressFamily.IPv4:
|
||||||
var a = IpAddress(
|
result = $ifa.net
|
||||||
family: IpAddressFamily.IPv4,
|
elif ifa.host.family == AddressFamily.IPv6:
|
||||||
address_v4: ifa.ifaddr.address_v4
|
result = $ifa.net
|
||||||
)
|
|
||||||
result = $a
|
|
||||||
result.add("/")
|
|
||||||
result.add($int(ifa.prefix))
|
|
||||||
elif ifa.ifaddr.family == AddressFamily.IPv6:
|
|
||||||
var a = IpAddress(family: IpAddressFamily.IPv6,
|
|
||||||
address_v6: ifa.ifaddr.address_v6)
|
|
||||||
result = $a
|
|
||||||
result.add("/")
|
|
||||||
result.add($int(ifa.prefix))
|
|
||||||
|
|
||||||
proc `$`*(iface: NetworkInterface): string =
|
proc `$`*(iface: NetworkInterface): string =
|
||||||
## Return string representation of network interface ``iface``.
|
## Return string representation of network interface ``iface``.
|
||||||
|
@ -373,9 +298,9 @@ proc `$`*(iface: NetworkInterface): string =
|
||||||
result.add(":")
|
result.add(":")
|
||||||
for item in iface.addresses:
|
for item in iface.addresses:
|
||||||
result.add("\n ")
|
result.add("\n ")
|
||||||
if item.ifaddr.family == AddressFamily.IPv4:
|
if item.host.family == AddressFamily.IPv4:
|
||||||
result.add("inet ")
|
result.add("inet ")
|
||||||
elif item.ifaddr.family == AddressFamily.IPv6:
|
elif item.host.family == AddressFamily.IPv6:
|
||||||
result.add("inet6 ")
|
result.add("inet6 ")
|
||||||
result.add($item)
|
result.add($item)
|
||||||
result.add(" netmask ")
|
result.add(" netmask ")
|
||||||
|
@ -745,8 +670,8 @@ when defined(linux):
|
||||||
if len(result.addresses) == 0:
|
if len(result.addresses) == 0:
|
||||||
result.addresses = newSeq[InterfaceAddress]()
|
result.addresses = newSeq[InterfaceAddress]()
|
||||||
let prefixLength = cast[int](iaddr.ifa_prefixlen)
|
let prefixLength = cast[int](iaddr.ifa_prefixlen)
|
||||||
result.addresses.add(InterfaceAddress(ifaddr: address,
|
let ifaddr = InterfaceAddress.init(address, prefixLength)
|
||||||
prefix: prefixLength))
|
result.addresses.add(ifaddr)
|
||||||
|
|
||||||
proc getLinks(netfd: SocketHandle, pid: Pid): seq[NetworkInterface] =
|
proc getLinks(netfd: SocketHandle, pid: Pid): seq[NetworkInterface] =
|
||||||
if not sendNetlinkMessage(netfd, pid, 1, RTM_GETLINK,
|
if not sendNetlinkMessage(netfd, pid, 1, RTM_GETLINK,
|
||||||
|
@ -904,26 +829,6 @@ elif defined(macosx) or defined(bsd):
|
||||||
else:
|
else:
|
||||||
result = StatusDown
|
result = StatusDown
|
||||||
|
|
||||||
proc netmaskToPrefix(address: TransportAddress): int =
|
|
||||||
var lastbyte: byte
|
|
||||||
if address.family == AddressFamily.IPv4:
|
|
||||||
for i in 0..<len(address.address_v4):
|
|
||||||
if address.address_v4[i] == 0xFF'u8:
|
|
||||||
result += 8
|
|
||||||
else:
|
|
||||||
lastbyte = address.address_v4[i]
|
|
||||||
break
|
|
||||||
elif address.family == AddressFamily.IPv6:
|
|
||||||
for i in 0..<len(address.address_v6):
|
|
||||||
if address.address_v6[i] == 0xFF'u8:
|
|
||||||
result += 8
|
|
||||||
else:
|
|
||||||
lastbyte = address.address_v6[i]
|
|
||||||
break
|
|
||||||
while lastbyte > 0'u8:
|
|
||||||
lastbyte = lastbyte shl 1
|
|
||||||
result += 1
|
|
||||||
|
|
||||||
proc getInterfaces*(): seq[NetworkInterface] =
|
proc getInterfaces*(): seq[NetworkInterface] =
|
||||||
## Return list of available interfaces.
|
## Return list of available interfaces.
|
||||||
var ifap: ptr IfAddrs
|
var ifap: ptr IfAddrs
|
||||||
|
@ -960,10 +865,10 @@ elif defined(macosx) or defined(bsd):
|
||||||
result[i].mtu = cast[int](data.ifi_mtu)
|
result[i].mtu = cast[int](data.ifi_mtu)
|
||||||
elif family == posix.AF_INET:
|
elif family == posix.AF_INET:
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_addr),
|
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_addr),
|
||||||
Socklen(sizeof(SockAddr_in)), ifaddress.ifaddr)
|
Socklen(sizeof(SockAddr_in)), ifaddress.host)
|
||||||
elif family == posix.AF_INET6:
|
elif family == posix.AF_INET6:
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_addr),
|
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_addr),
|
||||||
Socklen(sizeof(SockAddr_in6)), ifaddress.ifaddr)
|
Socklen(sizeof(SockAddr_in6)), ifaddress.host)
|
||||||
if not isNil(ifap.ifa_netmask):
|
if not isNil(ifap.ifa_netmask):
|
||||||
var na: TransportAddress
|
var na: TransportAddress
|
||||||
var slen: Socklen
|
var slen: Socklen
|
||||||
|
@ -974,9 +879,9 @@ elif defined(macosx) or defined(bsd):
|
||||||
elif family == posix.AF_INET6:
|
elif family == posix.AF_INET6:
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_netmask),
|
fromSAddr(cast[ptr Sockaddr_storage](ifap.ifa_netmask),
|
||||||
Socklen(sizeof(SockAddr_in6)), na)
|
Socklen(sizeof(SockAddr_in6)), na)
|
||||||
ifaddress.prefix = netmaskToPrefix(na)
|
ifaddress.net = IpNet.init(ifaddress.host, na)
|
||||||
|
|
||||||
if ifaddress.ifaddr.family != AddressFamily.None:
|
if ifaddress.host.family != AddressFamily.None:
|
||||||
if len(result[i].addresses) == 0:
|
if len(result[i].addresses) == 0:
|
||||||
result[i].addresses = newSeq[InterfaceAddress]()
|
result[i].addresses = newSeq[InterfaceAddress]()
|
||||||
result[i].addresses.add(ifaddress)
|
result[i].addresses.add(ifaddress)
|
||||||
|
@ -1182,7 +1087,7 @@ elif defined(windows):
|
||||||
vista: bool): InterfaceAddress =
|
vista: bool): InterfaceAddress =
|
||||||
var netfamily = ifunic.address.lpSockaddr.sa_family
|
var netfamily = ifunic.address.lpSockaddr.sa_family
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](ifunic.address.lpSockaddr),
|
fromSAddr(cast[ptr Sockaddr_storage](ifunic.address.lpSockaddr),
|
||||||
SockLen(ifunic.address.iSockaddrLength), result.ifaddr)
|
SockLen(ifunic.address.iSockaddrLength), result.host)
|
||||||
if not vista:
|
if not vista:
|
||||||
var prefix = ifitem.firstPrefix
|
var prefix = ifitem.firstPrefix
|
||||||
var prefixLength = -1
|
var prefixLength = -1
|
||||||
|
@ -1192,15 +1097,15 @@ elif defined(windows):
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](prefix.address.lpSockaddr),
|
fromSAddr(cast[ptr Sockaddr_storage](prefix.address.lpSockaddr),
|
||||||
SockLen(prefix.address.iSockaddrLength), pa)
|
SockLen(prefix.address.iSockaddrLength), pa)
|
||||||
if netfamily == prefamily:
|
if netfamily == prefamily:
|
||||||
if ipMatchPrefix(result.ifaddr, pa, cast[int](prefix.prefixLength)):
|
if ipMatchPrefix(result.host, pa, cast[int](prefix.prefixLength)):
|
||||||
prefixLength = max(prefixLength, cast[int](prefix.prefixLength))
|
prefixLength = max(prefixLength, cast[int](prefix.prefixLength))
|
||||||
prefix = prefix.next
|
prefix = prefix.next
|
||||||
if prefixLength >= 0:
|
if prefixLength >= 0:
|
||||||
result.prefix = prefixLength
|
result.net = IpNet.init(result.host, prefixLength)
|
||||||
else:
|
else:
|
||||||
let prefixLength = cast[int](ifunic.onLinkPrefixLength)
|
let prefixLength = cast[int](ifunic.onLinkPrefixLength)
|
||||||
if prefixLength >= 0:
|
if prefixLength >= 0:
|
||||||
result.prefix = prefixLength
|
result.net = IpNet.init(result.host, prefixLength)
|
||||||
|
|
||||||
proc getInterfaces*(): seq[NetworkInterface] =
|
proc getInterfaces*(): seq[NetworkInterface] =
|
||||||
## Return list of network interfaces.
|
## Return list of network interfaces.
|
||||||
|
@ -1254,8 +1159,3 @@ elif defined(windows):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
{.fatal: "Sorry, your OS is currently not supported!".}
|
{.fatal: "Sorry, your OS is currently not supported!".}
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
var a = getInterfaces()
|
|
||||||
for item in a:
|
|
||||||
echo $item
|
|
|
@ -1,5 +1,15 @@
|
||||||
|
## Nim-LibP2P
|
||||||
|
## Copyright (c) 2018 Status Research & Development GmbH
|
||||||
|
## Licensed under either of
|
||||||
|
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||||
|
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||||
|
## at your option.
|
||||||
|
## This file may not be copied, modified, or distributed except according to
|
||||||
|
## those terms.
|
||||||
|
|
||||||
import endians, strutils
|
import endians, strutils
|
||||||
import chronos
|
import chronos
|
||||||
|
export chronos
|
||||||
|
|
||||||
type
|
type
|
||||||
IpMask* = object
|
IpMask* = object
|
||||||
|
@ -44,6 +54,15 @@ proc toHostOrder(mask: IpMask): IpMask {.inline.} =
|
||||||
swapEndian64(cast[pointer](addr result.mask6[1]),
|
swapEndian64(cast[pointer](addr result.mask6[1]),
|
||||||
cast[pointer](unsafeAddr mask.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 =
|
proc init*(t: typedesc[IpMask], family: AddressFamily, prefix: int): IpMask =
|
||||||
## Initialize mask of IP family ``family`` from prefix length ``prefix``.
|
## Initialize mask of IP family ``family`` from prefix length ``prefix``.
|
||||||
##
|
##
|
||||||
|
@ -85,7 +104,7 @@ proc init*(t: typedesc[IpMask], netmask: TransportAddress): IpMask =
|
||||||
result.mask6[0] = cast[ptr uint64](unsafeAddr netmask.address_v6[0])[]
|
result.mask6[0] = cast[ptr uint64](unsafeAddr netmask.address_v6[0])[]
|
||||||
result.mask6[1] = cast[ptr uint64](unsafeAddr netmask.address_v6[8])[]
|
result.mask6[1] = cast[ptr uint64](unsafeAddr netmask.address_v6[8])[]
|
||||||
|
|
||||||
proc init*(t: typedesc[IpMask], netmask: string): IpMask =
|
proc initIp*(t: typedesc[IpMask], netmask: string): IpMask =
|
||||||
## Initialize network mask using IPv4 or IPv6 address in text representation
|
## Initialize network mask using IPv4 or IPv6 address in text representation
|
||||||
## ``netmask``.
|
## ``netmask``.
|
||||||
##
|
##
|
||||||
|
@ -98,6 +117,58 @@ proc init*(t: typedesc[IpMask], netmask: string): IpMask =
|
||||||
except ValueError:
|
except ValueError:
|
||||||
discard
|
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 =
|
proc toIPv6*(address: TransportAddress): TransportAddress =
|
||||||
## Map IPv4 ``address`` to IPv6 address.
|
## Map IPv4 ``address`` to IPv6 address.
|
||||||
##
|
##
|
||||||
|
@ -188,10 +259,16 @@ proc mask*(a: TransportAddress, m: IpMask): TransportAddress =
|
||||||
|
|
||||||
proc prefix*(mask: IpMask): int =
|
proc prefix*(mask: IpMask): int =
|
||||||
## Returns number of bits set `1` in IP mask ``mask``.
|
## 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()
|
var hmask = mask.toHostOrder()
|
||||||
if hmask.family == AddressFamily.IPv4:
|
if hmask.family == AddressFamily.IPv4:
|
||||||
var n = hmask.mask4
|
var n = hmask.mask4
|
||||||
while n != 0:
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000'u32) == 0'u32:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
n = n shl 1
|
n = n shl 1
|
||||||
inc(result)
|
inc(result)
|
||||||
elif hmask.family == AddressFamily.IPv6:
|
elif hmask.family == AddressFamily.IPv6:
|
||||||
|
@ -202,13 +279,21 @@ proc prefix*(mask: IpMask): int =
|
||||||
else:
|
else:
|
||||||
var n = hmask.mask6[1]
|
var n = hmask.mask6[1]
|
||||||
while n != 0:
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000_0000_0000'u64) == 0'u64:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
n = n shl 1
|
n = n shl 1
|
||||||
inc(result)
|
inc(result)
|
||||||
else:
|
else:
|
||||||
var n = hmask.mask6[0]
|
var n = hmask.mask6[0]
|
||||||
while n != 0:
|
while n != 0:
|
||||||
|
if (n and 0x8000_0000_0000_0000'u64) == 0'u64:
|
||||||
|
result = -1
|
||||||
|
return
|
||||||
n = n shl 1
|
n = n shl 1
|
||||||
inc(result)
|
inc(result)
|
||||||
|
if hmask.mask6[1] != 0x00'u64:
|
||||||
|
result = -1
|
||||||
|
|
||||||
proc subnetMask*(mask: IpMask): TransportAddress =
|
proc subnetMask*(mask: IpMask): TransportAddress =
|
||||||
## Returns TransportAddress representation of IP mask ``mask``.
|
## Returns TransportAddress representation of IP mask ``mask``.
|
||||||
|
@ -219,12 +304,12 @@ proc subnetMask*(mask: IpMask): TransportAddress =
|
||||||
cast[ptr uint64](addr result.address_v6[0])[] = mask.mask6[0]
|
cast[ptr uint64](addr result.address_v6[0])[] = mask.mask6[0]
|
||||||
cast[ptr uint64](addr result.address_v6[8])[] = mask.mask6[1]
|
cast[ptr uint64](addr result.address_v6[8])[] = mask.mask6[1]
|
||||||
|
|
||||||
proc `$`*(mask: IpMask): string =
|
proc `$`*(mask: IpMask, include0x = false): string =
|
||||||
## Returns hexadecimal string representation of IP mask ``mask``.
|
## Returns hexadecimal string representation of IP mask ``mask``.
|
||||||
var host = mask.toHostOrder()
|
var host = mask.toHostOrder()
|
||||||
result = ""
|
result = ""
|
||||||
if host.family == AddressFamily.IPv4:
|
if host.family == AddressFamily.IPv4:
|
||||||
result = "0x"
|
result = if include0x: "0x" else: ""
|
||||||
var n = 32
|
var n = 32
|
||||||
var m = host.mask4
|
var m = host.mask4
|
||||||
while n > 0:
|
while n > 0:
|
||||||
|
@ -235,7 +320,7 @@ proc `$`*(mask: IpMask): string =
|
||||||
else:
|
else:
|
||||||
result.add(chr(ord('A') + (c - 10)))
|
result.add(chr(ord('A') + (c - 10)))
|
||||||
elif host.family == AddressFamily.IPv6:
|
elif host.family == AddressFamily.IPv6:
|
||||||
result = "0x"
|
result = if include0x: "0x" else: ""
|
||||||
for i in 0..1:
|
for i in 0..1:
|
||||||
var n = 64
|
var n = 64
|
||||||
var m = host.mask6[i]
|
var m = host.mask6[i]
|
||||||
|
@ -246,13 +331,28 @@ proc `$`*(mask: IpMask): string =
|
||||||
result.add(chr(ord('0') + c))
|
result.add(chr(ord('0') + c))
|
||||||
else:
|
else:
|
||||||
result.add(chr(ord('A') + (c - 10)))
|
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,
|
proc init*(t: typedesc[IpNet], host: TransportAddress,
|
||||||
prefix: int): IpNet {.inline.} =
|
prefix: int): IpNet {.inline.} =
|
||||||
## Initialize IP Network using host address ``host`` and prefix length
|
## Initialize IP Network using host address ``host`` and prefix length
|
||||||
## ``prefix``.
|
## ``prefix``.
|
||||||
result.mask = IpMask.init(host.family, prefix)
|
result.mask = IpMask.init(host.family, prefix)
|
||||||
result.host = mask(host, result.mask)
|
result.host = host
|
||||||
|
|
||||||
proc init*(t: typedesc[IpNet], host, mask: TransportAddress): IpNet {.inline.} =
|
proc init*(t: typedesc[IpNet], host, mask: TransportAddress): IpNet {.inline.} =
|
||||||
## Initialize IP Network using host address ``host`` and network mask
|
## Initialize IP Network using host address ``host`` and network mask
|
||||||
|
@ -261,25 +361,22 @@ proc init*(t: typedesc[IpNet], host, mask: TransportAddress): IpNet {.inline.} =
|
||||||
## Note that ``host`` and ``mask`` must be from the same IP family.
|
## Note that ``host`` and ``mask`` must be from the same IP family.
|
||||||
if host.family == mask.family:
|
if host.family == mask.family:
|
||||||
result.mask = IpMask.init(mask)
|
result.mask = IpMask.init(mask)
|
||||||
result.host = mask(host, result.mask)
|
result.host = host
|
||||||
|
|
||||||
proc init*(t: typedesc[IpNet], host: TransportAddress,
|
proc init*(t: typedesc[IpNet], host: TransportAddress,
|
||||||
mask: IpMask): IpNet {.inline.} =
|
mask: IpMask): IpNet {.inline.} =
|
||||||
## Initialize IP Network using host address ``host`` and network mask
|
## Initialize IP Network using host address ``host`` and network mask
|
||||||
## ``mask``.
|
## ``mask``.
|
||||||
result.mask = mask
|
result.mask = mask
|
||||||
result.host = result.mask(host)
|
result.host = host
|
||||||
|
|
||||||
proc init*(t: typedesc[IpNet], network: string): IpNet =
|
proc init*(t: typedesc[IpNet], network: string): IpNet =
|
||||||
## Initialize IP Network from string representation in format
|
## Initialize IP Network from string representation in format
|
||||||
## <address>/<prefix length>.
|
## <address>/<prefix length> or <address>/<netmask address>.
|
||||||
##
|
|
||||||
## Not if <prefix length> is not present or its value is bigger then maximum
|
|
||||||
## value (32 for IPv4 and 128 for IPv6), then `/32` and `/128` will be used
|
|
||||||
## as prefix length.
|
|
||||||
var parts = network.rsplit("/", maxsplit = 1)
|
var parts = network.rsplit("/", maxsplit = 1)
|
||||||
var host: TransportAddress
|
var host, mhost: TransportAddress
|
||||||
var ipaddr: IpAddress
|
var ipaddr: IpAddress
|
||||||
|
var mask: IpMask
|
||||||
var prefix: int
|
var prefix: int
|
||||||
try:
|
try:
|
||||||
ipaddr = parseIpAddress(parts[0])
|
ipaddr = parseIpAddress(parts[0])
|
||||||
|
@ -292,50 +389,87 @@ proc init*(t: typedesc[IpNet], network: string): IpNet =
|
||||||
host.address_v6 = ipaddr.address_v6
|
host.address_v6 = ipaddr.address_v6
|
||||||
prefix = 128
|
prefix = 128
|
||||||
if len(parts) > 1:
|
if len(parts) > 1:
|
||||||
|
try:
|
||||||
prefix = parseInt(parts[1])
|
prefix = parseInt(parts[1])
|
||||||
if ipaddr.family == IpAddressFamily.IPv4 and
|
except:
|
||||||
(prefix < 0 or prefix > 32):
|
prefix = -1
|
||||||
prefix = 32
|
if prefix == -1:
|
||||||
elif ipaddr.family == IpAddressFamily.IPv6 and
|
ipaddr = parseIpAddress(parts[1])
|
||||||
(prefix < 0 or prefix > 128):
|
if ipaddr.family == IpAddressFamily.IPv4:
|
||||||
prefix = 128
|
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)
|
result = t.init(host, prefix)
|
||||||
except:
|
except:
|
||||||
raise newException(TransportAddressError, "Incorrect address family!")
|
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 =
|
proc contains*(net: IpNet, address: TransportAddress): bool =
|
||||||
## Returns ``true`` if ``address`` belongs to IP Network ``net``
|
## Returns ``true`` if ``address`` belongs to IP Network ``net``
|
||||||
if net.host.family == address.family:
|
if net.host.family == address.family:
|
||||||
var host = mask(address, net.mask)
|
var host1 = mask(address, net.mask)
|
||||||
result = (net.host == host)
|
var host2 = mask(net.host, net.mask)
|
||||||
|
host2.port = host1.port
|
||||||
|
result = (host1 == host2)
|
||||||
|
|
||||||
proc broadcast*(net: IpNet): TransportAddress =
|
proc broadcast*(net: IpNet): TransportAddress =
|
||||||
## Returns broadcast address for IP Network ``net``.
|
## Returns broadcast address for IP Network ``net``.
|
||||||
result = TransportAddress(family: net.host.family)
|
result = TransportAddress(family: net.host.family)
|
||||||
if result.family == AddressFamily.IPv4:
|
if result.family == AddressFamily.IPv4:
|
||||||
var address = cast[ptr uint32](unsafeAddr net.host.address_v4[0])[]
|
let address = cast[ptr uint32](unsafeAddr net.host.address_v4[0])[]
|
||||||
var mask = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
let mask = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
||||||
cast[ptr uint32](addr result.address_v4[0])[] = address or (not(mask))
|
cast[ptr uint32](addr result.address_v4[0])[] = address or (not(mask))
|
||||||
elif result.family == AddressFamily.IPv6:
|
elif result.family == AddressFamily.IPv6:
|
||||||
var address0 = cast[ptr uint64](unsafeAddr net.host.address_v6[0])[]
|
let address0 = cast[ptr uint64](unsafeAddr net.host.address_v6[0])[]
|
||||||
var address1 = cast[ptr uint64](unsafeAddr net.host.address_v6[8])[]
|
let address1 = cast[ptr uint64](unsafeAddr net.host.address_v6[8])[]
|
||||||
var data0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
let data0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
||||||
var data1 = cast[ptr uint64](unsafeAddr net.mask.mask6[1])[]
|
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[0])[] = address0 or (not(data0))
|
||||||
cast[ptr uint64](addr result.address_v6[8])[] = address1 or (not(data1))
|
cast[ptr uint64](addr result.address_v6[8])[] = address1 or (not(data1))
|
||||||
|
|
||||||
proc subnetMask*(net: IpNet): TransportAddress =
|
proc subnetMask*(net: IpNet): TransportAddress =
|
||||||
## Returns netmask address for IP Network ``net``
|
## Returns netmask address for IP Network ``net``.
|
||||||
result = TransportAddress(family: net.host.family)
|
result = TransportAddress(family: net.host.family)
|
||||||
if result.family == AddressFamily.IPv4:
|
if result.family == AddressFamily.IPv4:
|
||||||
var address = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
let address = cast[ptr uint32](unsafeAddr net.mask.mask4)[]
|
||||||
cast[ptr uint32](addr result.address_v4[0])[] = address
|
cast[ptr uint32](addr result.address_v4[0])[] = address
|
||||||
elif result.family == AddressFamily.IPv6:
|
elif result.family == AddressFamily.IPv6:
|
||||||
var address0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
let address0 = cast[ptr uint64](unsafeAddr net.mask.mask6[0])[]
|
||||||
var address1 = cast[ptr uint64](unsafeAddr net.mask.mask6[1])[]
|
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[0])[] = address0
|
||||||
cast[ptr uint64](addr result.address_v6[8])[] = address1
|
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 =
|
proc `and`*(address1, address2: TransportAddress): TransportAddress =
|
||||||
## Bitwise ``and`` operation for ``address1 and address2``.
|
## Bitwise ``and`` operation for ``address1 and address2``.
|
||||||
##
|
##
|
||||||
|
@ -430,13 +564,21 @@ proc `$`*(net: IpNet): string =
|
||||||
address_v4: net.host.address_v4)
|
address_v4: net.host.address_v4)
|
||||||
result = $a
|
result = $a
|
||||||
result.add("/")
|
result.add("/")
|
||||||
result.add($net.mask.prefix())
|
let prefix = net.mask.prefix()
|
||||||
|
if prefix == -1:
|
||||||
|
result.add(net.mask.ip())
|
||||||
|
else:
|
||||||
|
result.add($prefix)
|
||||||
elif net.host.family == AddressFamily.IPv6:
|
elif net.host.family == AddressFamily.IPv6:
|
||||||
var a = IpAddress(family: IpAddressFamily.IPv6,
|
var a = IpAddress(family: IpAddressFamily.IPv6,
|
||||||
address_v6: net.host.address_v6)
|
address_v6: net.host.address_v6)
|
||||||
result = $a
|
result = $a
|
||||||
result.add("/")
|
result.add("/")
|
||||||
result.add($net.mask.prefix())
|
let prefix = net.mask.prefix()
|
||||||
|
if prefix == -1:
|
||||||
|
result.add(net.mask.ip())
|
||||||
|
else:
|
||||||
|
result.add($prefix)
|
||||||
|
|
||||||
proc isUnspecified*(address: TransportAddress): bool {.inline.} =
|
proc isUnspecified*(address: TransportAddress): bool {.inline.} =
|
||||||
## Returns ``true`` if ``address`` is not specified yet, e.g. its ``family``
|
## Returns ``true`` if ``address`` is not specified yet, e.g. its ``family``
|
||||||
|
@ -555,34 +697,3 @@ proc isGlobalMulticast*(address: TransportAddress): bool =
|
||||||
elif address.family == AddressFamily.IPv6:
|
elif address.family == AddressFamily.IPv6:
|
||||||
result = (address.address_v6[0] == 0xFF'u8) and
|
result = (address.address_v6[0] == 0xFF'u8) and
|
||||||
((address.address_v6[1] and 0x0F'u8) == 0x0E'u8)
|
((address.address_v6[1] and 0x0F'u8) == 0x0E'u8)
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
var MaskVectors = [
|
|
||||||
["192.168.1.127:1024", "255.255.255.128", "192.168.1.0:1024"],
|
|
||||||
["192.168.1.127:1024", "255.255.255.192", "192.168.1.64:1024"],
|
|
||||||
["192.168.1.127:1024", "255.255.255.224", "192.168.1.96:1024"],
|
|
||||||
["192.168.1.127:1024", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80",
|
|
||||||
"192.168.1.0:1024"],
|
|
||||||
["192.168.1.127:1024", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0",
|
|
||||||
"192.168.1.64:1024"],
|
|
||||||
["192.168.1.127:1024", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0",
|
|
||||||
"192.168.1.96:1024"],
|
|
||||||
["192.168.1.127:1024", "255.0.255.0", "192.0.1.0:1024"],
|
|
||||||
["[2001:db8::1]:1024", "ffff:ff80::", "[2001:d80::]:1024"],
|
|
||||||
["[2001:db8::1]:1024", "f0f0:0f0f::", "[2000:d08::]:1024"]
|
|
||||||
]
|
|
||||||
for item in MaskVectors:
|
|
||||||
var a = initTAddress(item[0])
|
|
||||||
var m = IpMask.init(item[1])
|
|
||||||
var r = a.mask(m)
|
|
||||||
echo r
|
|
||||||
# var temp = [0'u8, 0, 255, 255, 255, 255, 255, 0]
|
|
||||||
# echo toHex(cast[ptr uint64](addr temp[0])[])
|
|
||||||
# # {IPv4(192, 168, 1, 127), IPMask(ParseIP("255.255.255.192")), IPv4(192, 168, 1, 64)},
|
|
||||||
# echo initTAddress("255.255.255.128", 0).toIPv6()
|
|
||||||
# var a = initTAddress("255.255.255.0", 0).toIPv6()
|
|
||||||
# echo a
|
|
||||||
# var m = IpMask.init(a)
|
|
||||||
# var b = initTAddress("192.168.1.127", 0)
|
|
||||||
# echo b.mask(m)
|
|
||||||
# # echo a.mask(m)
|
|
Loading…
Reference in New Issue