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 }