#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dnet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <check.h>
#define ADDR_PACK(a, ip) \
(a)->addr_type = ADDR_TYPE_IP; \
(a)->addr_bits = IP_ADDR_BITS; \
(a)->addr_ip = (ip)
#ifdef HAVE_SOCKADDR_SA_LEN
#define SIN_PACK(s, ip, port) \
(s)->sin_len = sizeof(struct sockaddr_in); \
(s)->sin_family = AF_INET; \
(s)->sin_port = htons(port); \
(s)->sin_addr.s_addr = (ip)
#else
#define SIN_PACK(s, ip, port) \
(s)->sin_family = AF_INET; \
(s)->sin_port = htons(port); \
(s)->sin_addr.s_addr = (ip)
#endif
typedef struct sockaddr SA;
START_TEST(test_addr_pack)
{
struct addr a, b;
memset(&a, 0, sizeof(a)); memset(&b, 0, sizeof(b));
ADDR_PACK(&a, 666);
addr_pack(&b, ADDR_TYPE_IP, IP_ADDR_BITS, &a.addr_ip, IP_ADDR_LEN);
fail_unless(memcmp(&a, &b, sizeof(a)) == 0, "got different address");
}
END_TEST
START_TEST(test_addr_cmp)
{
struct addr a, b;
ADDR_PACK(&a, 666);
memcpy(&b, &a, sizeof(a));
fail_unless(addr_cmp(&a, &b) == 0, "failed on equal addresses");
b.addr_type = ADDR_TYPE_ETH;
fail_unless(addr_cmp(&a, &b) != 0, "failed on different addr_type");
memcpy(&b, &a, sizeof(a)); b.addr_bits--;
fail_unless(addr_cmp(&a, &b) > 0, "failed on lesser addr_bits");
memcpy(&b, &a, sizeof(a)); b.addr_ip--;
fail_unless(addr_cmp(&a, &b) != 0, "failed on different addr_ip");
addr_aton("10.0.0.1", &a);
addr_aton("10.0.0.2", &b);
fail_unless(addr_cmp(&a, &b) < 0, "failed on lesser addr compare");
fail_unless(addr_cmp(&b, &a) > 0, "failed on greater addr compare");
}
END_TEST
START_TEST(test_addr_bcast)
{
struct addr a, b;
ADDR_PACK(&a, htonl(0x01020304));
a.addr_bits = 29; addr_bcast(&a, &b);
fail_unless(b.addr_ip == htonl(0x01020307), "wrong for /29");
a.addr_bits = 16; addr_bcast(&a, &b);
fail_unless(b.addr_ip == htonl(0x0102ffff), "wrong for /16");
a.addr_bits = 5; addr_bcast(&a, &b);
fail_unless(b.addr_ip == htonl(0x7ffffff), "wrong for /5");
}
END_TEST
START_TEST(test_addr_net)
{
struct addr a, b;
ADDR_PACK(&a, htonl(0x01020304));
a.addr_bits = 24; addr_net(&a, &b);
fail_unless(b.addr_ip == htonl(0x01020300), "wrong for /24");
addr_aton("cafe:babe::dead:beef", &a);
a.addr_bits = 20; addr_net(&a, &b);
addr_aton("cafe:b000::", &a);
a.addr_bits = IP6_ADDR_BITS;
fail_unless(addr_cmp(&a, &b) == 0, "IPv6 net failed");
}
END_TEST
START_TEST(test_addr_ntop)
{
struct ntop {
u_char *n;
char *p;
} *ntop, ntop_ip6[] = {
{ IP6_ADDR_UNSPEC, "::" },
{ IP6_ADDR_LOOPBACK, "::1" },
{ "\xfe\x08\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x01", "fe08::1" },
{ "\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff",
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" },
{ "\xca\xfe\xba\xbe\x00\x00\x00\x00\x00\x00\x00\x00"
"\xde\xad\xbe\xef", "cafe:babe::dead:beef" },
{ "\xfe\xed\xfa\xce\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00", "feed:face::" },
{ "\x00\x00\x00\x0a\x00\x0b\x00\x0c\x00"
"\x0d\x00\x0e\x00\x0f\x00\x00", "0:a:b:c:d:e:f:0" },
{ "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\xff\xff\x01\x02\x03\x04", "::ffff:1.2.3.4" },
{ NULL }
};
struct addr a;
char buf[64];
ADDR_PACK(&a, htonl(0x010203ff));
a.addr_bits = 23; addr_ntop(&a, buf, sizeof(buf));
fail_unless(strcmp(buf, "1.2.3.255/23") == 0, "bad /23 handling");
a.addr_bits = 0; addr_ntop(&a, buf, sizeof(buf));
fail_unless(strcmp(buf, "1.2.3.255/0") == 0, "bad /0 handling");
a.addr_bits = 32; addr_ntop(&a, buf, sizeof(buf));
fail_unless(strcmp(buf, "1.2.3.255") == 0, "bad /32 handling");
fail_unless(addr_ntop(&a, buf, 9) == NULL, "buffer overflow?");
addr_pack(&a, ADDR_TYPE_ETH, ETH_ADDR_BITS,
"\x00\x00\x00\x00\x00\x00", ETH_ADDR_LEN);
fail_unless(strcmp(addr_ntop(&a, buf, sizeof(buf)),
"00:00:00:00:00:00") == 0, "bad empty MAC handling");
memcpy(&a.addr_eth, "\x00\x0d\x0e\x0a\x0d\x00", ETH_ADDR_LEN);
fail_unless(strcmp(addr_ntop(&a, buf, sizeof(buf)),
"00:0d:0e:0a:0d:00") == 0, "b0rked");
a.addr_bits = 16;
fail_unless(addr_ntop(&a, buf, sizeof(buf)) == NULL, "took /16 mask");
for (ntop = ntop_ip6; ntop->n != NULL; ntop++) {
addr_pack(&a, ADDR_TYPE_IP6, IP6_ADDR_BITS, ntop->n,
IP6_ADDR_LEN);
fail_unless(strcmp(addr_ntop(&a, buf, sizeof(buf)),
ntop->p) == 0, ntop->p);
}
}
END_TEST
START_TEST(test_addr_pton)
{
struct pton {
char *p;
u_char *n;
} *pton, pton_ip6[] = {
{ "::", IP6_ADDR_UNSPEC },
{ "::1", IP6_ADDR_LOOPBACK },
{ "fe08::", "\xfe\x08\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00" },
{ "fe08::1", "\xfe\x08\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x01" },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" },
{ "cafe::babe:dead:beef:0:ffff", "\xca\xfe\x00\x00\x00\x00"
"\xba\xbe\xde\xad\xbe\xef\x00\x00\xff\xff" },
{ "::1.2.3.4", "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x01\x02\x03\x04" },
{ ":cafe", NULL }, { ":::", NULL }, { "::fffff", NULL },
{ NULL }
}, pton_eth[] = {
{ "0:d:e:a:d:0", "\x00\x0d\x0e\x0a\x0d\x00" },
{ "ff:ff:ff:ff:ff:ff", ETH_ADDR_BROADCAST },
{ "00:d:0e:a:0d:0", "\x00\x0d\x0e\x0a\x0d\x00" },
{ ":d:e:a:d:0", NULL }, { "0:d:e:a:d:", NULL },
{ "0:d:e:a:def:0", NULL }, { "0:d:e:a:d:0:0", NULL },
{ "0:0:0:0:0:0", "\x00\x00\x00\x00\x00\x00" },
{ NULL }
};
struct addr a, b;
int res;
ADDR_PACK(&a, htonl(0x010203ff));
a.addr_bits = 17; addr_pton("1.2.3.255/17", &b);
fail_unless(addr_cmp(&a, &b) == 0, "bad /17 handling");
a.addr_bits = 32; addr_pton("1.2.3.255", &b);
fail_unless(addr_cmp(&a, &b) == 0, "bad handling of missing /32");
fail_unless(addr_pton("1.2.3.4/33", &b) < 0, "accepted /33");
fail_unless(addr_pton("1.2.3.256", &b) < 0, "accepted .256");
fail_unless(addr_pton("1.2.3.4.5", &b) < 0, "accepted quint octet");
fail_unless(addr_pton("1.2.3", &b) < 0, "accepted triple octet");
fail_unless(addr_pton("localhost", &b) == 0, "barfed on localhost");
fail_unless(addr_pton("localhost/24", &b) == 0,
"barfed on localhost/24");
addr_pton("1.2.3.4/24", &a);
addr_pton("1.2.3.4/255.255.255.0", &b);
fail_unless(addr_cmp(&a, &b) == 0, "bad /255.255.255.0 handling");
for (pton = pton_eth; pton->n != NULL; pton++) {
res = addr_pton(pton->p, &a);
if (pton->n != NULL) {
fail_unless(res == 0 &&
a.addr_type == ADDR_TYPE_ETH &&
a.addr_bits == ETH_ADDR_BITS &&
memcmp(&a.addr_eth, pton->n, ETH_ADDR_LEN) == 0,
pton->p);
} else {
fail_unless(res < 0, pton->p);
}
}
for (pton = pton_ip6; pton->n != NULL; pton++) {
res = addr_pton(pton->p, &a);
if (pton->n != NULL) {
fail_unless(res == 0 &&
a.addr_type == ADDR_TYPE_IP6 &&
a.addr_bits == IP6_ADDR_BITS &&
memcmp(&a.addr_ip6, pton->n, IP6_ADDR_LEN) == 0,
pton->p);
} else {
fail_unless(res < 0, pton->p);
}
}
}
END_TEST
START_TEST(test_addr_ntoa)
{
struct addr a;
int i;
ADDR_PACK(&a, htonl(0x01020304));
for (i = 0; i < 1000; i++) {
fail_unless(strcmp(addr_ntoa(&a), "1.2.3.4") == 0,
"barfed on 1.2.3.4 loop");
}
}
END_TEST
START_TEST(test_addr_ntos)
{
struct sockaddr_in s1, s2;
struct addr a;
memset(&s1, 0, sizeof(s1));
memset(&s2, 0, sizeof(s2));
SIN_PACK(&s1, htonl(0x01020304), 0);
ADDR_PACK(&a, htonl(0x01020304));
addr_ntos(&a, (SA *)&s2);
fail_unless(memcmp(&s1, &s2, sizeof(s1)) == 0, "bad sockaddr_in");
}
END_TEST
START_TEST(test_addr_ston)
{
struct sockaddr_in s, t;
struct addr a, b;
memset(&a, 0, sizeof(a));
ADDR_PACK(&a, htonl(0x01020304));
memcpy(&b, &a, sizeof(&b));
SIN_PACK(&s, htonl(0x01020304), 0);
memcpy(&t, &s, sizeof(&t));
addr_ston((SA *)&s, &b);
fail_unless(memcmp(&a, &b, sizeof(a)) == 0, "bad addr");
#ifdef HAVE_SOCKADDR_SA_LEN
s.sin_len = 0;
fail_unless(addr_ston((SA *)&s, &b) == 0 && addr_cmp(&a, &b) == 0,
"sin_len == 0");
#endif
s.sin_family = 123;
fail_unless(addr_ston((SA *)&s, &b) < 0, "sin_family == 123");
}
END_TEST
START_TEST(test_addr_btos)
{
struct sockaddr s;
struct addr a;
ADDR_PACK(&a, htonl(0xffffff00));
a.addr_bits = 24;
fail_unless(addr_btos(a.addr_bits, &s) == 0, "b0rked");
}
END_TEST
START_TEST(test_addr_stob)
{
struct sockaddr_in s;
struct addr a;
SIN_PACK(&s, htonl(0xffffff00), 0);
addr_stob((SA *)&s, &a.addr_bits);
fail_unless(a.addr_bits == 24, "b0rked");
/* XXX - BSD routing sockets or SIOCGIFNETMASK */
s.sin_family = 0;
fail_unless(addr_stob((SA *)&s, &a.addr_bits) == 0 &&
a.addr_bits == 24, "sin_family = 0");
}
END_TEST
START_TEST(test_addr_btom)
{
struct addr a;
uint32_t mask;
ADDR_PACK(&a, htonl(0xffffff00));
a.addr_bits = 24;
addr_btom(a.addr_bits, &mask, sizeof(mask));
fail_unless(mask == htonl(0xffffff00), "b0rked");
}
END_TEST
START_TEST(test_addr_mtob)
{
struct addr a;
uint32_t mask;
mask = htonl(0xffffff00);
addr_mtob(&mask, sizeof(mask), &a.addr_bits);
fail_unless(a.addr_bits == 24, "b0rked");
}
END_TEST
Suite *
addr_suite(void)
{
Suite *s = suite_create("addr");
TCase *tc_core = tcase_create("core");
suite_add_tcase(s, tc_core);
tcase_add_test(tc_core, test_addr_pack);
tcase_add_test(tc_core, test_addr_cmp);
tcase_add_test(tc_core, test_addr_bcast);
tcase_add_test(tc_core, test_addr_net);
tcase_add_test(tc_core, test_addr_ntop);
tcase_add_test(tc_core, test_addr_pton);
tcase_add_test(tc_core, test_addr_ntoa);
tcase_add_test(tc_core, test_addr_ntos);
tcase_add_test(tc_core, test_addr_ston);
tcase_add_test(tc_core, test_addr_btos);
tcase_add_test(tc_core, test_addr_stob);
tcase_add_test(tc_core, test_addr_btom);
tcase_add_test(tc_core, test_addr_mtob);
return (s);
}
int
main(void)
{
Suite *s = addr_suite();
SRunner *sr = srunner_create(s);
int nf;
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
syntax highlighted by Code2HTML, v. 0.9.1