Move iface.nim and ipnet.nim to proper place.

This commit is contained in:
cheatfate 2019-03-18 10:47:54 +02:00
parent 518d33e26c
commit 4fa5ee3c93
No known key found for this signature in database
GPG Key ID: 46ADD633A7201F95
2 changed files with 214 additions and 203 deletions

View File

@ -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

View File

@ -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:
prefix = parseInt(parts[1]) try:
if ipaddr.family == IpAddressFamily.IPv4 and prefix = parseInt(parts[1])
(prefix < 0 or prefix > 32): except:
prefix = 32 prefix = -1
elif ipaddr.family == IpAddressFamily.IPv6 and if prefix == -1:
(prefix < 0 or prefix > 128): ipaddr = parseIpAddress(parts[1])
prefix = 128 if ipaddr.family == IpAddressFamily.IPv4:
result = t.init(host, prefix) 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: 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)