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