1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2001
4 * Author: David L Stevens
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 * the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 /*
21 * Description:
22 * Tests for name to index and index to name functions in IPv6
23 */
24
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/socket.h>
28 #include <net/if.h>
29
30 #include "test.h"
31
32 static struct {
33 char *name;
34 int nonzero;
35 } n2i[] = {
36 { "lo", 1 },
37 { "eth0", 1 },
38 { "hoser75", 0 },
39 { "6", 0 },
40 };
41
42 #define N2I_COUNT (sizeof(n2i)/sizeof(n2i[0]))
43 #define I2N_RNDCOUNT 10 /* random ints */
44 #define I2N_LOWCOUNT 10 /* sequential from 0 */
45
46 static void setup(void);
47 static void n2itest(void);
48 static void i2ntest(void);
49 static void initest(void);
50
51 static void (*testfunc[])(void) = { n2itest,
52 i2ntest, initest };
53
54 char *TCID = "in6_02";
55 int TST_TOTAL = ARRAY_SIZE(testfunc);
56
main(int argc,char * argv[])57 int main(int argc, char *argv[])
58 {
59 int lc;
60 int i;
61
62 tst_parse_opts(argc, argv, NULL, NULL);
63
64 setup();
65
66 for (lc = 0; TEST_LOOPING(lc); ++lc) {
67 tst_count = 0;
68
69 for (i = 0; i < TST_TOTAL; i++)
70 (*testfunc[i])();
71 }
72
73 tst_exit();
74 }
75
76 /* if_nametoindex tests */
n2itest(void)77 void n2itest(void)
78 {
79 unsigned int i;
80 char ifname[IF_NAMESIZE], *pifn;
81
82 for (i = 0; i < N2I_COUNT; ++i) {
83 TEST(if_nametoindex(n2i[i].name));
84 if (!TEST_RETURN != !n2i[i].nonzero) {
85 tst_resm(TFAIL, "if_nametoindex(\"%s\") %ld "
86 "[should be %szero]", n2i[i].name, TEST_RETURN,
87 n2i[i].nonzero ? "non" : "");
88 return;
89 }
90 if (TEST_RETURN) {
91 pifn = if_indextoname(TEST_RETURN, ifname);
92 if (!pifn || strcmp(n2i[i].name, pifn)) {
93 tst_resm(TFAIL, "if_nametoindex(\"%s\") %ld "
94 "doesn't match if_indextoname(%ld) "
95 "\"%s\"", n2i[i].name, TEST_RETURN,
96 TEST_RETURN, pifn ? pifn : "");
97 return;
98 }
99 }
100 tst_resm(TINFO, "if_nametoindex(\"%s\") %ld",
101 n2i[i].name, TEST_RETURN);
102 }
103
104 tst_resm(TPASS, "if_nametoindex() tests succeed");
105 }
106
sub_i2ntest(unsigned int if_index)107 int sub_i2ntest(unsigned int if_index)
108 {
109 char ifname[IF_NAMESIZE];
110 unsigned int idx;
111
112 TEST((ifname == if_indextoname(if_index, ifname)));
113 if (!TEST_RETURN) {
114 if (TEST_ERRNO != ENXIO) {
115 tst_resm(TFAIL, "if_indextoname(%d) returns %ld "
116 "but errno %d != ENXIO", if_index, TEST_RETURN,
117 TEST_ERRNO);
118 return 0;
119 }
120 tst_resm(TINFO, "if_indextoname(%d) returns NULL", if_index);
121 return 1;
122 }
123 /* else, a valid interface-- double check name */
124 idx = if_nametoindex(ifname);
125 if (idx != if_index) {
126 tst_resm(TFAIL, "if_indextoname(%u) returns \"%s\" but "
127 "doesn't if_nametoindex(\"%s\") returns %u",
128 if_index, ifname, ifname, idx);
129 return 0;
130 }
131 tst_resm(TINFO, "if_indextoname(%d) returns \"%s\"", if_index, ifname);
132 return 1;
133 }
134
135 /* if_indextoname tests */
i2ntest(void)136 void i2ntest(void)
137 {
138 unsigned int i;
139
140 /* some low-numbered indexes-- likely to get valid interfaces here */
141 for (i = 0; i < I2N_LOWCOUNT; ++i)
142 if (!sub_i2ntest(i))
143 return; /* skip the rest, if broken */
144 /* some random ints; should mostly fail */
145 for (i = 0; i < I2N_RNDCOUNT; ++i)
146 if (!sub_i2ntest(rand()))
147 return; /* skip the rest, if broken */
148
149 tst_resm(TPASS, "if_indextoname() tests succeed");
150 }
151
152 /*
153 * This is an ugly, linux-only solution. getrusage() doesn't support the
154 * current data segment size, so we get it out of /proc
155 */
getdatasize(void)156 int getdatasize(void)
157 {
158 char line[128], *p;
159 int dsize = -1;
160 FILE *fp;
161
162 fp = fopen("/proc/self/status", "r");
163 if (fp == NULL)
164 return -1;
165 while (fgets(line, sizeof(line), fp)) {
166 if (strncmp(line, "VmData:", 7) == 0) {
167 dsize = strtol(line + 7, &p, 0);
168 ++p; /* skip space */
169 if (!strcmp(p, "kB"))
170 return -1; /* don't know units */
171 dsize *= 1024;
172 break;
173 }
174 }
175 fclose(fp);
176 return dsize;
177 }
178
179 /* if_nameindex tests */
initest(void)180 void initest(void)
181 {
182 struct if_nameindex *pini;
183 int i;
184 char buf[IF_NAMESIZE], *p;
185 unsigned int idx;
186 int freenicount;
187 int dsize_before, dsize_after;
188
189 pini = if_nameindex();
190 if (pini == NULL) {
191 tst_resm(TFAIL, "if_nameindex() returns NULL, errno %d (%s)",
192 TEST_ERRNO, strerror(TEST_ERRNO));
193 return;
194 }
195 for (i = 0; pini[i].if_index; ++i) {
196 p = if_indextoname(pini[i].if_index, buf);
197 if (!p || strcmp(p, pini[i].if_name)) {
198 tst_resm(TFAIL, "if_nameindex idx %d name \"%s\" but "
199 "if_indextoname(%d) is \"%s\"",
200 pini[i].if_index, pini[i].if_name,
201 pini[i].if_index, p ? p : "");
202 return;
203 }
204 idx = if_nametoindex(pini[i].if_name);
205 if (idx != pini[i].if_index) {
206 tst_resm(TFAIL, "if_nameindex idx %d name \"%s\" but "
207 "if_indextoname(\"%s\") is %d",
208 pini[i].if_index, pini[i].if_name,
209 pini[i].if_name, idx);
210 return;
211 }
212 tst_resm(TINFO, "if_nameindex idx %d name \"%s\"",
213 pini[i].if_index, pini[i].if_name);
214 }
215 if_freenameindex(pini);
216
217 /* if_freenameindex() has no error conditions; see if we run
218 * out of memory if we do it a lot.
219 */
220 dsize_before = getdatasize();
221 if (dsize_before < 0) {
222 tst_brkm(TBROK, NULL, "getdatasize failed: errno %d (%s)",
223 errno, strerror(errno));
224 }
225 /* we need to leak at least a page to detect a leak; 1 byte per call
226 * will be detected with getpagesize() calls.
227 */
228 freenicount = getpagesize();
229 for (i = 0; i < freenicount; ++i) {
230 pini = if_nameindex();
231 if (pini == NULL) {
232 tst_resm(TINFO, "if_freenameindex test failed "
233 "if_nameindex() iteration %d", i);
234 break;
235 }
236 if_freenameindex(pini);
237 }
238 dsize_after = getdatasize();
239 if (dsize_after < 0) {
240 tst_brkm(TBROK, NULL, "getdatasize failed: errno %d (%s)",
241 errno, strerror(errno));
242 }
243 if (dsize_after > dsize_before + getpagesize()) {
244 tst_resm(TFAIL, "if_freenameindex leaking memory "
245 "(%d iterations) dsize before %d dsize after %d", i,
246 dsize_before, dsize_after);
247 return;
248 } else {
249 tst_resm(TINFO, "if_freenameindex passed %d iterations", i);
250 }
251
252 tst_resm(TPASS, "if_nameindex() tests succeed");
253 }
254
setup(void)255 void setup(void)
256 {
257 TEST_PAUSE;
258
259 tst_resm(TINFO, "get interface name from LHOST_IFACES var");
260
261 char *ifnames = getenv("LHOST_IFACES");
262
263 if (!ifnames) {
264 tst_resm(TWARN, "LHOST_IFACES not defined, default to eth0");
265 return;
266 }
267
268 static char name[256];
269
270 sscanf(ifnames, "%255s", name);
271
272 if (!strcmp(name, n2i[1].name))
273 return;
274
275 tst_resm(TINFO, "change default 'eth0' name to '%s'", name);
276 n2i[1].name = name;
277 }
278