1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /**
6 * Network interfaces.
7 *
8 * Copyright: Eugene Wissner 2018-2020.
9 * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
10 * Mozilla Public License, v. 2.0).
11 * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
12 * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/net/iface.d,
13 * tanya/net/iface.d)
14 */
15 module tanya.net.iface;
16
17 import tanya.algorithm.mutation;
18 import tanya.container..string;
19 import tanya.meta.trait;
20 import tanya.meta.transform;
21 import tanya.range;
22
23 version (Windows)
24 {
25 import tanya.sys.windows.ifdef;
26 import tanya.sys.windows.iphlpapi;
27 }
28 else version (Posix)
29 {
30 import core.sys.posix.net.if_;
31 }
32
33 /**
34 * Converts the name of a network interface to its index.
35 *
36 * If an interface with the name $(D_PARAM name) cannot be found or another
37 * error occurres, returns 0.
38 *
39 * Params:
40 * name = Interface name.
41 *
42 * Returns: Returns interface index or 0.
43 */
44 uint nameToIndex(R)(R name) @trusted
45 if (isInputRange!R && is(Unqual!(ElementType!R) == char) && hasLength!R)
46 {
47 version (Windows)
48 {
49 if (name.length > IF_MAX_STRING_SIZE)
50 {
51 return 0;
52 }
53 char[IF_MAX_STRING_SIZE + 1] buffer;
54 NET_LUID luid;
55
56 copy(name, buffer[]);
57 buffer[name.length] = '\0';
58
59 if (ConvertInterfaceNameToLuidA(buffer.ptr, &luid) != 0)
60 {
61 return 0;
62 }
63 NET_IFINDEX index;
64 if (ConvertInterfaceLuidToIndex(&luid, &index) == 0)
65 {
66 return index;
67 }
68 return 0;
69 }
70 else version (Posix)
71 {
72 if (name.length >= IF_NAMESIZE)
73 {
74 return 0;
75 }
76 char[IF_NAMESIZE] buffer;
77
78 copy(name, buffer[]);
79 buffer[name.length] = '\0';
80
81 return if_nametoindex(buffer.ptr);
82 }
83 }
84
85 ///
86 @nogc nothrow @safe unittest
87 {
88 version (linux)
89 {
90 assert(nameToIndex("lo") == 1);
91 }
92 else version (Windows)
93 {
94 assert(nameToIndex("loopback_0") == 1);
95 }
96 else
97 {
98 assert(nameToIndex("lo0") == 1);
99 }
100 assert(nameToIndex("ecafretni") == 0);
101 }
102
103 /**
104 * Converts the index of a network interface to its name.
105 *
106 * If an interface with the $(D_PARAM index) cannot be found or another
107 * error occurres, returns an empty $(D_PSYMBOL String).
108 *
109 * Params:
110 * index = Interface index.
111 *
112 * Returns: Returns interface name or an empty $(D_PSYMBOL String).
113 */
114 String indexToName(uint index) @nogc nothrow @trusted
115 {
116 import tanya.memory.op : findNullTerminated;
117
118 version (Windows)
119 {
120 NET_LUID luid;
121 if (ConvertInterfaceIndexToLuid(index, &luid) != 0)
122 {
123 return String();
124 }
125
126 char[IF_MAX_STRING_SIZE + 1] buffer;
127 if (ConvertInterfaceLuidToNameA(&luid,
128 buffer.ptr,
129 IF_MAX_STRING_SIZE + 1) != 0)
130 {
131 return String();
132 }
133 return String(findNullTerminated(buffer));
134 }
135 else version (Posix)
136 {
137 char[IF_NAMESIZE] buffer;
138 if (if_indextoname(index, buffer.ptr) is null)
139 {
140 return String();
141 }
142 return String(findNullTerminated(buffer));
143 }
144 }
145
146 /**
147 * $(D_PSYMBOL AddressFamily) specifies a communication domain; this selects
148 * the protocol family which will be used for communication.
149 */
150 enum AddressFamily : int
151 {
152 unspec = 0, /// Unspecified.
153 local = 1, /// Local to host (pipes and file-domain).
154 unix = local, /// POSIX name for PF_LOCAL.
155 inet = 2, /// IP protocol family.
156 ax25 = 3, /// Amateur Radio AX.25.
157 ipx = 4, /// Novell Internet Protocol.
158 appletalk = 5, /// Appletalk DDP.
159 netrom = 6, /// Amateur radio NetROM.
160 bridge = 7, /// Multiprotocol bridge.
161 atmpvc = 8, /// ATM PVCs.
162 x25 = 9, /// Reserved for X.25 project.
163 inet6 = 10, /// IP version 6.
164 }