From aa12aa90145c9b6f34198cd453953e4c2b12f576 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Sat, 1 Sep 2018 09:56:44 +0200 Subject: [PATCH] Add module for network interfaces --- arch/x64/linux/syscall.S | 7 +- dub.json | 4 +- source/tanya/net/iface.d | 141 ++++++++++++++++++++++++++++ source/tanya/sys/linux/syscall.d | 11 ++- source/tanya/sys/windows/def.d | 5 + source/tanya/sys/windows/ifdef.d | 30 ++++++ source/tanya/sys/windows/iphlpapi.d | 39 ++++++++ source/tanya/sys/windows/package.d | 2 + 8 files changed, 233 insertions(+), 6 deletions(-) create mode 100644 source/tanya/net/iface.d create mode 100644 source/tanya/sys/windows/ifdef.d create mode 100644 source/tanya/sys/windows/iphlpapi.d diff --git a/arch/x64/linux/syscall.S b/arch/x64/linux/syscall.S index e69bd30..a9c5437 100644 --- a/arch/x64/linux/syscall.S +++ b/arch/x64/linux/syscall.S @@ -11,10 +11,11 @@ The returned value is placed in %rax. */ .text - .globl syscall1 - .type syscall1, @function +// 1 parameter. + .globl _D5tanya3sys5linux7syscallQiFNbNillZl + .type _D5tanya3sys5linux7syscallQiFNbNillZl, @function -syscall1: +_D5tanya3sys5linux7syscallQiFNbNillZl: movq %rsi, %rax // Syscall number. syscall diff --git a/dub.json b/dub.json index 63774fe..e52bbfd 100644 --- a/dub.json +++ b/dub.json @@ -34,5 +34,7 @@ } ], - "libs-windows": ["advapi32"] + "libs-windows": ["advapi32"], + "libs-windows-x86_mscoff": ["iphlpapi"], + "libs-windows-x86_64": ["iphlpapi"] } diff --git a/source/tanya/net/iface.d b/source/tanya/net/iface.d new file mode 100644 index 0000000..abb5c42 --- /dev/null +++ b/source/tanya/net/iface.d @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Network interfaces. + * + * Copyright: Eugene Wissner 2018. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/net/iface.d, + * tanya/net/iface.d) + */ +module tanya.net.iface; + +import tanya.algorithm.mutation; +import tanya.meta.trait; +import tanya.meta.transform; +import tanya.range; + +version (TanyaNative) +{ + import mir.linux._asm.unistd; + import tanya.sys.linux.syscall; + import tanya.sys.posix.ioctl; + import tanya.sys.posix.net.if_; + import tanya.sys.posix.socket; +} +else version (Windows) +{ + import tanya.sys.windows.ifdef; + import tanya.sys.windows.iphlpapi; +} +else version (Posix) +{ + import core.sys.posix.net.if_; +} + +/** + * Converts the name of a network interface to its index. + * + * If an interface with the name $(D_PARAM name) cannot be found or another + * error occurres, returns 0. + * + * Params: + * name = Interface name. + * + * Returns: Returns interface index or 0. + */ +uint nameToIndex(R)(R name) @trusted +if (isInputRange!R && is(Unqual!(ElementType!R) == char) && hasLength!R) +{ + version (TanyaNative) + { + if (name.length >= IF_NAMESIZE) + { + return 0; + } + ifreq ifreq_ = void; + ifreq_.ifr_ifindex = 8; + + copy(name, ifreq_.ifr_name[]); + ifreq_.ifr_name[name.length] = '\0'; + + auto socket = syscall(AF_INET, + SOCK_DGRAM | SOCK_CLOEXEC, + 0, + NR_socket); + if (socket <= 0) + { + return 0; + } + scope (exit) + { + syscall(socket, NR_close); + } + if (syscall(socket, + SIOCGIFINDEX, + cast(ptrdiff_t) &ifreq_, + NR_ioctl) == 0) + { + return ifreq_.ifr_ifindex; + } + return 0; + } + else version (Windows) + { + if (name.length > IF_MAX_STRING_SIZE) + { + return 0; + } + char[IF_MAX_STRING_SIZE + 1] buffer; + NET_LUID luid; + + copy(name, buffer[]); + buffer[name.length] = '\0'; + + if (ConvertInterfaceNameToLuidA(buffer.ptr, &luid) != 0) + { + return 0; + } + NET_IFINDEX index; + if (ConvertInterfaceLuidToIndex(&luid, &index) == 0) + { + return index; + } + return 0; + } + else version (Posix) + { + if (name.length >= IF_NAMESIZE) + { + return 0; + } + char[IF_NAMESIZE] buffer; + + copy(name, buffer[]); + buffer[name.length] = '\0'; + + return if_nametoindex(buffer.ptr); + } +} + +/// +@nogc nothrow @safe unittest +{ + version (linux) + { + assert(nameToIndex("lo") == 1); + } + else version (Windows) + { + assert(nameToIndex("loopback_0") == 1); + } + else + { + assert(nameToIndex("lo0") == 1); + } + assert(nameToIndex("ecafretni") == 0); +} diff --git a/source/tanya/sys/linux/syscall.d b/source/tanya/sys/linux/syscall.d index fab77cf..e70f75a 100644 --- a/source/tanya/sys/linux/syscall.d +++ b/source/tanya/sys/linux/syscall.d @@ -14,6 +14,9 @@ module tanya.sys.linux.syscall; version (TanyaNative): +extern ptrdiff_t syscall(ptrdiff_t, ptrdiff_t) +@nogc nothrow @system; + extern ptrdiff_t syscall(ptrdiff_t, ptrdiff_t, ptrdiff_t) @nogc nothrow @system; @@ -37,14 +40,18 @@ private template getOverloadMangling(size_t n) } pragma(mangle, getOverloadMangling!0) -extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t, ptrdiff_t) +extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t) @nogc nothrow pure @system; pragma(mangle, getOverloadMangling!1) -extern ptrdiff_t syscall(ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t) +extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t, ptrdiff_t) @nogc nothrow pure @system; pragma(mangle, getOverloadMangling!2) +extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t) +@nogc nothrow pure @system; + +pragma(mangle, getOverloadMangling!3) extern ptrdiff_t syscall_(ptrdiff_t, ptrdiff_t, ptrdiff_t, diff --git a/source/tanya/sys/windows/def.d b/source/tanya/sys/windows/def.d index 6fe920e..ea37266 100644 --- a/source/tanya/sys/windows/def.d +++ b/source/tanya/sys/windows/def.d @@ -30,6 +30,7 @@ version (Windows): alias BYTE = ubyte; alias TBYTE = wchar; // If Unicode, otherwise char. alias CHAR = char; // Signed or unsigned char. +alias WCHAR = wchar; alias TCHAR = wchar; // If Unicode, otherwise char. alias SHORT = short; alias USHORT = ushort; @@ -52,6 +53,10 @@ enum HANDLE INVALID_HANDLE_VALUE = cast(HANDLE) -1; enum TRUE = 1; enum FALSE = 0; +alias PSTR = CHAR*; +alias PWSTR = WCHAR*; +alias PTSTR = TCHAR*; + align(1) struct GUID { uint Data1; diff --git a/source/tanya/sys/windows/ifdef.d b/source/tanya/sys/windows/ifdef.d new file mode 100644 index 0000000..89e1c3f --- /dev/null +++ b/source/tanya/sys/windows/ifdef.d @@ -0,0 +1,30 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Copyright: Eugene Wissner 2018. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/ifdef.d, + * tanya/sys/windows/ifdef.d) + */ +module tanya.sys.windows.ifdef; + +version (Windows): + +import tanya.sys.windows.def; + +union NET_LUID_LH +{ + ulong Value; + ulong Info; +} + +alias NET_LUID = NET_LUID_LH; +alias IF_LUID = NET_LUID_LH; + +alias NET_IFINDEX = ULONG; + +enum size_t IF_MAX_STRING_SIZE = 256; diff --git a/source/tanya/sys/windows/iphlpapi.d b/source/tanya/sys/windows/iphlpapi.d new file mode 100644 index 0000000..002d2f5 --- /dev/null +++ b/source/tanya/sys/windows/iphlpapi.d @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Copyright: Eugene Wissner 2018. + * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, + * Mozilla Public License, v. 2.0). + * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner) + * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/sys/windows/iphlpapi.d, + * tanya/sys/windows/iphlpapi.d) + */ +module tanya.sys.windows.iphlpapi; + +version (Windows): + +import tanya.sys.windows.def; +import tanya.sys.windows.ifdef; + +extern(Windows) +DWORD ConvertInterfaceNameToLuidA(const(CHAR)* InterfaceName, + NET_LUID* InterfaceLuid) +@nogc nothrow @system; + +extern(Windows) +DWORD ConvertInterfaceLuidToIndex(const(NET_LUID)* InterfaceLuid, + NET_IFINDEX* InterfaceIndex) +@nogc nothrow @system; + +extern(Windows) +DWORD ConvertInterfaceIndexToLuid(NET_IFINDEX InterfaceIndex, + NET_LUID* InterfaceLuid) +@nogc nothrow @system; + +extern(Windows) +DWORD ConvertInterfaceLuidToNameA(const(NET_LUID)* InterfaceLuid, + PSTR InterfaceName, + size_t Length) +@nogc nothrow @system; diff --git a/source/tanya/sys/windows/package.d b/source/tanya/sys/windows/package.d index a09f0c1..120013f 100644 --- a/source/tanya/sys/windows/package.d +++ b/source/tanya/sys/windows/package.d @@ -15,5 +15,7 @@ module tanya.sys.windows; version (Windows): public import tanya.sys.windows.def; +public import tanya.sys.windows.ifdef; +public import tanya.sys.windows.iphlpapi; public import tanya.sys.windows.winbase; public import tanya.sys.windows.winsock2;