* Refactor osnet.nim to not use `result`. Fix #156. * Fix linux compilation error.
This commit is contained in:
parent
d6a39e46e1
commit
eb6e32605f
|
@ -255,83 +255,86 @@ type
|
||||||
gateway*: TransportAddress
|
gateway*: TransportAddress
|
||||||
metric*: int
|
metric*: int
|
||||||
|
|
||||||
proc broadcast*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
proc broadcast*(ifa: InterfaceAddress): TransportAddress =
|
||||||
## Return broadcast address for ``ifa``.
|
## Return broadcast address for ``ifa``.
|
||||||
result = ifa.net.broadcast()
|
ifa.net.broadcast()
|
||||||
|
|
||||||
proc network*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
proc network*(ifa: InterfaceAddress): TransportAddress =
|
||||||
## Return network address for ``ifa``.
|
## Return network address for ``ifa``.
|
||||||
result = ifa.net.network()
|
ifa.net.network()
|
||||||
|
|
||||||
proc netmask*(ifa: InterfaceAddress): TransportAddress {.inline.} =
|
proc netmask*(ifa: InterfaceAddress): TransportAddress =
|
||||||
## Return network mask for ``ifa``.
|
## Return network mask for ``ifa``.
|
||||||
result = ifa.net.subnetMask()
|
ifa.net.subnetMask()
|
||||||
|
|
||||||
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.host = address
|
InterfaceAddress(host: address, net: IpNet.init(address, prefix))
|
||||||
result.net = IpNet.init(address, prefix)
|
|
||||||
|
|
||||||
proc `$`*(ifa: InterfaceAddress): string {.inline.} =
|
proc `$`*(ifa: InterfaceAddress): string =
|
||||||
## Return string representation of ``ifa``.
|
## Return string representation of ``ifa``.
|
||||||
if ifa.host.family == AddressFamily.IPv4:
|
if ifa.host.family == AddressFamily.IPv4:
|
||||||
result = $ifa.net
|
$ifa.net
|
||||||
elif ifa.host.family == AddressFamily.IPv6:
|
elif ifa.host.family == AddressFamily.IPv6:
|
||||||
result = $ifa.net
|
$ifa.net
|
||||||
|
else:
|
||||||
|
"Unknown"
|
||||||
|
|
||||||
proc `$`*(iface: NetworkInterface): string =
|
proc `$`*(iface: NetworkInterface): string =
|
||||||
## Return string representation of network interface ``iface``.
|
## Return string representation of network interface ``iface``.
|
||||||
result = $iface.ifIndex
|
var res = $iface.ifIndex
|
||||||
if len(result) == 1:
|
if len(res) == 1:
|
||||||
result.add(". ")
|
res.add(". ")
|
||||||
else:
|
else:
|
||||||
result.add(". ")
|
res.add(". ")
|
||||||
result.add(iface.name)
|
res.add(iface.name)
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
result.add(" [")
|
res.add(" [")
|
||||||
result.add(iface.desc)
|
res.add(iface.desc)
|
||||||
result.add("]")
|
res.add("]")
|
||||||
result.add(": flags = ")
|
res.add(": flags = ")
|
||||||
result.add($iface.flags)
|
res.add($iface.flags)
|
||||||
result.add(" mtu ")
|
res.add(" mtu ")
|
||||||
result.add($iface.mtu)
|
res.add($iface.mtu)
|
||||||
result.add(" state ")
|
res.add(" state ")
|
||||||
result.add($iface.state)
|
res.add($iface.state)
|
||||||
result.add("\n ")
|
res.add("\n ")
|
||||||
result.add($iface.ifType)
|
res.add($iface.ifType)
|
||||||
result.add(" ")
|
res.add(" ")
|
||||||
if iface.maclen > 0:
|
if iface.maclen > 0:
|
||||||
for i in 0..<iface.maclen:
|
for i in 0..<iface.maclen:
|
||||||
result.add(toHex(iface.mac[i]))
|
res.add(toHex(iface.mac[i]))
|
||||||
if i < iface.maclen - 1:
|
if i < iface.maclen - 1:
|
||||||
result.add(":")
|
res.add(":")
|
||||||
for item in iface.addresses:
|
for item in iface.addresses:
|
||||||
result.add("\n ")
|
res.add("\n ")
|
||||||
if item.host.family == AddressFamily.IPv4:
|
if item.host.family == AddressFamily.IPv4:
|
||||||
result.add("inet ")
|
res.add("inet ")
|
||||||
elif item.host.family == AddressFamily.IPv6:
|
elif item.host.family == AddressFamily.IPv6:
|
||||||
result.add("inet6 ")
|
res.add("inet6 ")
|
||||||
result.add($item)
|
res.add($item)
|
||||||
result.add(" netmask ")
|
res.add(" netmask ")
|
||||||
result.add($(item.netmask().address()))
|
res.add($(item.netmask().address()))
|
||||||
result.add(" brd ")
|
res.add(" brd ")
|
||||||
result.add($(item.broadcast().address()))
|
res.add($(item.broadcast().address()))
|
||||||
|
res
|
||||||
|
|
||||||
proc `$`*(route: Route): string =
|
proc `$`*(route: Route): string =
|
||||||
result = $route.dest.address()
|
var res = $route.dest.address()
|
||||||
result.add(" via ")
|
res.add(" via ")
|
||||||
if route.gateway.family != AddressFamily.None:
|
if route.gateway.family != AddressFamily.None:
|
||||||
result.add("gateway ")
|
res.add("gateway ")
|
||||||
result.add($route.gateway.address())
|
res.add($route.gateway.address())
|
||||||
else:
|
else:
|
||||||
result.add("link")
|
res.add("link")
|
||||||
result.add(" src ")
|
res.add(" src ")
|
||||||
result.add($route.source.address())
|
res.add($route.source.address())
|
||||||
|
res
|
||||||
|
|
||||||
proc cmp*(a, b: NetworkInterface): int =
|
proc cmp*(a, b: NetworkInterface): int =
|
||||||
result = cmp(a.ifIndex, b.ifIndex)
|
cmp(a.ifIndex, b.ifIndex)
|
||||||
|
|
||||||
when defined(linux):
|
when defined(linux):
|
||||||
import posix
|
import posix
|
||||||
|
@ -507,19 +510,19 @@ when defined(linux):
|
||||||
template NLMSG_LENGTH(length: int): uint32 =
|
template NLMSG_LENGTH(length: int): uint32 =
|
||||||
uint32(NLMSG_HDRLEN() + length)
|
uint32(NLMSG_HDRLEN() + length)
|
||||||
|
|
||||||
proc NLMSG_OK(nlh: ptr NlMsgHeader, length: int): bool {.inline.} =
|
proc NLMSG_OK(nlh: ptr NlMsgHeader, length: int): bool =
|
||||||
result = (length >= int(sizeof(NlMsgHeader))) and
|
(length >= int(sizeof(NlMsgHeader))) and
|
||||||
(nlh.nlmsg_len >= uint32(sizeof(NlMsgHeader))) and
|
(nlh.nlmsg_len >= uint32(sizeof(NlMsgHeader))) and
|
||||||
(nlh.nlmsg_len <= uint32(length))
|
(nlh.nlmsg_len <= uint32(length))
|
||||||
|
|
||||||
proc NLMSG_NEXT(nlh: ptr NlMsgHeader,
|
proc NLMSG_NEXT(nlh: ptr NlMsgHeader,
|
||||||
length: var int): ptr NlMsgHeader {.inline.} =
|
length: var int): ptr NlMsgHeader =
|
||||||
length = length - int(NLMSG_ALIGN(uint(nlh.nlmsg_len)))
|
length = length - int(NLMSG_ALIGN(uint(nlh.nlmsg_len)))
|
||||||
result = cast[ptr NlMsgHeader](cast[uint](nlh) +
|
cast[ptr NlMsgHeader](cast[uint](nlh) +
|
||||||
cast[uint](NLMSG_ALIGN(uint(nlh.nlmsg_len))))
|
cast[uint](NLMSG_ALIGN(uint(nlh.nlmsg_len))))
|
||||||
|
|
||||||
proc NLMSG_DATA(nlh: ptr NlMsgHeader): ptr byte {.inline.} =
|
proc NLMSG_DATA(nlh: ptr NlMsgHeader): ptr byte =
|
||||||
result = cast[ptr byte](cast[uint](nlh) + NLMSG_LENGTH(0))
|
cast[ptr byte](cast[uint](nlh) + NLMSG_LENGTH(0))
|
||||||
|
|
||||||
proc NLMSG_TAIL(nlh: ptr NlMsgHeader): ptr byte {.inline.} =
|
proc NLMSG_TAIL(nlh: ptr NlMsgHeader): ptr byte {.inline.} =
|
||||||
cast[ptr byte](cast[uint](nlh) + NLMSG_ALIGN(uint(nlh.nlmsg_len)))
|
cast[ptr byte](cast[uint](nlh) + NLMSG_ALIGN(uint(nlh.nlmsg_len)))
|
||||||
|
@ -536,87 +539,88 @@ when defined(linux):
|
||||||
template RTA_PAYLOAD*(length: uint): uint =
|
template RTA_PAYLOAD*(length: uint): uint =
|
||||||
length - RTA_LENGTH(0)
|
length - RTA_LENGTH(0)
|
||||||
|
|
||||||
proc IFLA_RTA(r: ptr byte): ptr RtAttr {.inline.} =
|
proc IFLA_RTA(r: ptr byte): ptr RtAttr =
|
||||||
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(IfInfoMessage))))
|
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(IfInfoMessage))))
|
||||||
|
|
||||||
proc IFA_RTA(r: ptr byte): ptr RtAttr {.inline.} =
|
proc IFA_RTA(r: ptr byte): ptr RtAttr =
|
||||||
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(IfAddrMessage))))
|
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(IfAddrMessage))))
|
||||||
|
|
||||||
proc RT_RTA(r: ptr byte): ptr RtAttr {.inline.} =
|
proc RT_RTA(r: ptr byte): ptr RtAttr =
|
||||||
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(RtMessage))))
|
cast[ptr RtAttr](cast[uint](r) + NLMSG_ALIGN(uint(sizeof(RtMessage))))
|
||||||
|
|
||||||
proc RTA_OK(rta: ptr RtAttr, length: int): bool {.inline.} =
|
proc RTA_OK(rta: ptr RtAttr, length: int): bool =
|
||||||
result = length >= sizeof(RtAttr) and
|
length >= sizeof(RtAttr) and
|
||||||
rta.rta_len >= cushort(sizeof(RtAttr)) and
|
rta.rta_len >= cushort(sizeof(RtAttr)) and
|
||||||
rta.rta_len <= cushort(length)
|
rta.rta_len <= cushort(length)
|
||||||
|
|
||||||
proc RTA_NEXT(rta: ptr RtAttr, length: var int): ptr RtAttr {.inline.} =
|
proc RTA_NEXT(rta: ptr RtAttr, length: var int): ptr RtAttr =
|
||||||
length = length - int(RTA_ALIGN(uint(rta.rta_len)))
|
length = length - int(RTA_ALIGN(uint(rta.rta_len)))
|
||||||
result = cast[ptr RtAttr](cast[uint](rta) +
|
cast[ptr RtAttr](cast[uint](rta) +
|
||||||
cast[uint](RTA_ALIGN(uint(rta.rta_len))))
|
cast[uint](RTA_ALIGN(uint(rta.rta_len))))
|
||||||
|
|
||||||
proc RTA_DATA(rta: ptr RtAttr): ptr byte {.inline.} =
|
proc RTA_DATA(rta: ptr RtAttr): ptr byte =
|
||||||
result = cast[ptr byte](cast[uint](rta) + RTA_LENGTH(0))
|
cast[ptr byte](cast[uint](rta) + RTA_LENGTH(0))
|
||||||
|
|
||||||
proc toInterfaceState(it: cint, flags: cuint): InterfaceState {.inline.} =
|
proc toInterfaceState(it: cint, flags: cuint): InterfaceState =
|
||||||
case it
|
case it
|
||||||
of 1:
|
of 1:
|
||||||
result = StatusNotPresent
|
StatusNotPresent
|
||||||
of 2:
|
of 2:
|
||||||
result = StatusDown
|
StatusDown
|
||||||
of 3:
|
of 3:
|
||||||
result = StatusLowerLayerDown
|
StatusLowerLayerDown
|
||||||
of 4:
|
of 4:
|
||||||
result = StatusTesting
|
StatusTesting
|
||||||
of 5:
|
of 5:
|
||||||
result = StatusDormant
|
StatusDormant
|
||||||
of 6:
|
of 6:
|
||||||
result = StatusUp
|
StatusUp
|
||||||
else:
|
else:
|
||||||
result = StatusUnknown
|
StatusUnknown
|
||||||
|
|
||||||
proc toInterfaceType(ft: uint32): InterfaceType {.inline.} =
|
proc toInterfaceType(ft: uint32): InterfaceType =
|
||||||
case ft
|
case ft
|
||||||
of ARPHRD_ETHER, ARPHRD_EETHER:
|
of ARPHRD_ETHER, ARPHRD_EETHER:
|
||||||
result = IfEthernetCsmacd
|
IfEthernetCsmacd
|
||||||
of ARPHRD_LOOPBACK:
|
of ARPHRD_LOOPBACK:
|
||||||
result = IfSoftwareLoopback
|
IfSoftwareLoopback
|
||||||
of 787..799:
|
of 787..799:
|
||||||
result = IfFibreChannel
|
IfFibreChannel
|
||||||
of ARPHRD_PPP:
|
of ARPHRD_PPP:
|
||||||
result = IfPpp
|
IfPpp
|
||||||
of ARPHRD_SLIP, ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6:
|
of ARPHRD_SLIP, ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6:
|
||||||
result = IfSlip
|
IfSlip
|
||||||
of ARPHRD_IEEE1394:
|
of ARPHRD_IEEE1394:
|
||||||
result = IfIeee1394
|
IfIeee1394
|
||||||
of ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP:
|
of ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP:
|
||||||
result = IfIeee80211
|
IfIeee80211
|
||||||
of ARPHRD_ATM:
|
of ARPHRD_ATM:
|
||||||
result = IfAtm
|
IfAtm
|
||||||
of ARPHRD_HDLC:
|
of ARPHRD_HDLC:
|
||||||
result = IfHdlc
|
IfHdlc
|
||||||
of ARPHRD_HIPPI:
|
of ARPHRD_HIPPI:
|
||||||
result = IfHippiInterface
|
IfHippiInterface
|
||||||
of ARPHRD_ARCNET:
|
of ARPHRD_ARCNET:
|
||||||
result = IfArcNet
|
IfArcNet
|
||||||
of ARPHRD_LAPB:
|
of ARPHRD_LAPB:
|
||||||
result = IfLapB
|
IfLapB
|
||||||
of ARPHRD_FRAD:
|
of ARPHRD_FRAD:
|
||||||
result = IfFrameRelay
|
IfFrameRelay
|
||||||
else:
|
else:
|
||||||
result = IfOther
|
IfOther
|
||||||
|
|
||||||
proc createNetlinkSocket(pid: Pid): SocketHandle =
|
proc createNetlinkSocket(pid: Pid): SocketHandle =
|
||||||
var address: SockAddr_nl
|
var address: SockAddr_nl
|
||||||
address.family = cushort(AF_NETLINK)
|
address.family = cushort(AF_NETLINK)
|
||||||
address.groups = 0
|
address.groups = 0
|
||||||
address.pid = cast[uint32](pid)
|
address.pid = cast[uint32](pid)
|
||||||
result = posix.socket(AF_NETLINK, posix.SOCK_DGRAM, NETLINK_ROUTE)
|
var res = posix.socket(AF_NETLINK, posix.SOCK_DGRAM, NETLINK_ROUTE)
|
||||||
if result != SocketHandle(-1):
|
if res != SocketHandle(-1):
|
||||||
if posix.bindSocket(result, cast[ptr SockAddr](addr address),
|
if posix.bindSocket(res, cast[ptr SockAddr](addr address),
|
||||||
Socklen(sizeof(SockAddr_nl))) != 0:
|
Socklen(sizeof(SockAddr_nl))) != 0:
|
||||||
discard posix.close(result)
|
discard posix.close(res)
|
||||||
result = SocketHandle(-1)
|
res = SocketHandle(-1)
|
||||||
|
res
|
||||||
|
|
||||||
proc sendLinkMessage(fd: SocketHandle, pid: Pid, seqno: uint32,
|
proc sendLinkMessage(fd: SocketHandle, pid: Pid, seqno: uint32,
|
||||||
ntype: uint16, nflags: uint16): bool =
|
ntype: uint16, nflags: uint16): bool =
|
||||||
|
@ -642,8 +646,7 @@ when defined(linux):
|
||||||
rmsg.msg_name = cast[pointer](addr address)
|
rmsg.msg_name = cast[pointer](addr address)
|
||||||
rmsg.msg_namelen = Socklen(sizeof(SockAddr_nl))
|
rmsg.msg_namelen = Socklen(sizeof(SockAddr_nl))
|
||||||
let res = posix.sendmsg(fd, addr rmsg, 0).TIovLen
|
let res = posix.sendmsg(fd, addr rmsg, 0).TIovLen
|
||||||
if res == iov.iov_len:
|
(res == iov.iov_len)
|
||||||
result = true
|
|
||||||
|
|
||||||
proc sendRouteMessage(fd: SocketHandle, pid: Pid, seqno: uint32,
|
proc sendRouteMessage(fd: SocketHandle, pid: Pid, seqno: uint32,
|
||||||
ntype: uint16, nflags: uint16,
|
ntype: uint16, nflags: uint16,
|
||||||
|
@ -691,8 +694,7 @@ when defined(linux):
|
||||||
rmsg.msg_name = cast[pointer](addr address)
|
rmsg.msg_name = cast[pointer](addr address)
|
||||||
rmsg.msg_namelen = Socklen(sizeof(SockAddr_nl))
|
rmsg.msg_namelen = Socklen(sizeof(SockAddr_nl))
|
||||||
let res = posix.sendmsg(fd, addr rmsg, 0).TIovLen
|
let res = posix.sendmsg(fd, addr rmsg, 0).TIovLen
|
||||||
if res == iov.iov_len:
|
(res == iov.iov_len)
|
||||||
result = true
|
|
||||||
|
|
||||||
proc readNetlinkMessage(fd: SocketHandle, data: var seq[byte]): bool =
|
proc readNetlinkMessage(fd: SocketHandle, data: var seq[byte]): bool =
|
||||||
var
|
var
|
||||||
|
@ -709,9 +711,10 @@ when defined(linux):
|
||||||
var length = posix.recvmsg(fd, addr rmsg, 0)
|
var length = posix.recvmsg(fd, addr rmsg, 0)
|
||||||
if length >= 0:
|
if length >= 0:
|
||||||
data.setLen(length)
|
data.setLen(length)
|
||||||
result = true
|
true
|
||||||
else:
|
else:
|
||||||
data.setLen(0)
|
data.setLen(0)
|
||||||
|
false
|
||||||
|
|
||||||
proc processLink(msg: ptr NlMsgHeader): NetworkInterface =
|
proc processLink(msg: ptr NlMsgHeader): NetworkInterface =
|
||||||
var iface: ptr IfInfoMessage
|
var iface: ptr IfInfoMessage
|
||||||
|
@ -722,34 +725,41 @@ when defined(linux):
|
||||||
length = int(msg.nlmsg_len) - int(NLMSG_LENGTH(sizeof(IfInfoMessage)))
|
length = int(msg.nlmsg_len) - int(NLMSG_LENGTH(sizeof(IfInfoMessage)))
|
||||||
|
|
||||||
attr = IFLA_RTA(cast[ptr byte](iface))
|
attr = IFLA_RTA(cast[ptr byte](iface))
|
||||||
result.ifType = toInterfaceType(iface.ifi_type)
|
var res = NetworkInterface(
|
||||||
result.ifIndex = iface.ifi_index
|
ifType: toInterfaceType(iface.ifi_type),
|
||||||
result.flags = cast[uint64](iface.ifi_flags)
|
ifIndex: iface.ifi_index,
|
||||||
|
flags: cast[uint64](iface.ifi_flags)
|
||||||
|
)
|
||||||
|
|
||||||
while RTA_OK(attr, length):
|
while RTA_OK(attr, length):
|
||||||
if attr.rta_type == IFLA_IFNAME:
|
if attr.rta_type == IFLA_IFNAME:
|
||||||
var p = cast[cstring](RTA_DATA(attr))
|
var p = cast[cstring](RTA_DATA(attr))
|
||||||
result.name = $p
|
res.name = $p
|
||||||
elif attr.rta_type == IFLA_ADDRESS:
|
elif attr.rta_type == IFLA_ADDRESS:
|
||||||
var p = cast[ptr byte](RTA_DATA(attr))
|
var p = cast[ptr byte](RTA_DATA(attr))
|
||||||
var plen = min(int(RTA_PAYLOAD(uint(attr.rta_len))), len(result.mac))
|
var plen = min(int(RTA_PAYLOAD(uint(attr.rta_len))), len(res.mac))
|
||||||
copyMem(addr result.mac[0], p, plen)
|
copyMem(addr res.mac[0], p, plen)
|
||||||
result.maclen = plen
|
res.maclen = plen
|
||||||
elif attr.rta_type == IFLA_MTU:
|
elif attr.rta_type == IFLA_MTU:
|
||||||
var p = cast[ptr uint32](RTA_DATA(attr))
|
var p = cast[ptr uint32](RTA_DATA(attr))
|
||||||
result.mtu = cast[int](p[])
|
res.mtu = cast[int](p[])
|
||||||
elif attr.rta_type == IFLA_OPERSTATE:
|
elif attr.rta_type == IFLA_OPERSTATE:
|
||||||
var p = cast[ptr byte](RTA_DATA(attr))
|
var p = cast[ptr byte](RTA_DATA(attr))
|
||||||
result.state = toInterfaceState(cast[cint](p[]), iface.ifi_flags)
|
res.state = toInterfaceState(cast[cint](p[]), iface.ifi_flags)
|
||||||
attr = RTA_NEXT(attr, length)
|
attr = RTA_NEXT(attr, length)
|
||||||
|
res
|
||||||
|
|
||||||
proc getAddress(f: int, p: pointer): TransportAddress {.inline.} =
|
proc getAddress(f: int, p: pointer): TransportAddress =
|
||||||
if f == posix.AF_INET:
|
if f == posix.AF_INET:
|
||||||
result = TransportAddress(family: AddressFamily.IPv4)
|
var res = TransportAddress(family: AddressFamily.IPv4)
|
||||||
copyMem(addr result.address_v4[0], p, len(result.address_v4))
|
copyMem(addr res.address_v4[0], p, len(res.address_v4))
|
||||||
|
res
|
||||||
elif f == posix.AF_INET6:
|
elif f == posix.AF_INET6:
|
||||||
result = TransportAddress(family: AddressFamily.IPv6)
|
var res = TransportAddress(family: AddressFamily.IPv6)
|
||||||
copyMem(addr result.address_v6[0], p, len(result.address_v6))
|
copyMem(addr res.address_v6[0], p, len(res.address_v6))
|
||||||
|
res
|
||||||
|
else:
|
||||||
|
TransportAddress(family: AddressFamily.None)
|
||||||
|
|
||||||
proc processAddress(msg: ptr NlMsgHeader): NetworkInterface =
|
proc processAddress(msg: ptr NlMsgHeader): NetworkInterface =
|
||||||
var iaddr: ptr IfAddrMessage
|
var iaddr: ptr IfAddrMessage
|
||||||
|
@ -762,7 +772,7 @@ when defined(linux):
|
||||||
attr = IFA_RTA(cast[ptr byte](iaddr))
|
attr = IFA_RTA(cast[ptr byte](iaddr))
|
||||||
|
|
||||||
let family = cast[int](iaddr.ifa_family)
|
let family = cast[int](iaddr.ifa_family)
|
||||||
result.ifIndex = cast[int](iaddr.ifa_index)
|
var res = NetworkInterface(ifIndex: cast[int](iaddr.ifa_index))
|
||||||
|
|
||||||
var address, local: TransportAddress
|
var address, local: TransportAddress
|
||||||
|
|
||||||
|
@ -775,38 +785,41 @@ when defined(linux):
|
||||||
|
|
||||||
if local.family != AddressFamily.None:
|
if local.family != AddressFamily.None:
|
||||||
address = local
|
address = local
|
||||||
if len(result.addresses) == 0:
|
|
||||||
result.addresses = newSeq[InterfaceAddress]()
|
|
||||||
let prefixLength = cast[int](iaddr.ifa_prefixlen)
|
let prefixLength = cast[int](iaddr.ifa_prefixlen)
|
||||||
let ifaddr = InterfaceAddress.init(address, prefixLength)
|
let ifaddr = InterfaceAddress.init(address, prefixLength)
|
||||||
result.addresses.add(ifaddr)
|
res.addresses.add(ifaddr)
|
||||||
|
res
|
||||||
|
|
||||||
proc processRoute(msg: ptr NlMsgHeader): Route =
|
proc processRoute(msg: ptr NlMsgHeader): Route =
|
||||||
var rtmsg = cast[ptr RtMessage](NLMSG_DATA(msg))
|
var rtmsg = cast[ptr RtMessage](NLMSG_DATA(msg))
|
||||||
var length = int(msg.nlmsg_len) - int(NLMSG_LENGTH(sizeof(RtMessage)))
|
var length = int(msg.nlmsg_len) - int(NLMSG_LENGTH(sizeof(RtMessage)))
|
||||||
var attr = RT_RTA(cast[ptr byte](rtmsg))
|
var attr = RT_RTA(cast[ptr byte](rtmsg))
|
||||||
|
var res = Route()
|
||||||
while RTA_OK(attr, length):
|
while RTA_OK(attr, length):
|
||||||
if attr.rta_type == RTA_DST:
|
if attr.rta_type == RTA_DST:
|
||||||
result.dest = getAddress(int(rtmsg.rtm_family),
|
res.dest = getAddress(int(rtmsg.rtm_family),
|
||||||
cast[pointer](RTA_DATA(attr)))
|
cast[pointer](RTA_DATA(attr)))
|
||||||
elif attr.rta_type == RTA_GATEWAY:
|
elif attr.rta_type == RTA_GATEWAY:
|
||||||
result.gateway = getAddress(int(rtmsg.rtm_family),
|
res.gateway = getAddress(int(rtmsg.rtm_family),
|
||||||
cast[pointer](RTA_DATA(attr)))
|
cast[pointer](RTA_DATA(attr)))
|
||||||
elif attr.rta_type == RTA_OIF:
|
elif attr.rta_type == RTA_OIF:
|
||||||
var oid: uint32
|
var oid: uint32
|
||||||
copyMem(addr oid, RTA_DATA(attr), sizeof(uint32))
|
copyMem(addr oid, RTA_DATA(attr), sizeof(uint32))
|
||||||
result.ifIndex = int(oid)
|
res.ifIndex = int(oid)
|
||||||
elif attr.rta_type == RTA_PREFSRC:
|
elif attr.rta_type == RTA_PREFSRC:
|
||||||
result.source = getAddress(int(rtmsg.rtm_family),
|
res.source = getAddress(int(rtmsg.rtm_family),
|
||||||
cast[pointer](RTA_DATA(attr)))
|
cast[pointer](RTA_DATA(attr)))
|
||||||
attr = RTA_NEXT(attr, length)
|
attr = RTA_NEXT(attr, length)
|
||||||
|
res
|
||||||
|
|
||||||
proc getRoute(netfd: SocketHandle, pid: Pid,
|
proc getRoute(netfd: SocketHandle, pid: Pid,
|
||||||
address: TransportAddress): Route =
|
address: TransportAddress): Route =
|
||||||
if not sendRouteMessage(netfd, pid, 1, RTM_GETROUTE,
|
if not sendRouteMessage(netfd, pid, 1, RTM_GETROUTE,
|
||||||
NLM_F_REQUEST, address):
|
NLM_F_REQUEST, address):
|
||||||
return
|
return Route()
|
||||||
var data = newSeq[byte]()
|
var data = newSeq[byte]()
|
||||||
|
var res = Route()
|
||||||
while true:
|
while true:
|
||||||
if not readNetlinkMessage(netfd, data):
|
if not readNetlinkMessage(netfd, data):
|
||||||
break
|
break
|
||||||
|
@ -818,19 +831,21 @@ when defined(linux):
|
||||||
endflag = true
|
endflag = true
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
result = processRoute(msg)
|
res = processRoute(msg)
|
||||||
endflag = true
|
endflag = true
|
||||||
break
|
break
|
||||||
msg = NLMSG_NEXT(msg, length)
|
msg = NLMSG_NEXT(msg, length)
|
||||||
if endflag:
|
if endflag:
|
||||||
break
|
break
|
||||||
|
res
|
||||||
|
|
||||||
proc getLinks(netfd: SocketHandle, pid: Pid): seq[NetworkInterface] =
|
proc getLinks(netfd: SocketHandle, pid: Pid): seq[NetworkInterface] =
|
||||||
|
var res: seq[NetworkInterface]
|
||||||
if not sendLinkMessage(netfd, pid, 1, RTM_GETLINK,
|
if not sendLinkMessage(netfd, pid, 1, RTM_GETLINK,
|
||||||
NLM_F_REQUEST or NLM_F_DUMP):
|
NLM_F_REQUEST or NLM_F_DUMP):
|
||||||
return
|
return res
|
||||||
var data = newSeq[byte]()
|
var data = newSeq[byte]()
|
||||||
result = newSeq[NetworkInterface]()
|
res = newSeq[NetworkInterface]()
|
||||||
while true:
|
while true:
|
||||||
if not readNetlinkMessage(netfd, data):
|
if not readNetlinkMessage(netfd, data):
|
||||||
break
|
break
|
||||||
|
@ -848,10 +863,11 @@ when defined(linux):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
var iface = processLink(msg)
|
var iface = processLink(msg)
|
||||||
result.add(iface)
|
res.add(iface)
|
||||||
msg = NLMSG_NEXT(msg, length)
|
msg = NLMSG_NEXT(msg, length)
|
||||||
if endflag:
|
if endflag:
|
||||||
break
|
break
|
||||||
|
res
|
||||||
|
|
||||||
proc getAddresses(netfd: SocketHandle, pid: Pid,
|
proc getAddresses(netfd: SocketHandle, pid: Pid,
|
||||||
ifaces: var seq[NetworkInterface]) =
|
ifaces: var seq[NetworkInterface]) =
|
||||||
|
@ -884,26 +900,32 @@ when defined(linux):
|
||||||
if endflag:
|
if endflag:
|
||||||
break
|
break
|
||||||
|
|
||||||
proc getInterfaces*(): seq[NetworkInterface] =
|
proc getInterfaces*(): seq[NetworkInterface] {.raises: [Defect].} =
|
||||||
## Return list of available interfaces.
|
## Return list of available interfaces.
|
||||||
|
var res: seq[NetworkInterface]
|
||||||
var pid = posix.getpid()
|
var pid = posix.getpid()
|
||||||
var sock = createNetlinkSocket(pid)
|
var sock = createNetlinkSocket(pid)
|
||||||
if sock == InvalidSocketHandle:
|
if sock == InvalidSocketHandle:
|
||||||
return
|
return res
|
||||||
result = getLinks(sock, pid)
|
else:
|
||||||
getAddresses(sock, pid, result)
|
res = getLinks(sock, pid)
|
||||||
sort(result, cmp)
|
getAddresses(sock, pid, res)
|
||||||
discard posix.close(sock)
|
sort(res, cmp)
|
||||||
|
discard posix.close(sock)
|
||||||
|
res
|
||||||
|
|
||||||
proc getBestRoute*(address: TransportAddress): Route =
|
proc getBestRoute*(address: TransportAddress): Route {.raises: [Defect].} =
|
||||||
## Return best applicable OS route, which will be used for connecting to
|
## Return best applicable OS route, which will be used for connecting to
|
||||||
## address ``address``.
|
## address ``address``.
|
||||||
var pid = posix.getpid()
|
var pid = posix.getpid()
|
||||||
|
var res = Route()
|
||||||
var sock = createNetlinkSocket(pid)
|
var sock = createNetlinkSocket(pid)
|
||||||
if sock == InvalidSocketHandle:
|
if sock == InvalidSocketHandle:
|
||||||
return
|
res
|
||||||
result = getRoute(sock, pid, address)
|
else:
|
||||||
discard posix.close(sock)
|
res = getRoute(sock, pid, address)
|
||||||
|
discard posix.close(sock)
|
||||||
|
res
|
||||||
|
|
||||||
elif defined(macosx) or defined(bsd):
|
elif defined(macosx) or defined(bsd):
|
||||||
import posix
|
import posix
|
||||||
|
@ -1018,25 +1040,25 @@ elif defined(macosx) or defined(bsd):
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <ifaddrs.h>""".}
|
#include <ifaddrs.h>""".}
|
||||||
|
|
||||||
proc toInterfaceType(f: byte): InterfaceType {.inline.} =
|
proc toInterfaceType(f: byte): InterfaceType =
|
||||||
var ft = cast[int](f)
|
var ft = cast[int](f)
|
||||||
if (ft >= 1 and ft <= 196) or (ft == 237) or (ft == 243) or (ft == 244):
|
if (ft >= 1 and ft <= 196) or (ft == 237) or (ft == 243) or (ft == 244):
|
||||||
result = cast[InterfaceType](ft)
|
cast[InterfaceType](ft)
|
||||||
else:
|
else:
|
||||||
result = IfOther
|
IfOther
|
||||||
|
|
||||||
proc toInterfaceState(f: cuint): InterfaceState {.inline.} =
|
proc toInterfaceState(f: cuint): InterfaceState =
|
||||||
if (f and IFF_RUNNING) != 0 and (f and IFF_UP) != 0:
|
if (f and IFF_RUNNING) != 0 and (f and IFF_UP) != 0:
|
||||||
result = StatusUp
|
StatusUp
|
||||||
else:
|
else:
|
||||||
result = StatusDown
|
StatusDown
|
||||||
|
|
||||||
proc getInterfaces*(): seq[NetworkInterface] =
|
proc getInterfaces*(): seq[NetworkInterface] {.raises: [Defect].} =
|
||||||
## Return list of available interfaces.
|
## Return list of available interfaces.
|
||||||
|
var res: seq[NetworkInterface]
|
||||||
var ifap: ptr IfAddrs
|
var ifap: ptr IfAddrs
|
||||||
let res = getIfAddrs(addr ifap)
|
let gres = getIfAddrs(addr ifap)
|
||||||
if res == 0:
|
if gres == 0:
|
||||||
result = newSeq[NetworkInterface]()
|
|
||||||
while not isNil(ifap):
|
while not isNil(ifap):
|
||||||
var iface: NetworkInterface
|
var iface: NetworkInterface
|
||||||
var ifaddress: InterfaceAddress
|
var ifaddress: InterfaceAddress
|
||||||
|
@ -1044,27 +1066,27 @@ elif defined(macosx) or defined(bsd):
|
||||||
iface.name = $ifap.ifa_name
|
iface.name = $ifap.ifa_name
|
||||||
iface.flags = cast[uint64](ifap.ifa_flags)
|
iface.flags = cast[uint64](ifap.ifa_flags)
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < len(result):
|
while i < len(res):
|
||||||
if result[i].name == iface.name:
|
if res[i].name == iface.name:
|
||||||
break
|
break
|
||||||
inc(i)
|
inc(i)
|
||||||
if i == len(result):
|
if i == len(res):
|
||||||
result.add(iface)
|
res.add(iface)
|
||||||
|
|
||||||
if not isNil(ifap.ifa_addr):
|
if not isNil(ifap.ifa_addr):
|
||||||
let family = cast[int](ifap.ifa_addr.sa_family)
|
let family = cast[int](ifap.ifa_addr.sa_family)
|
||||||
if family == AF_LINK:
|
if family == AF_LINK:
|
||||||
var data = cast[ptr IfData](ifap.ifa_data)
|
var data = cast[ptr IfData](ifap.ifa_data)
|
||||||
var link = cast[ptr SockAddr_dl](ifap.ifa_addr)
|
var link = cast[ptr SockAddr_dl](ifap.ifa_addr)
|
||||||
result[i].ifIndex = cast[int](link.sdl_index)
|
res[i].ifIndex = cast[int](link.sdl_index)
|
||||||
let nlen = cast[int](link.sdl_nlen)
|
let nlen = cast[int](link.sdl_nlen)
|
||||||
if nlen < len(link.sdl_data):
|
if nlen < len(link.sdl_data):
|
||||||
let minsize = min(cast[int](link.sdl_alen), len(result[i].mac))
|
let minsize = min(cast[int](link.sdl_alen), len(res[i].mac))
|
||||||
copyMem(addr result[i].mac[0], addr link.sdl_data[nlen], minsize)
|
copyMem(addr res[i].mac[0], addr link.sdl_data[nlen], minsize)
|
||||||
result[i].maclen = cast[int](link.sdl_alen)
|
res[i].maclen = cast[int](link.sdl_alen)
|
||||||
result[i].ifType = toInterfaceType(data.ifi_type)
|
res[i].ifType = toInterfaceType(data.ifi_type)
|
||||||
result[i].state = toInterfaceState(ifap.ifa_flags)
|
res[i].state = toInterfaceState(ifap.ifa_flags)
|
||||||
result[i].mtu = cast[int](data.ifi_mtu)
|
res[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.host)
|
Socklen(sizeof(SockAddr_in)), ifaddress.host)
|
||||||
|
@ -1083,27 +1105,31 @@ elif defined(macosx) or defined(bsd):
|
||||||
ifaddress.net = IpNet.init(ifaddress.host, na)
|
ifaddress.net = IpNet.init(ifaddress.host, na)
|
||||||
|
|
||||||
if ifaddress.host.family != AddressFamily.None:
|
if ifaddress.host.family != AddressFamily.None:
|
||||||
if len(result[i].addresses) == 0:
|
if len(res[i].addresses) == 0:
|
||||||
result[i].addresses = newSeq[InterfaceAddress]()
|
res[i].addresses = newSeq[InterfaceAddress]()
|
||||||
result[i].addresses.add(ifaddress)
|
res[i].addresses.add(ifaddress)
|
||||||
ifap = ifap.ifa_next
|
ifap = ifap.ifa_next
|
||||||
|
|
||||||
sort(result, cmp)
|
sort(res, cmp)
|
||||||
freeIfAddrs(ifap)
|
freeIfAddrs(ifap)
|
||||||
|
res
|
||||||
|
|
||||||
proc sasize(data: openarray[byte]): int =
|
proc sasize(data: openarray[byte]): int =
|
||||||
# SA_SIZE() template. Taken from FreeBSD net/route.h:1.63
|
# SA_SIZE() template. Taken from FreeBSD net/route.h:1.63
|
||||||
if len(data) > 0:
|
if len(data) > 0:
|
||||||
if data[0] == 0x00'u8:
|
if data[0] == 0x00'u8:
|
||||||
result = sizeof(uint32)
|
sizeof(uint32)
|
||||||
else:
|
else:
|
||||||
result = 1 + (int(data[0] - 1) or (sizeof(uint32) - 1))
|
1 + (int(data[0] - 1) or (sizeof(uint32) - 1))
|
||||||
|
else:
|
||||||
|
0
|
||||||
|
|
||||||
proc getBestRoute*(address: TransportAddress): Route =
|
proc getBestRoute*(address: TransportAddress): Route {.raises: [Defect].} =
|
||||||
## Return best applicable OS route, which will be used for connecting to
|
## Return best applicable OS route, which will be used for connecting to
|
||||||
## address ``address``.
|
## address ``address``.
|
||||||
var sock: cint
|
var sock: cint
|
||||||
var msg: RtMessage
|
var msg: RtMessage
|
||||||
|
var res = Route()
|
||||||
var pid = posix.getpid()
|
var pid = posix.getpid()
|
||||||
|
|
||||||
if address.family notin {AddressFamily.IPv4, AddressFamily.IPv6}:
|
if address.family notin {AddressFamily.IPv4, AddressFamily.IPv6}:
|
||||||
|
@ -1129,15 +1155,20 @@ elif defined(macosx) or defined(bsd):
|
||||||
msg.rtm.rtm_addrs = RTA_DST
|
msg.rtm.rtm_addrs = RTA_DST
|
||||||
msg.space[0] = cast[byte](salen)
|
msg.space[0] = cast[byte](salen)
|
||||||
msg.rtm.rtm_msglen = uint16(sizeof(RtMessage))
|
msg.rtm.rtm_msglen = uint16(sizeof(RtMessage))
|
||||||
var res = posix.write(sock, addr msg, sizeof(RtMessage))
|
let wres = posix.write(sock, addr msg, sizeof(RtMessage))
|
||||||
if res >= 0:
|
if wres >= 0:
|
||||||
while true:
|
let rres =
|
||||||
res = posix.read(sock, addr msg, sizeof(RtMessage))
|
block:
|
||||||
if res >= 0 and msg.rtm.rtm_pid == pid and msg.rtm.rtm_seq == 0xCAFE:
|
var pres = 0
|
||||||
break
|
while true:
|
||||||
if res >= 0 and msg.rtm.rtm_version == RTM_VERSION and
|
pres = posix.read(sock, addr msg, sizeof(RtMessage))
|
||||||
msg.rtm.rtm_errno == 0:
|
if ((pres >= 0) and (msg.rtm.rtm_pid == pid) and
|
||||||
result.ifIndex = int(msg.rtm.rtm_index)
|
(msg.rtm.rtm_seq == 0xCAFE)) or (pres < 0):
|
||||||
|
break
|
||||||
|
pres
|
||||||
|
if (rres >= 0) and (msg.rtm.rtm_version == RTM_VERSION) and
|
||||||
|
(msg.rtm.rtm_errno == 0):
|
||||||
|
res.ifIndex = int(msg.rtm.rtm_index)
|
||||||
var so = 0
|
var so = 0
|
||||||
var eo = len(msg.space) - 1
|
var eo = len(msg.space) - 1
|
||||||
for i in 0..<2:
|
for i in 0..<2:
|
||||||
|
@ -1146,21 +1177,22 @@ elif defined(macosx) or defined(bsd):
|
||||||
var saddr = cast[ptr Sockaddr_storage](addr msg.space[so])
|
var saddr = cast[ptr Sockaddr_storage](addr msg.space[so])
|
||||||
let size = sasize(msg.space.toOpenArray(so, eo))
|
let size = sasize(msg.space.toOpenArray(so, eo))
|
||||||
if mask == RTA_DST:
|
if mask == RTA_DST:
|
||||||
fromSAddr(saddr, Socklen(size), result.dest)
|
fromSAddr(saddr, Socklen(size), res.dest)
|
||||||
elif mask == RTA_GATEWAY:
|
elif mask == RTA_GATEWAY:
|
||||||
fromSAddr(saddr, Socklen(size), result.gateway)
|
fromSAddr(saddr, Socklen(size), res.gateway)
|
||||||
so += size
|
so += size
|
||||||
|
|
||||||
if result.dest.isZero():
|
if res.dest.isZero():
|
||||||
result.dest = address
|
res.dest = address
|
||||||
var interfaces = getInterfaces()
|
var interfaces = getInterfaces()
|
||||||
for item in interfaces:
|
for item in interfaces:
|
||||||
if result.ifIndex == item.ifIndex:
|
if res.ifIndex == item.ifIndex:
|
||||||
for a in item.addresses:
|
for a in item.addresses:
|
||||||
if a.host.family == address.family:
|
if a.host.family == address.family:
|
||||||
result.source = a.host
|
res.source = a.host
|
||||||
break
|
break
|
||||||
discard posix.close(sock)
|
discard posix.close(sock)
|
||||||
|
res
|
||||||
|
|
||||||
elif defined(windows):
|
elif defined(windows):
|
||||||
import winlean, dynlib
|
import winlean, dynlib
|
||||||
|
@ -1293,69 +1325,78 @@ elif defined(windows):
|
||||||
AddressSortOptions: uint32,
|
AddressSortOptions: uint32,
|
||||||
BestRoute: ptr MibIpForwardRow2,
|
BestRoute: ptr MibIpForwardRow2,
|
||||||
BestSourceAddress: ptr SOCKADDR_INET): DWORD {.
|
BestSourceAddress: ptr SOCKADDR_INET): DWORD {.
|
||||||
gcsafe, stdcall.}
|
gcsafe, stdcall, raises: [].}
|
||||||
|
|
||||||
proc toInterfaceType(ft: uint32): InterfaceType {.inline.} =
|
proc toInterfaceType(ft: uint32): InterfaceType {.inline.} =
|
||||||
if (ft >= 1'u32 and ft <= 196'u32) or
|
if (ft >= 1'u32 and ft <= 196'u32) or
|
||||||
(ft == 237) or (ft == 243) or (ft == 244) or (ft == 259) or (ft == 281):
|
(ft == 237) or (ft == 243) or (ft == 244) or (ft == 259) or (ft == 281):
|
||||||
result = cast[InterfaceType](ft)
|
cast[InterfaceType](ft)
|
||||||
else:
|
else:
|
||||||
result = IfOther
|
IfOther
|
||||||
|
|
||||||
proc toInterfaceState(it: cint): InterfaceState {.inline.} =
|
proc toInterfaceState(it: cint): InterfaceState {.inline.} =
|
||||||
if it >= 1 and it <= 7:
|
if it >= 1 and it <= 7:
|
||||||
result = cast[InterfaceState](it)
|
cast[InterfaceState](it)
|
||||||
else:
|
else:
|
||||||
result = StatusUnknown
|
StatusUnknown
|
||||||
|
|
||||||
proc GetAdaptersAddresses(family: uint32, flags: uint32, reserved: pointer,
|
proc GetAdaptersAddresses(family: uint32, flags: uint32, reserved: pointer,
|
||||||
addresses: ptr IpAdapterAddressesXp,
|
addresses: ptr IpAdapterAddressesXp,
|
||||||
sizeptr: ptr uint32): uint32 {.
|
sizeptr: ptr uint32): uint32 {.
|
||||||
stdcall, dynlib: "iphlpapi", importc: "GetAdaptersAddresses".}
|
stdcall, dynlib: "iphlpapi", importc: "GetAdaptersAddresses",
|
||||||
|
raises: [].}
|
||||||
|
|
||||||
proc WideCharToMultiByte(CodePage: uint32, dwFlags: uint32,
|
proc WideCharToMultiByte(CodePage: uint32, dwFlags: uint32,
|
||||||
lpWideCharStr: ptr WCHAR, cchWideChar: cint,
|
lpWideCharStr: ptr WCHAR, cchWideChar: cint,
|
||||||
lpMultiByteStr: ptr char, cbMultiByte: cint,
|
lpMultiByteStr: ptr char, cbMultiByte: cint,
|
||||||
lpDefaultChar: ptr char,
|
lpDefaultChar: ptr char,
|
||||||
lpUsedDefaultChar: ptr uint32): cint
|
lpUsedDefaultChar: ptr uint32): cint
|
||||||
{.stdcall, dynlib: "kernel32.dll", importc: "WideCharToMultiByte".}
|
{.stdcall, dynlib: "kernel32.dll", importc: "WideCharToMultiByte",
|
||||||
|
raises: [].}
|
||||||
|
|
||||||
proc getBestRouteXp(dwDestAddr: uint32, dwSourceAddr: uint32,
|
proc getBestRouteXp(dwDestAddr: uint32, dwSourceAddr: uint32,
|
||||||
pBestRoute: ptr MibIpForwardRow): uint32 {.
|
pBestRoute: ptr MibIpForwardRow): uint32 {.
|
||||||
stdcall, dynlib: "iphlpapi", importc: "GetBestRoute".}
|
stdcall, dynlib: "iphlpapi", importc: "GetBestRoute",
|
||||||
|
raises: [].}
|
||||||
|
|
||||||
proc `$`(bstr: ptr WCHAR): string =
|
proc `$`(bstr: ptr WCHAR): string =
|
||||||
var buffer: char
|
var buffer: char
|
||||||
var count = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(buffer), 0,
|
var count = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(buffer), 0,
|
||||||
nil, nil)
|
nil, nil)
|
||||||
if count > 0:
|
if count > 0:
|
||||||
result = newString(count + 8)
|
var res = newString(count + 8)
|
||||||
let res = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(result[0]),
|
let wres = WideCharToMultiByte(CP_UTF8, 0, bstr, -1, addr(res[0]),
|
||||||
count, nil, nil)
|
count, nil, nil)
|
||||||
if res > 0:
|
if wres > 0:
|
||||||
result.setLen(res - 1)
|
res.setLen(wres - 1)
|
||||||
else:
|
else:
|
||||||
result.setLen(0)
|
res.setLen(0)
|
||||||
|
res
|
||||||
|
else:
|
||||||
|
""
|
||||||
|
|
||||||
proc isVista(): bool =
|
proc isVista(): bool =
|
||||||
var ver: OSVERSIONINFO
|
var ver: OSVERSIONINFO
|
||||||
ver.dwOSVersionInfoSize = DWORD(sizeof(ver))
|
ver.dwOSVersionInfoSize = DWORD(sizeof(ver))
|
||||||
let res = getVersionExW(addr(ver))
|
let res = getVersionExW(addr(ver))
|
||||||
if res == 0:
|
if res == 0:
|
||||||
result = false
|
false
|
||||||
else:
|
else:
|
||||||
result = (ver.dwMajorVersion >= 6)
|
(ver.dwMajorVersion >= 6)
|
||||||
|
|
||||||
proc toIPv6(a: TransportAddress): TransportAddress =
|
proc toIPv6(a: TransportAddress): TransportAddress =
|
||||||
## IPv4-mapped addresses are formed by:
|
## IPv4-mapped addresses are formed by:
|
||||||
## <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
|
## <80 bits of zeros> + <16 bits of ones> + <32-bit IPv4 address>.
|
||||||
if a.family == AddressFamily.IPv4:
|
if a.family == AddressFamily.IPv4:
|
||||||
result = TransportAddress(family: AddressFamily.IPv6)
|
var res = TransportAddress(family: AddressFamily.IPv6)
|
||||||
result.address_v6[10] = 0xFF'u8
|
res.address_v6[10] = 0xFF'u8
|
||||||
result.address_v6[11] = 0xFF'u8
|
res.address_v6[11] = 0xFF'u8
|
||||||
copyMem(addr result.address_v6[12], unsafeAddr a.address_v4[0], 4)
|
copyMem(addr res.address_v6[12], unsafeAddr a.address_v4[0], 4)
|
||||||
|
res
|
||||||
elif a.family == AddressFamily.IPv6:
|
elif a.family == AddressFamily.IPv6:
|
||||||
result = a
|
a
|
||||||
|
else:
|
||||||
|
TransportAddress(family: AddressFamily.IPv6)
|
||||||
|
|
||||||
proc ipMatchPrefix(number, prefix: TransportAddress, nbits: int): bool =
|
proc ipMatchPrefix(number, prefix: TransportAddress, nbits: int): bool =
|
||||||
var num6, prefix6: TransportAddress
|
var num6, prefix6: TransportAddress
|
||||||
|
@ -1377,14 +1418,15 @@ elif defined(windows):
|
||||||
let i = bytesCount
|
let i = bytesCount
|
||||||
if (num6.address_v6[i] and mask) != (prefix6.address_v6[i] and mask):
|
if (num6.address_v6[i] and mask) != (prefix6.address_v6[i] and mask):
|
||||||
return false
|
return false
|
||||||
result = true
|
true
|
||||||
|
|
||||||
proc processAddress(ifitem: ptr IpAdapterAddressesXp,
|
proc processAddress(ifitem: ptr IpAdapterAddressesXp,
|
||||||
ifunic: ptr IpAdapterUnicastAddressXpLh,
|
ifunic: ptr IpAdapterUnicastAddressXpLh,
|
||||||
vista: bool): InterfaceAddress =
|
vista: bool): InterfaceAddress =
|
||||||
|
var res = 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.host)
|
SockLen(ifunic.address.iSockaddrLength), res.host)
|
||||||
if not vista:
|
if not vista:
|
||||||
var prefix = ifitem.firstPrefix
|
var prefix = ifitem.firstPrefix
|
||||||
var prefixLength = -1
|
var prefixLength = -1
|
||||||
|
@ -1394,34 +1436,35 @@ 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.host, pa, cast[int](prefix.prefixLength)):
|
if ipMatchPrefix(res.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.net = IpNet.init(result.host, prefixLength)
|
res.net = IpNet.init(res.host, prefixLength)
|
||||||
else:
|
else:
|
||||||
let prefixLength = cast[int](ifunic.onLinkPrefixLength)
|
let prefixLength = cast[int](ifunic.onLinkPrefixLength)
|
||||||
if prefixLength >= 0:
|
if prefixLength >= 0:
|
||||||
result.net = IpNet.init(result.host, prefixLength)
|
res.net = IpNet.init(res.host, prefixLength)
|
||||||
|
res
|
||||||
|
|
||||||
proc getInterfaces*(): seq[NetworkInterface] =
|
proc getInterfaces*(): seq[NetworkInterface] {.raises: [Defect].} =
|
||||||
## Return list of network interfaces.
|
## Return list of network interfaces.
|
||||||
result = newSeq[NetworkInterface]()
|
var res = newSeq[NetworkInterface]()
|
||||||
var size = WorkBufferSize
|
var size = WorkBufferSize
|
||||||
var tries = 0
|
var tries = 0
|
||||||
var buffer: seq[byte]
|
var buffer: seq[byte]
|
||||||
var res: uint32
|
var gres: uint32
|
||||||
var vista = isVista()
|
var vista = isVista()
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
buffer = newSeq[byte](size)
|
buffer = newSeq[byte](size)
|
||||||
var addresses = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
var addresses = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
||||||
res = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nil,
|
gres = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, nil,
|
||||||
addresses, addr size)
|
addresses, addr size)
|
||||||
if res == ERROR_SUCCESS:
|
if gres == ERROR_SUCCESS:
|
||||||
buffer.setLen(size)
|
buffer.setLen(size)
|
||||||
break
|
break
|
||||||
elif res == ERROR_BUFFER_OVERFLOW:
|
elif gres == ERROR_BUFFER_OVERFLOW:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
@ -1429,7 +1472,7 @@ elif defined(windows):
|
||||||
if tries >= MaxTries:
|
if tries >= MaxTries:
|
||||||
break
|
break
|
||||||
|
|
||||||
if res == ERROR_SUCCESS:
|
if gres == ERROR_SUCCESS:
|
||||||
var slider = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
var slider = cast[ptr IpAdapterAddressesXp](addr buffer[0])
|
||||||
while not isNil(slider):
|
while not isNil(slider):
|
||||||
var iface = NetworkInterface(
|
var iface = NetworkInterface(
|
||||||
|
@ -1449,14 +1492,16 @@ elif defined(windows):
|
||||||
var ifaddr = processAddress(slider, unicast, vista)
|
var ifaddr = processAddress(slider, unicast, vista)
|
||||||
iface.addresses.add(ifaddr)
|
iface.addresses.add(ifaddr)
|
||||||
unicast = unicast.next
|
unicast = unicast.next
|
||||||
result.add(iface)
|
res.add(iface)
|
||||||
slider = slider.next
|
slider = slider.next
|
||||||
|
|
||||||
sort(result, cmp)
|
sort(res, cmp)
|
||||||
|
res
|
||||||
|
|
||||||
proc getBestRoute*(address: TransportAddress): Route =
|
proc getBestRoute*(address: TransportAddress): Route {.raises: [Defect].} =
|
||||||
## Return best applicable OS route, which will be used for connecting to
|
## Return best applicable OS route, which will be used for connecting to
|
||||||
## address ``address``.
|
## address ``address``.
|
||||||
|
var res = Route()
|
||||||
if isVista():
|
if isVista():
|
||||||
let iph = loadLib("iphlpapi.dll")
|
let iph = loadLib("iphlpapi.dll")
|
||||||
if iph != nil:
|
if iph != nil:
|
||||||
|
@ -1467,48 +1512,49 @@ elif defined(windows):
|
||||||
var destlen: Socklen
|
var destlen: Socklen
|
||||||
address.toSAddr(dest, destlen)
|
address.toSAddr(dest, destlen)
|
||||||
var getBestRoute2 = cast[GETBESTROUTE2](symAddr(iph, "GetBestRoute2"))
|
var getBestRoute2 = cast[GETBESTROUTE2](symAddr(iph, "GetBestRoute2"))
|
||||||
var res = getBestRoute2(addr luid, 0'u32, nil,
|
var gres = getBestRoute2(addr luid, 0'u32, nil,
|
||||||
cast[ptr SOCKADDR_INET](addr dest),
|
cast[ptr SOCKADDR_INET](addr dest),
|
||||||
0'u32,
|
0'u32,
|
||||||
addr bestRoute,
|
addr bestRoute,
|
||||||
cast[ptr SOCKADDR_INET](addr src))
|
cast[ptr SOCKADDR_INET](addr src))
|
||||||
if res == 0:
|
if gres == 0:
|
||||||
if src.ss_family == winlean.AF_INET:
|
if src.ss_family == winlean.AF_INET:
|
||||||
fromSAddr(addr src, Socklen(sizeof(Sockaddr_in)), result.source)
|
fromSAddr(addr src, Socklen(sizeof(Sockaddr_in)), res.source)
|
||||||
elif src.ss_family == winlean.AF_INET6:
|
elif src.ss_family == winlean.AF_INET6:
|
||||||
fromSAddr(addr src, Socklen(sizeof(Sockaddr_in6)), result.source)
|
fromSAddr(addr src, Socklen(sizeof(Sockaddr_in6)), res.source)
|
||||||
if bestRoute.nextHop.si_family == winlean.AF_INET:
|
if bestRoute.nextHop.si_family == winlean.AF_INET:
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](addr bestRoute.nextHop),
|
fromSAddr(cast[ptr Sockaddr_storage](addr bestRoute.nextHop),
|
||||||
Socklen(sizeof(Sockaddr_in)), result.gateway)
|
Socklen(sizeof(Sockaddr_in)), res.gateway)
|
||||||
elif bestRoute.nextHop.si_family == winlean.AF_INET6:
|
elif bestRoute.nextHop.si_family == winlean.AF_INET6:
|
||||||
fromSAddr(cast[ptr Sockaddr_storage](addr bestRoute.nextHop),
|
fromSAddr(cast[ptr Sockaddr_storage](addr bestRoute.nextHop),
|
||||||
Socklen(sizeof(Sockaddr_in6)), result.gateway)
|
Socklen(sizeof(Sockaddr_in6)), res.gateway)
|
||||||
if result.gateway.isZero():
|
if res.gateway.isZero():
|
||||||
result.gateway = empty
|
res.gateway = empty
|
||||||
result.dest = address
|
res.dest = address
|
||||||
result.ifIndex = int(bestRoute.interfaceIndex)
|
res.ifIndex = int(bestRoute.interfaceIndex)
|
||||||
result.metric = int(bestRoute.metric)
|
res.metric = int(bestRoute.metric)
|
||||||
else:
|
else:
|
||||||
if address.family == AddressFamily.IPv4:
|
if address.family == AddressFamily.IPv4:
|
||||||
var bestRoute: MibIpForwardRow
|
var bestRoute: MibIpForwardRow
|
||||||
var dest: uint32
|
var dest: uint32
|
||||||
copyMem(addr dest, unsafeAddr address.address_v4[0], 4)
|
copyMem(addr dest, unsafeAddr address.address_v4[0], 4)
|
||||||
let res = getBestRouteXp(dest, 0'u32, addr bestRoute)
|
let gres = getBestRouteXp(dest, 0'u32, addr bestRoute)
|
||||||
if res == 0:
|
if gres == 0:
|
||||||
var interfaces = getInterfaces()
|
var interfaces = getInterfaces()
|
||||||
result.dest = address
|
res.dest = address
|
||||||
if bestRoute.dwForwardNextHop != 0'u32:
|
if bestRoute.dwForwardNextHop != 0'u32:
|
||||||
result.gateway = TransportAddress(family: AddressFamily.IPv4)
|
res.gateway = TransportAddress(family: AddressFamily.IPv4)
|
||||||
copyMem(addr result.gateway.address_v4[0],
|
copyMem(addr res.gateway.address_v4[0],
|
||||||
addr bestRoute.dwForwardNextHop, 4)
|
addr bestRoute.dwForwardNextHop, 4)
|
||||||
result.metric = int(bestRoute.dwForwardMetric1)
|
res.metric = int(bestRoute.dwForwardMetric1)
|
||||||
result.ifIndex = int(bestRoute.dwForwardIfIndex)
|
res.ifIndex = int(bestRoute.dwForwardIfIndex)
|
||||||
for item in interfaces:
|
for item in interfaces:
|
||||||
if item.ifIndex == int(bestRoute.dwForwardIfIndex):
|
if item.ifIndex == int(bestRoute.dwForwardIfIndex):
|
||||||
for a in item.addresses:
|
for a in item.addresses:
|
||||||
if a.host.family == AddressFamily.IPv4:
|
if a.host.family == AddressFamily.IPv4:
|
||||||
result.source = a.host
|
res.source = a.host
|
||||||
break
|
break
|
||||||
|
res
|
||||||
|
|
||||||
else:
|
else:
|
||||||
{.fatal: "Sorry, your OS is currently not supported!".}
|
{.fatal: "Sorry, your OS is currently not supported!".}
|
||||||
|
|
Loading…
Reference in New Issue