1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * Copyright (c) 2018 Petr Vorel <[email protected]>
5 * Copyright (c) Linux Test Project, 2005-2022
6 * Author: David L Stevens
7 */
8
9 /*\
10 * [Description]
11 *
12 * IPv6 name to index and index to name function tests.
13 */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <sys/socket.h>
20 #include <net/if.h>
21
22 #include "tst_test.h"
23
24 #define I2N_RNDCOUNT 10 /* random ints */
25 #define I2N_LOWCOUNT 10 /* sequential from 0 */
26
27 static struct {
28 char *name;
29 int nonzero;
30 } test_case[] = {
31 { "lo", 1 },
32 { NULL, 1 },
33 { "hoser75", 0 },
34 { "6", 0 },
35 };
36
37 static void setup(void);
38 static void if_nametoindex_test(void);
39 static void if_indextoname_test(void);
40 static void if_nameindex_test(void);
41
42 static void (*testfunc[])(void) = { if_nametoindex_test, if_indextoname_test,
43 if_nameindex_test };
44
if_nametoindex_test(void)45 static void if_nametoindex_test(void)
46 {
47 unsigned int i;
48 char ifname[IF_NAMESIZE], *pifn;
49
50 tst_res(TINFO, "IPv6 if_nametoindex() test");
51
52 for (i = 0; i < ARRAY_SIZE(test_case); ++i) {
53 if (test_case[i].name == NULL) {
54 tst_res(TCONF, "LHOST_IFACES not defined or invalid");
55 continue;
56 }
57
58 TEST(if_nametoindex(test_case[i].name));
59 if (!TST_RET != !test_case[i].nonzero) {
60 tst_res(TFAIL, "if_nametoindex(%s) %ld [should be %szero]",
61 test_case[i].name, TST_RET,
62 test_case[i].nonzero ? "non" : "");
63 return;
64 }
65 if (TST_RET) {
66 pifn = if_indextoname(TST_RET, ifname);
67 if (!pifn || strcmp(test_case[i].name, pifn)) {
68 tst_res(TFAIL,
69 "if_nametoindex(%s) %ld doesn't match if_indextoname(%ld) '%s'",
70 test_case[i].name, TST_RET,
71 TST_RET, pifn ? pifn : "");
72 return;
73 }
74 }
75 tst_res(TINFO, "if_nametoindex(%s) %ld",
76 test_case[i].name, TST_RET);
77 }
78
79 tst_res(TPASS, "if_nametoindex() test succeeded");
80 }
81
sub_if_indextoname_test(unsigned int if_index)82 static int sub_if_indextoname_test(unsigned int if_index)
83 {
84 char ifname[IF_NAMESIZE];
85 unsigned int idx;
86
87 TEST((ifname == if_indextoname(if_index, ifname)));
88 if (!TST_RET) {
89 if (TST_ERR != ENXIO) {
90 tst_res(TFAIL,
91 "if_indextoname(%d) returns %ld but errno %d != ENXIO",
92 if_index, TST_RET, TST_ERR);
93 return 0;
94 }
95 tst_res(TINFO, "if_indextoname(%d) returns NULL", if_index);
96 return 1;
97 }
98 /* else, a valid interface-- double check name */
99 idx = if_nametoindex(ifname);
100 if (idx != if_index) {
101 tst_res(TFAIL,
102 "if_indextoname(%u) returns '%s' but doesn't if_nametoindex(%s) returns %u",
103 if_index, ifname, ifname, idx);
104 return 0;
105 }
106 tst_res(TINFO, "if_indextoname(%d) returns '%s'", if_index, ifname);
107 return 1;
108 }
109
if_indextoname_test(void)110 static void if_indextoname_test(void)
111 {
112 unsigned int i;
113
114 tst_res(TINFO, "IPv6 if_indextoname() test");
115
116 /* some low-numbered indexes-- likely to get valid interfaces here */
117 for (i = 0; i < I2N_LOWCOUNT; ++i)
118 if (!sub_if_indextoname_test(i))
119 return; /* skip the rest, if broken */
120 /* some random ints; should mostly fail */
121 for (i = 0; i < I2N_RNDCOUNT; ++i)
122 if (!sub_if_indextoname_test(rand()))
123 return; /* skip the rest, if broken */
124
125 tst_res(TPASS, "if_indextoname() test succeeded");
126 }
127
128 /*
129 * This is an ugly, linux-only solution. getrusage() doesn't support the
130 * current data segment size, so we get it out of /proc
131 */
getdatasize(void)132 static int getdatasize(void)
133 {
134 char line[128], *p;
135 int dsize = -1;
136 FILE *fp;
137
138 fp = fopen("/proc/self/status", "r");
139 if (fp == NULL)
140 return -1;
141 while (fgets(line, sizeof(line), fp)) {
142 if (strncmp(line, "VmData:", 7) == 0) {
143 dsize = strtol(line + 7, &p, 0);
144 ++p; /* skip space */
145 if (!strcmp(p, "kB"))
146 return -1; /* don't know units */
147 dsize *= 1024;
148 break;
149 }
150 }
151 fclose(fp);
152 return dsize;
153 }
154
if_nameindex_test(void)155 static void if_nameindex_test(void)
156 {
157 struct if_nameindex *pini;
158 int i;
159 char buf[IF_NAMESIZE], *p;
160 unsigned int idx;
161 int freenicount;
162 int dsize_before, dsize_after;
163
164 tst_res(TINFO, "IPv6 if_nameindex() test");
165
166 pini = if_nameindex();
167 if (pini == NULL) {
168 tst_res(TFAIL, "if_nameindex() returns NULL, errno %d (%s)",
169 TST_ERR, strerror(TST_ERR));
170 return;
171 }
172 for (i = 0; pini[i].if_index; ++i) {
173 p = if_indextoname(pini[i].if_index, buf);
174 if (!p || strcmp(p, pini[i].if_name)) {
175 tst_res(TFAIL,
176 "if_nameindex() idx %d name '%s' but if_indextoname(%d) is '%s'",
177 pini[i].if_index, pini[i].if_name,
178 pini[i].if_index, p ? p : "");
179 return;
180 }
181 idx = if_nametoindex(pini[i].if_name);
182 if (idx != pini[i].if_index) {
183 tst_res(TFAIL,
184 "if_nameindex() idx %d name '%s' but if_indextoname(%s) is %d",
185 pini[i].if_index, pini[i].if_name,
186 pini[i].if_name, idx);
187 return;
188 }
189 tst_res(TINFO, "if_nameindex() idx %d name '%s'",
190 pini[i].if_index, pini[i].if_name);
191 }
192 if_freenameindex(pini);
193
194 /*
195 * if_freenameindex() has no error conditions; see if we run
196 * out of memory if we do it a lot.
197 */
198 dsize_before = getdatasize();
199 if (dsize_before < 0) {
200 tst_brk(TBROK, "getdatasize failed: errno %d (%s)",
201 errno, strerror(errno));
202 }
203
204 /*
205 * we need to leak at least a page to detect a leak; 1 byte per call
206 * will be detected with getpagesize() calls.
207 */
208 freenicount = getpagesize();
209 for (i = 0; i < freenicount; ++i) {
210 pini = if_nameindex();
211 if (pini == NULL) {
212 tst_res(TINFO,
213 "if_freenameindex test failed if_nameindex() iteration %d", i);
214 break;
215 }
216 if_freenameindex(pini);
217 }
218 dsize_after = getdatasize();
219 if (dsize_after < 0) {
220 tst_brk(TBROK, "getdatasize failed: errno %d (%s)",
221 errno, strerror(errno));
222 }
223 if (dsize_after > dsize_before + getpagesize()) {
224 tst_res(TFAIL,
225 "if_freenameindex leaking memory (%d iterations) dsize before %d dsize after %d",
226 i, dsize_before, dsize_after);
227 return;
228 }
229 tst_res(TINFO, "if_freenameindex passed %d iterations", i);
230
231 tst_res(TPASS, "if_nameindex() test succeeded");
232 }
233
setup(void)234 static void setup(void)
235 {
236 char *ifnames = getenv("LHOST_IFACES");
237
238 if (!ifnames)
239 return;
240
241 static char name[256];
242 int ret;
243
244 ret = sscanf(ifnames, "%255s", name);
245 if (ret == -1)
246 return;
247
248 tst_res(TINFO, "get interface name from LHOST_IFACES: '%s'", name);
249 test_case[1].name = name;
250 }
251
do_test(unsigned int i)252 static void do_test(unsigned int i)
253 {
254 testfunc[i]();
255 }
256
257 static struct tst_test test = {
258 .tcnt = ARRAY_SIZE(testfunc),
259 .setup = setup,
260 .test = do_test,
261 };
262