1a6cc4bbasomers/*-
2a6cc4bbasomers * Copyright (c) 2014 Spectra Logic Corporation
3a6cc4bbasomers * All rights reserved.
4a6cc4bbasomers *
5a6cc4bbasomers * Redistribution and use in source and binary forms, with or without
6a6cc4bbasomers * modification, are permitted provided that the following conditions
7a6cc4bbasomers * are met:
8a6cc4bbasomers * 1. Redistributions of source code must retain the above copyright
9a6cc4bbasomers *    notice, this list of conditions, and the following disclaimer,
10a6cc4bbasomers *    without modification.
11a6cc4bbasomers * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12a6cc4bbasomers *    substantially similar to the "NO WARRANTY" disclaimer below
13a6cc4bbasomers *    ("Disclaimer") and any redistribution must be conditioned upon
14a6cc4bbasomers *    including a substantially similar Disclaimer requirement for further
15a6cc4bbasomers *    binary redistribution.
16a6cc4bbasomers *
17a6cc4bbasomers * NO WARRANTY
18a6cc4bbasomers * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19a6cc4bbasomers * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20a6cc4bbasomers * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21a6cc4bbasomers * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22a6cc4bbasomers * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23a6cc4bbasomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24a6cc4bbasomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25a6cc4bbasomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26a6cc4bbasomers * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27a6cc4bbasomers * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28a6cc4bbasomers * POSSIBILITY OF SUCH DAMAGES.
29a6cc4bbasomers *
30a6cc4bbasomers * $FreeBSD$
31a6cc4bbasomers */
32a6cc4bbasomers
33a6cc4bbasomers#include <rpc/rpc.h>
34a6cc4bbasomers#include <sys/types.h>
35a6cc4bbasomers#include <sys/socket.h>
36a6cc4bbasomers
37a6cc4bbasomers#include <net/if.h>
38a6cc4bbasomers#include <netinet/in.h>
39a6cc4bbasomers#include <arpa/inet.h>
40a6cc4bbasomers
41a6cc4bbasomers#include <ifaddrs.h>
42a6cc4bbasomers#include <stdlib.h>
43a6cc4bbasomers
44a6cc4bbasomers#include <atf-c.h>
45a6cc4bbasomers
46a6cc4bbasomers#include "rpcbind.h"
47a6cc4bbasomers
48a6cc4bbasomers#define MAX_IFADDRS 16
49a6cc4bbasomers
50a6cc4bbasomersint debugging = false;
51a6cc4bbasomers
52a6cc4bbasomers/* Data for mocking getifaddrs */
53a6cc4bbasomersstruct ifaddr_storage {
54a6cc4bbasomers	struct ifaddrs ifaddr;
55a6cc4bbasomers	struct sockaddr_storage addr;
56a6cc4bbasomers	struct sockaddr_storage mask;
57a6cc4bbasomers	struct sockaddr_storage bcast;
58a6cc4bbasomers} mock_ifaddr_storage[MAX_IFADDRS];
59a6cc4bbasomersstruct ifaddrs *mock_ifaddrs = NULL;
60a6cc4bbasomersint ifaddr_count = 0;
61a6cc4bbasomers
62a6cc4bbasomers/* Data for mocking listen_addr */
63a6cc4bbasomersint bind_address_count = 0;
64a6cc4bbasomersstruct sockaddr* bind_addresses[MAX_IFADDRS];
65a6cc4bbasomers
66a6cc4bbasomers/* Stub library functions */
67a6cc4bbasomersvoid
68a6cc4bbasomersfreeifaddrs(struct ifaddrs *ifp __unused)
69a6cc4bbasomers{
70a6cc4bbasomers	return ;
71a6cc4bbasomers}
72a6cc4bbasomers
73a6cc4bbasomersint
74a6cc4bbasomersgetifaddrs(struct ifaddrs **ifap)
75a6cc4bbasomers{
76a6cc4bbasomers	*ifap = mock_ifaddrs;
77a6cc4bbasomers	return (0);
78a6cc4bbasomers}
79a6cc4bbasomers
80a6cc4bbasomersstatic void
81a6cc4bbasomersmock_ifaddr4(const char* name, const char* addr, const char* mask,
82a6cc4bbasomers    const char* bcast, unsigned int flags, bool bind)
83a6cc4bbasomers{
84a6cc4bbasomers	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
85a6cc4bbasomers	struct sockaddr_in *in = (struct sockaddr_in*)
86a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].addr;
87a6cc4bbasomers	struct sockaddr_in *mask_in = (struct sockaddr_in*)
88a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].mask;
89a6cc4bbasomers	struct sockaddr_in *bcast_in = (struct sockaddr_in*)
90a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].bcast;
91a6cc4bbasomers
92a6cc4bbasomers	in->sin_family = AF_INET;
93a6cc4bbasomers	in->sin_port = 0;
947973595asomers	in->sin_len = sizeof(*in);
95a6cc4bbasomers	in->sin_addr.s_addr = inet_addr(addr);
96a6cc4bbasomers	mask_in->sin_family = AF_INET;
97a6cc4bbasomers	mask_in->sin_port = 0;
987973595asomers	mask_in->sin_len = sizeof(*mask_in);
99a6cc4bbasomers	mask_in->sin_addr.s_addr = inet_addr(mask);
100a6cc4bbasomers	bcast_in->sin_family = AF_INET;
101a6cc4bbasomers	bcast_in->sin_port = 0;
1027973595asomers	bcast_in->sin_len = sizeof(*bcast_in);
103a6cc4bbasomers	bcast_in->sin_addr.s_addr = inet_addr(bcast);
104a6cc4bbasomers	*ifaddr = (struct ifaddrs) {
105a6cc4bbasomers		.ifa_next = NULL,
106a6cc4bbasomers		.ifa_name = (char*) name,
107a6cc4bbasomers		.ifa_flags = flags,
108a6cc4bbasomers		.ifa_addr = (struct sockaddr*) in,
109a6cc4bbasomers		.ifa_netmask = (struct sockaddr*) mask_in,
110a6cc4bbasomers		.ifa_broadaddr = (struct sockaddr*) bcast_in,
111a6cc4bbasomers		.ifa_data = NULL,	/* addrmerge doesn't care*/
112a6cc4bbasomers	};
113a6cc4bbasomers
114a6cc4bbasomers	if (ifaddr_count > 0)
115a6cc4bbasomers		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
116a6cc4bbasomers	ifaddr_count++;
117a6cc4bbasomers	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
118a6cc4bbasomers
119a6cc4bbasomers	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
120a6cc4bbasomers	if (bind) {
121a6cc4bbasomers		bind_addresses[bind_address_count] = (struct sockaddr*)in;
122a6cc4bbasomers		bind_address_count++;
123a6cc4bbasomers	}
124a6cc4bbasomers}
125a6cc4bbasomers
126a6cc4bbasomers#ifdef INET6
127a6cc4bbasomersstatic void
128a6cc4bbasomersmock_ifaddr6(const char* name, const char* addr, const char* mask,
129a6cc4bbasomers    const char* bcast, unsigned int flags, uint32_t scope_id, bool bind)
130a6cc4bbasomers{
131a6cc4bbasomers	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
132a6cc4bbasomers	struct sockaddr_in6 *in6 = (struct sockaddr_in6*)
133a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].addr;
134a6cc4bbasomers	struct sockaddr_in6 *mask_in6 = (struct sockaddr_in6*)
135a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].mask;
136a6cc4bbasomers	struct sockaddr_in6 *bcast_in6 = (struct sockaddr_in6*)
137a6cc4bbasomers	    			&mock_ifaddr_storage[ifaddr_count].bcast;
138a6cc4bbasomers
139a6cc4bbasomers	in6->sin6_family = AF_INET6;
140a6cc4bbasomers	in6->sin6_port = 0;
141a6cc4bbasomers	in6->sin6_len = sizeof(*in6);
142a6cc4bbasomers	in6->sin6_scope_id = scope_id;
143a6cc4bbasomers	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, addr, (void*)&in6->sin6_addr));
144a6cc4bbasomers	mask_in6->sin6_family = AF_INET6;
145a6cc4bbasomers	mask_in6->sin6_port = 0;
146a6cc4bbasomers	mask_in6->sin6_len = sizeof(*mask_in6);
147a6cc4bbasomers	mask_in6->sin6_scope_id = scope_id;
148a6cc4bbasomers	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, mask,
149a6cc4bbasomers	    (void*)&mask_in6->sin6_addr));
150a6cc4bbasomers	bcast_in6->sin6_family = AF_INET6;
151a6cc4bbasomers	bcast_in6->sin6_port = 0;
152a6cc4bbasomers	bcast_in6->sin6_len = sizeof(*bcast_in6);
153a6cc4bbasomers	bcast_in6->sin6_scope_id = scope_id;
154a6cc4bbasomers	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, bcast,
155a6cc4bbasomers	    (void*)&bcast_in6->sin6_addr));
156a6cc4bbasomers	*ifaddr = (struct ifaddrs) {
157a6cc4bbasomers		.ifa_next = NULL,
158a6cc4bbasomers		.ifa_name = (char*) name,
159a6cc4bbasomers		.ifa_flags = flags,
160a6cc4bbasomers		.ifa_addr = (struct sockaddr*) in6,
161a6cc4bbasomers		.ifa_netmask = (struct sockaddr*) mask_in6,
162a6cc4bbasomers		.ifa_broadaddr = (struct sockaddr*) bcast_in6,
163a6cc4bbasomers		.ifa_data = NULL,	/* addrmerge doesn't care*/
164a6cc4bbasomers	};
165a6cc4bbasomers
166a6cc4bbasomers	if (ifaddr_count > 0)
167a6cc4bbasomers		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
168a6cc4bbasomers	ifaddr_count++;
169a6cc4bbasomers	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
170a6cc4bbasomers
171a6cc4bbasomers	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
172a6cc4bbasomers	if (bind) {
173a6cc4bbasomers		bind_addresses[bind_address_count] = (struct sockaddr*)in6;
174a6cc4bbasomers		bind_address_count++;
175a6cc4bbasomers	}
176a6cc4bbasomers}
177a6cc4bbasomers#else
178a6cc4bbasomersstatic void
179a6cc4bbasomersmock_ifaddr6(const char* name __unused, const char* addr __unused,
180a6cc4bbasomers    const char* mask __unused, const char* bcast __unused,
181a6cc4bbasomers    unsigned int flags __unused, uint32_t scope_id __unused, bool bind __unused)
182a6cc4bbasomers{
183a6cc4bbasomers}
184a6cc4bbasomers#endif /*INET6 */
185a6cc4bbasomers
186a6cc4bbasomersstatic void
187a6cc4bbasomersmock_lo0(void)
188a6cc4bbasomers{
189a6cc4bbasomers	/*
190a6cc4bbasomers	 * This broadcast address looks wrong, but it's what getifaddrs(2)
191a6cc4bbasomers	 * actually returns.  It's invalid because IFF_BROADCAST is not set
192a6cc4bbasomers	 */
193a6cc4bbasomers	mock_ifaddr4("lo0", "127.0.0.1", "255.0.0.0", "127.0.0.1",
194a6cc4bbasomers	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, false);
195a6cc4bbasomers	mock_ifaddr6("lo0", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
196a6cc4bbasomers	    "::1",
197a6cc4bbasomers	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, 0, false);
198a6cc4bbasomers}
199a6cc4bbasomers
200a6cc4bbasomersstatic void
201a6cc4bbasomersmock_igb0(void)
202a6cc4bbasomers{
203a6cc4bbasomers	mock_ifaddr4("igb0", "192.0.2.2", "255.255.255.128", "192.0.2.127",
204a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
205a6cc4bbasomers	    false);
206a6cc4bbasomers	mock_ifaddr6("igb0", "2001:db8::2", "ffff:ffff:ffff:ffff::",
207a6cc4bbasomers	    "2001:db8::ffff:ffff:ffff:ffff",
208a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
209a6cc4bbasomers	    0, false);
210a6cc4bbasomers	/* Link local address */
211a6cc4bbasomers	mock_ifaddr6("igb0", "fe80::2", "ffff:ffff:ffff:ffff::",
212a6cc4bbasomers	    "fe80::ffff:ffff:ffff:ffff",
213a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
214a6cc4bbasomers	    2, false);
215a6cc4bbasomers}
216a6cc4bbasomers
217a6cc4bbasomers/* On the same subnet as igb0 */
218a6cc4bbasomersstatic void
219a6cc4bbasomersmock_igb1(bool bind)
220a6cc4bbasomers{
221a6cc4bbasomers	mock_ifaddr4("igb1", "192.0.2.3", "255.255.255.128", "192.0.2.127",
222a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
223a6cc4bbasomers	    bind);
224a6cc4bbasomers	mock_ifaddr6("igb1", "2001:db8::3", "ffff:ffff:ffff:ffff::",
225a6cc4bbasomers	    "2001:db8::ffff:ffff:ffff:ffff",
226a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
227a6cc4bbasomers	    0, bind);
228a6cc4bbasomers	/* Link local address */
229a6cc4bbasomers	mock_ifaddr6("igb1", "fe80::3", "ffff:ffff:ffff:ffff::",
230a6cc4bbasomers	    "fe80::ffff:ffff:ffff:ffff",
231a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
232a6cc4bbasomers	    3, bind);
233a6cc4bbasomers}
234a6cc4bbasomers
235a6cc4bbasomers/* igb2 is on a different subnet than igb0 */
236a6cc4bbasomersstatic void
237a6cc4bbasomersmock_igb2(void)
238a6cc4bbasomers{
239a6cc4bbasomers	mock_ifaddr4("igb2", "192.0.2.130", "255.255.255.128", "192.0.2.255",
240a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
241a6cc4bbasomers	    false);
242a6cc4bbasomers	mock_ifaddr6("igb2", "2001:db8:1::2", "ffff:ffff:ffff:ffff::",
243a6cc4bbasomers	    "2001:db8:1:0:ffff:ffff:ffff:ffff",
244a6cc4bbasomers	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
245a6cc4bbasomers	    0, false);
246