Home | History | Annotate | Download | only in lib6
      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 
     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 */
     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 
    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 */
    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  */
    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 */
    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 
    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