1*36589d6bSRobert Mustacchi /*
2*36589d6bSRobert Mustacchi  * This file and its contents are supplied under the terms of the
3*36589d6bSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4*36589d6bSRobert Mustacchi  * You may only use this file in accordance with the terms of version
5*36589d6bSRobert Mustacchi  * 1.0 of the CDDL.
6*36589d6bSRobert Mustacchi  *
7*36589d6bSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8*36589d6bSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9*36589d6bSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10*36589d6bSRobert Mustacchi  */
11*36589d6bSRobert Mustacchi 
12*36589d6bSRobert Mustacchi /*
13*36589d6bSRobert Mustacchi  * Copyright 2015, Joyent, Inc.
14*36589d6bSRobert Mustacchi  */
15*36589d6bSRobert Mustacchi 
16*36589d6bSRobert Mustacchi /*
17*36589d6bSRobert Mustacchi  * Files based plug-in for varpd
18*36589d6bSRobert Mustacchi  *
19*36589d6bSRobert Mustacchi  * This is a dynamic varpd plug-in that has a static backing store. It's really
20*36589d6bSRobert Mustacchi  * nothing more than a glorified version of /etc/ethers, though it facilitates
21*36589d6bSRobert Mustacchi  * a bit more. The files module allows for the full set of mappings to be fixed
22*36589d6bSRobert Mustacchi  * at creation time. In addition, it also provides support for proxying ARP,
23*36589d6bSRobert Mustacchi  * NDP, and DHCP.
24*36589d6bSRobert Mustacchi  *
25*36589d6bSRobert Mustacchi  * At this time, the plugin requires that the destination type involve both an
26*36589d6bSRobert Mustacchi  * IP address and a port; however, there's no reason that this cannot be made
27*36589d6bSRobert Mustacchi  * more flexible as we have additional encapsulation algorithms that support it.
28*36589d6bSRobert Mustacchi  * The plug-in only has a single property, which is the location of the JSON
29*36589d6bSRobert Mustacchi  * file. The JSON file itself looks something like:
30*36589d6bSRobert Mustacchi  *
31*36589d6bSRobert Mustacchi  *	{
32*36589d6bSRobert Mustacchi  *		"aa:bb:cc:dd:ee:ff": {
33*36589d6bSRobert Mustacchi  *			"arp": "10.23.69.1",
34*36589d6bSRobert Mustacchi  *			"ndp": "2600:3c00::f03c:91ff:fe96:a264",
35*36589d6bSRobert Mustacchi  *			"ip": "192.168.1.1",
36*36589d6bSRobert Mustacchi  *			"port": 8080
37*36589d6bSRobert Mustacchi  *		},
38*36589d6bSRobert Mustacchi  *		...
39*36589d6bSRobert Mustacchi  *	}
40*36589d6bSRobert Mustacchi  */
41*36589d6bSRobert Mustacchi 
42*36589d6bSRobert Mustacchi #include <libvarpd_provider.h>
43*36589d6bSRobert Mustacchi #include <umem.h>
44*36589d6bSRobert Mustacchi #include <errno.h>
45*36589d6bSRobert Mustacchi #include <thread.h>
46*36589d6bSRobert Mustacchi #include <synch.h>
47*36589d6bSRobert Mustacchi #include <strings.h>
48*36589d6bSRobert Mustacchi #include <assert.h>
49*36589d6bSRobert Mustacchi #include <limits.h>
50*36589d6bSRobert Mustacchi #include <sys/types.h>
51*36589d6bSRobert Mustacchi #include <sys/stat.h>
52*36589d6bSRobert Mustacchi #include <fcntl.h>
53*36589d6bSRobert Mustacchi #include <libnvpair.h>
54*36589d6bSRobert Mustacchi #include <unistd.h>
55*36589d6bSRobert Mustacchi #include <sys/mman.h>
56*36589d6bSRobert Mustacchi #include <sys/ethernet.h>
57*36589d6bSRobert Mustacchi #include <sys/socket.h>
58*36589d6bSRobert Mustacchi #include <netinet/in.h>
59*36589d6bSRobert Mustacchi #include <arpa/inet.h>
60*36589d6bSRobert Mustacchi 
61*36589d6bSRobert Mustacchi #include <libvarpd_files_json.h>
62*36589d6bSRobert Mustacchi 
63*36589d6bSRobert Mustacchi typedef struct varpd_files {
64*36589d6bSRobert Mustacchi 	overlay_plugin_dest_t	vaf_dest;	/* RO */
65*36589d6bSRobert Mustacchi 	varpd_provider_handle_t	*vaf_hdl;	/* RO */
66*36589d6bSRobert Mustacchi 	char			*vaf_path;	/* WO */
67*36589d6bSRobert Mustacchi 	nvlist_t		*vaf_nvl;	/* WO */
68*36589d6bSRobert Mustacchi 	uint64_t		vaf_nmisses;	/* Atomic */
69*36589d6bSRobert Mustacchi 	uint64_t		vaf_narp;	/* Atomic */
70*36589d6bSRobert Mustacchi } varpd_files_t;
71*36589d6bSRobert Mustacchi 
72*36589d6bSRobert Mustacchi static const char *varpd_files_props[] = {
73*36589d6bSRobert Mustacchi 	"files/config"
74*36589d6bSRobert Mustacchi };
75*36589d6bSRobert Mustacchi 
76*36589d6bSRobert Mustacchi static boolean_t
varpd_files_valid_dest(overlay_plugin_dest_t dest)77*36589d6bSRobert Mustacchi varpd_files_valid_dest(overlay_plugin_dest_t dest)
78*36589d6bSRobert Mustacchi {
79*36589d6bSRobert Mustacchi 	if (dest & ~(OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT))
80*36589d6bSRobert Mustacchi 		return (B_FALSE);
81*36589d6bSRobert Mustacchi 
82*36589d6bSRobert Mustacchi 	if (!(dest & (OVERLAY_PLUGIN_D_IP | OVERLAY_PLUGIN_D_PORT)))
83*36589d6bSRobert Mustacchi 		return (B_FALSE);
84*36589d6bSRobert Mustacchi 
85*36589d6bSRobert Mustacchi 	return (B_TRUE);
86*36589d6bSRobert Mustacchi }
87*36589d6bSRobert Mustacchi 
88*36589d6bSRobert Mustacchi static int
varpd_files_create(varpd_provider_handle_t * hdl,void ** outp,overlay_plugin_dest_t dest)89*36589d6bSRobert Mustacchi varpd_files_create(varpd_provider_handle_t *hdl, void **outp,
90*36589d6bSRobert Mustacchi     overlay_plugin_dest_t dest)
91*36589d6bSRobert Mustacchi {
92*36589d6bSRobert Mustacchi 	varpd_files_t *vaf;
93*36589d6bSRobert Mustacchi 
94*36589d6bSRobert Mustacchi 	if (varpd_files_valid_dest(dest) == B_FALSE)
95*36589d6bSRobert Mustacchi 		return (ENOTSUP);
96*36589d6bSRobert Mustacchi 
97*36589d6bSRobert Mustacchi 	vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
98*36589d6bSRobert Mustacchi 	if (vaf == NULL)
99*36589d6bSRobert Mustacchi 		return (ENOMEM);
100*36589d6bSRobert Mustacchi 
101*36589d6bSRobert Mustacchi 	bzero(vaf, sizeof (varpd_files_t));
102*36589d6bSRobert Mustacchi 	vaf->vaf_dest = dest;
103*36589d6bSRobert Mustacchi 	vaf->vaf_path = NULL;
104*36589d6bSRobert Mustacchi 	vaf->vaf_nvl = NULL;
105*36589d6bSRobert Mustacchi 	vaf->vaf_hdl = hdl;
106*36589d6bSRobert Mustacchi 	*outp = vaf;
107*36589d6bSRobert Mustacchi 	return (0);
108*36589d6bSRobert Mustacchi }
109*36589d6bSRobert Mustacchi 
110*36589d6bSRobert Mustacchi static int
varpd_files_normalize_nvlist(varpd_files_t * vaf,nvlist_t * nvl)111*36589d6bSRobert Mustacchi varpd_files_normalize_nvlist(varpd_files_t *vaf, nvlist_t *nvl)
112*36589d6bSRobert Mustacchi {
113*36589d6bSRobert Mustacchi 	int ret;
114*36589d6bSRobert Mustacchi 	nvlist_t *out;
115*36589d6bSRobert Mustacchi 	nvpair_t *pair;
116*36589d6bSRobert Mustacchi 
117*36589d6bSRobert Mustacchi 	if ((ret = nvlist_alloc(&out, NV_UNIQUE_NAME, 0)) != 0)
118*36589d6bSRobert Mustacchi 		return (ret);
119*36589d6bSRobert Mustacchi 
120*36589d6bSRobert Mustacchi 	for (pair = nvlist_next_nvpair(nvl, NULL); pair != NULL;
121*36589d6bSRobert Mustacchi 	    pair = nvlist_next_nvpair(nvl, pair)) {
122*36589d6bSRobert Mustacchi 		char *name, fname[ETHERADDRSTRL];
123*36589d6bSRobert Mustacchi 		nvlist_t *data;
124*36589d6bSRobert Mustacchi 		struct ether_addr ether, *e;
125*36589d6bSRobert Mustacchi 		e = &ether;
126*36589d6bSRobert Mustacchi 
127*36589d6bSRobert Mustacchi 		if (nvpair_type(pair) != DATA_TYPE_NVLIST) {
128*36589d6bSRobert Mustacchi 			nvlist_free(out);
129*36589d6bSRobert Mustacchi 			return (EINVAL);
130*36589d6bSRobert Mustacchi 		}
131*36589d6bSRobert Mustacchi 
132*36589d6bSRobert Mustacchi 		name = nvpair_name(pair);
133*36589d6bSRobert Mustacchi 		if ((ret = nvpair_value_nvlist(pair, &data)) != 0) {
134*36589d6bSRobert Mustacchi 			nvlist_free(out);
135*36589d6bSRobert Mustacchi 			return (EINVAL);
136*36589d6bSRobert Mustacchi 		}
137*36589d6bSRobert Mustacchi 
138*36589d6bSRobert Mustacchi 		if (ether_aton_r(name, e) == NULL) {
139*36589d6bSRobert Mustacchi 			nvlist_free(out);
140*36589d6bSRobert Mustacchi 			return (EINVAL);
141*36589d6bSRobert Mustacchi 		}
142*36589d6bSRobert Mustacchi 
143*36589d6bSRobert Mustacchi 		if (ether_ntoa_r(e, fname) == NULL) {
144*36589d6bSRobert Mustacchi 			nvlist_free(out);
145*36589d6bSRobert Mustacchi 			return (ENOMEM);
146*36589d6bSRobert Mustacchi 		}
147*36589d6bSRobert Mustacchi 
148*36589d6bSRobert Mustacchi 		if ((ret = nvlist_add_nvlist(out, fname, data)) != 0) {
149*36589d6bSRobert Mustacchi 			nvlist_free(out);
150*36589d6bSRobert Mustacchi 			return (EINVAL);
151*36589d6bSRobert Mustacchi 		}
152*36589d6bSRobert Mustacchi 	}
153*36589d6bSRobert Mustacchi 
154*36589d6bSRobert Mustacchi 	vaf->vaf_nvl = out;
155*36589d6bSRobert Mustacchi 	return (0);
156*36589d6bSRobert Mustacchi }
157*36589d6bSRobert Mustacchi 
158*36589d6bSRobert Mustacchi static int
varpd_files_start(void * arg)159*36589d6bSRobert Mustacchi varpd_files_start(void *arg)
160*36589d6bSRobert Mustacchi {
161*36589d6bSRobert Mustacchi 	int fd, ret;
162*36589d6bSRobert Mustacchi 	void *maddr;
163*36589d6bSRobert Mustacchi 	struct stat st;
164*36589d6bSRobert Mustacchi 	nvlist_t *nvl;
165*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
166*36589d6bSRobert Mustacchi 
167*36589d6bSRobert Mustacchi 	if (vaf->vaf_path == NULL)
168*36589d6bSRobert Mustacchi 		return (EAGAIN);
169*36589d6bSRobert Mustacchi 
170*36589d6bSRobert Mustacchi 	if ((fd = open(vaf->vaf_path, O_RDONLY)) < 0)
171*36589d6bSRobert Mustacchi 		return (errno);
172*36589d6bSRobert Mustacchi 
173*36589d6bSRobert Mustacchi 	if (fstat(fd, &st) != 0) {
174*36589d6bSRobert Mustacchi 		ret = errno;
175*36589d6bSRobert Mustacchi 		if (close(fd) != 0)
176*36589d6bSRobert Mustacchi 			abort();
177*36589d6bSRobert Mustacchi 		return (ret);
178*36589d6bSRobert Mustacchi 	}
179*36589d6bSRobert Mustacchi 
180*36589d6bSRobert Mustacchi 	maddr = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
181*36589d6bSRobert Mustacchi 	    fd, 0);
182*36589d6bSRobert Mustacchi 	if (maddr == NULL) {
183*36589d6bSRobert Mustacchi 		ret = errno;
184*36589d6bSRobert Mustacchi 		if (close(fd) != 0)
185*36589d6bSRobert Mustacchi 			abort();
186*36589d6bSRobert Mustacchi 		return (ret);
187*36589d6bSRobert Mustacchi 	}
188*36589d6bSRobert Mustacchi 
189*36589d6bSRobert Mustacchi 	ret = nvlist_parse_json(maddr, st.st_size, &nvl,
190*36589d6bSRobert Mustacchi 	    NVJSON_FORCE_INTEGER, NULL);
191*36589d6bSRobert Mustacchi 	if (ret == 0) {
192*36589d6bSRobert Mustacchi 		ret = varpd_files_normalize_nvlist(vaf, nvl);
193*36589d6bSRobert Mustacchi 		nvlist_free(nvl);
194*36589d6bSRobert Mustacchi 	}
195*36589d6bSRobert Mustacchi 	if (munmap(maddr, st.st_size) != 0)
196*36589d6bSRobert Mustacchi 		abort();
197*36589d6bSRobert Mustacchi 	if (close(fd) != 0)
198*36589d6bSRobert Mustacchi 		abort();
199*36589d6bSRobert Mustacchi 
200*36589d6bSRobert Mustacchi 	return (ret);
201*36589d6bSRobert Mustacchi }
202*36589d6bSRobert Mustacchi 
203*36589d6bSRobert Mustacchi static void
varpd_files_stop(void * arg)204*36589d6bSRobert Mustacchi varpd_files_stop(void *arg)
205*36589d6bSRobert Mustacchi {
206*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
207*36589d6bSRobert Mustacchi 
208*36589d6bSRobert Mustacchi 	nvlist_free(vaf->vaf_nvl);
209*36589d6bSRobert Mustacchi 	vaf->vaf_nvl = NULL;
210*36589d6bSRobert Mustacchi }
211*36589d6bSRobert Mustacchi 
212*36589d6bSRobert Mustacchi static void
varpd_files_destroy(void * arg)213*36589d6bSRobert Mustacchi varpd_files_destroy(void *arg)
214*36589d6bSRobert Mustacchi {
215*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
216*36589d6bSRobert Mustacchi 
217*36589d6bSRobert Mustacchi 	assert(vaf->vaf_nvl == NULL);
218*36589d6bSRobert Mustacchi 	if (vaf->vaf_path != NULL) {
219*36589d6bSRobert Mustacchi 		umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
220*36589d6bSRobert Mustacchi 		vaf->vaf_path = NULL;
221*36589d6bSRobert Mustacchi 	}
222*36589d6bSRobert Mustacchi 	umem_free(vaf, sizeof (varpd_files_t));
223*36589d6bSRobert Mustacchi }
224*36589d6bSRobert Mustacchi 
225*36589d6bSRobert Mustacchi static void
varpd_files_lookup(void * arg,varpd_query_handle_t * qh,const overlay_targ_lookup_t * otl,overlay_target_point_t * otp)226*36589d6bSRobert Mustacchi varpd_files_lookup(void *arg, varpd_query_handle_t *qh,
227*36589d6bSRobert Mustacchi     const overlay_targ_lookup_t *otl, overlay_target_point_t *otp)
228*36589d6bSRobert Mustacchi {
229*36589d6bSRobert Mustacchi 	char macstr[ETHERADDRSTRL], *ipstr;
230*36589d6bSRobert Mustacchi 	nvlist_t *nvl;
231*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
232*36589d6bSRobert Mustacchi 	int32_t port;
233*36589d6bSRobert Mustacchi 	static const uint8_t bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
234*36589d6bSRobert Mustacchi 
235*36589d6bSRobert Mustacchi 	/* We don't support a default */
236*36589d6bSRobert Mustacchi 	if (otl == NULL) {
237*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
238*36589d6bSRobert Mustacchi 		return;
239*36589d6bSRobert Mustacchi 	}
240*36589d6bSRobert Mustacchi 
241*36589d6bSRobert Mustacchi 	if (otl->otl_sap == ETHERTYPE_ARP) {
242*36589d6bSRobert Mustacchi 		libvarpd_plugin_proxy_arp(vaf->vaf_hdl, qh, otl);
243*36589d6bSRobert Mustacchi 		return;
244*36589d6bSRobert Mustacchi 	}
245*36589d6bSRobert Mustacchi 
246*36589d6bSRobert Mustacchi 	if (otl->otl_sap == ETHERTYPE_IPV6 &&
247*36589d6bSRobert Mustacchi 	    otl->otl_dstaddr[0] == 0x33 &&
248*36589d6bSRobert Mustacchi 	    otl->otl_dstaddr[1] == 0x33) {
249*36589d6bSRobert Mustacchi 		libvarpd_plugin_proxy_ndp(vaf->vaf_hdl, qh, otl);
250*36589d6bSRobert Mustacchi 		return;
251*36589d6bSRobert Mustacchi 	}
252*36589d6bSRobert Mustacchi 
253*36589d6bSRobert Mustacchi 	if (otl->otl_sap == ETHERTYPE_IP &&
254*36589d6bSRobert Mustacchi 	    bcmp(otl->otl_dstaddr, bcast, ETHERADDRL) == 0) {
255*36589d6bSRobert Mustacchi 		char *mac;
256*36589d6bSRobert Mustacchi 		struct ether_addr a, *addr;
257*36589d6bSRobert Mustacchi 
258*36589d6bSRobert Mustacchi 		addr = &a;
259*36589d6bSRobert Mustacchi 		if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
260*36589d6bSRobert Mustacchi 		    macstr) == NULL) {
261*36589d6bSRobert Mustacchi 			libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
262*36589d6bSRobert Mustacchi 			return;
263*36589d6bSRobert Mustacchi 		}
264*36589d6bSRobert Mustacchi 
265*36589d6bSRobert Mustacchi 		if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
266*36589d6bSRobert Mustacchi 			libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
267*36589d6bSRobert Mustacchi 			return;
268*36589d6bSRobert Mustacchi 		}
269*36589d6bSRobert Mustacchi 
270*36589d6bSRobert Mustacchi 		if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
271*36589d6bSRobert Mustacchi 			libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
272*36589d6bSRobert Mustacchi 			return;
273*36589d6bSRobert Mustacchi 		}
274*36589d6bSRobert Mustacchi 
275*36589d6bSRobert Mustacchi 		if (ether_aton_r(mac, addr) == NULL) {
276*36589d6bSRobert Mustacchi 			libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
277*36589d6bSRobert Mustacchi 			return;
278*36589d6bSRobert Mustacchi 		}
279*36589d6bSRobert Mustacchi 
280*36589d6bSRobert Mustacchi 		libvarpd_plugin_proxy_dhcp(vaf->vaf_hdl, qh, otl);
281*36589d6bSRobert Mustacchi 		return;
282*36589d6bSRobert Mustacchi 	}
283*36589d6bSRobert Mustacchi 
284*36589d6bSRobert Mustacchi 	if (ether_ntoa_r((struct ether_addr *)otl->otl_dstaddr,
285*36589d6bSRobert Mustacchi 	    macstr) == NULL) {
286*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
287*36589d6bSRobert Mustacchi 		return;
288*36589d6bSRobert Mustacchi 	}
289*36589d6bSRobert Mustacchi 
290*36589d6bSRobert Mustacchi 	if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
291*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
292*36589d6bSRobert Mustacchi 		return;
293*36589d6bSRobert Mustacchi 	}
294*36589d6bSRobert Mustacchi 
295*36589d6bSRobert Mustacchi 	if (nvlist_lookup_int32(nvl, "port", &port) != 0) {
296*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
297*36589d6bSRobert Mustacchi 		return;
298*36589d6bSRobert Mustacchi 	}
299*36589d6bSRobert Mustacchi 
300*36589d6bSRobert Mustacchi 	if (port <= 0 || port > UINT16_MAX) {
301*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
302*36589d6bSRobert Mustacchi 		return;
303*36589d6bSRobert Mustacchi 	}
304*36589d6bSRobert Mustacchi 	otp->otp_port = port;
305*36589d6bSRobert Mustacchi 
306*36589d6bSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "ip", &ipstr) != 0) {
307*36589d6bSRobert Mustacchi 		libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
308*36589d6bSRobert Mustacchi 		return;
309*36589d6bSRobert Mustacchi 	}
310*36589d6bSRobert Mustacchi 
311*36589d6bSRobert Mustacchi 	/*
312*36589d6bSRobert Mustacchi 	 * Try to parse it as a v6 address and then if it's not, try to
313*36589d6bSRobert Mustacchi 	 * transform it into a v4 address which we'll then wrap it into a v4
314*36589d6bSRobert Mustacchi 	 * mapped address.
315*36589d6bSRobert Mustacchi 	 */
316*36589d6bSRobert Mustacchi 	if (inet_pton(AF_INET6, ipstr, &otp->otp_ip) != 1) {
317*36589d6bSRobert Mustacchi 		uint32_t v4;
318*36589d6bSRobert Mustacchi 		if (inet_pton(AF_INET, ipstr, &v4) != 1) {
319*36589d6bSRobert Mustacchi 			libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_DROP);
320*36589d6bSRobert Mustacchi 			return;
321*36589d6bSRobert Mustacchi 		}
322*36589d6bSRobert Mustacchi 		IN6_IPADDR_TO_V4MAPPED(v4, &otp->otp_ip);
323*36589d6bSRobert Mustacchi 	}
324*36589d6bSRobert Mustacchi 
325*36589d6bSRobert Mustacchi 	libvarpd_plugin_query_reply(qh, VARPD_LOOKUP_OK);
326*36589d6bSRobert Mustacchi }
327*36589d6bSRobert Mustacchi 
328*36589d6bSRobert Mustacchi /* ARGSUSED */
329*36589d6bSRobert Mustacchi static int
varpd_files_nprops(void * arg,uint_t * nprops)330*36589d6bSRobert Mustacchi varpd_files_nprops(void *arg, uint_t *nprops)
331*36589d6bSRobert Mustacchi {
332*36589d6bSRobert Mustacchi 	*nprops = 1;
333*36589d6bSRobert Mustacchi 	return (0);
334*36589d6bSRobert Mustacchi }
335*36589d6bSRobert Mustacchi 
336*36589d6bSRobert Mustacchi /* ARGSUSED */
337*36589d6bSRobert Mustacchi static int
varpd_files_propinfo(void * arg,uint_t propid,varpd_prop_handle_t * vph)338*36589d6bSRobert Mustacchi varpd_files_propinfo(void *arg, uint_t propid, varpd_prop_handle_t *vph)
339*36589d6bSRobert Mustacchi {
340*36589d6bSRobert Mustacchi 	if (propid != 0)
341*36589d6bSRobert Mustacchi 		return (EINVAL);
342*36589d6bSRobert Mustacchi 
343*36589d6bSRobert Mustacchi 	libvarpd_prop_set_name(vph, varpd_files_props[0]);
344*36589d6bSRobert Mustacchi 	libvarpd_prop_set_prot(vph, OVERLAY_PROP_PERM_RRW);
345*36589d6bSRobert Mustacchi 	libvarpd_prop_set_type(vph, OVERLAY_PROP_T_STRING);
346*36589d6bSRobert Mustacchi 	libvarpd_prop_set_nodefault(vph);
347*36589d6bSRobert Mustacchi 	return (0);
348*36589d6bSRobert Mustacchi }
349*36589d6bSRobert Mustacchi 
350*36589d6bSRobert Mustacchi static int
varpd_files_getprop(void * arg,const char * pname,void * buf,uint32_t * sizep)351*36589d6bSRobert Mustacchi varpd_files_getprop(void *arg, const char *pname, void *buf, uint32_t *sizep)
352*36589d6bSRobert Mustacchi {
353*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
354*36589d6bSRobert Mustacchi 
355*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_files_props[0]) != 0)
356*36589d6bSRobert Mustacchi 		return (EINVAL);
357*36589d6bSRobert Mustacchi 
358*36589d6bSRobert Mustacchi 	if (vaf->vaf_path != NULL) {
359*36589d6bSRobert Mustacchi 		size_t len = strlen(vaf->vaf_path) + 1;
360*36589d6bSRobert Mustacchi 		if (*sizep < len)
361*36589d6bSRobert Mustacchi 			return (EOVERFLOW);
362*36589d6bSRobert Mustacchi 		*sizep = len;
363*36589d6bSRobert Mustacchi 		(void) strlcpy(buf, vaf->vaf_path, *sizep);
364*36589d6bSRobert Mustacchi 
365*36589d6bSRobert Mustacchi 	} else {
366*36589d6bSRobert Mustacchi 		*sizep = 0;
367*36589d6bSRobert Mustacchi 	}
368*36589d6bSRobert Mustacchi 
369*36589d6bSRobert Mustacchi 	return (0);
370*36589d6bSRobert Mustacchi }
371*36589d6bSRobert Mustacchi 
372*36589d6bSRobert Mustacchi static int
varpd_files_setprop(void * arg,const char * pname,const void * buf,const uint32_t size)373*36589d6bSRobert Mustacchi varpd_files_setprop(void *arg, const char *pname, const void *buf,
374*36589d6bSRobert Mustacchi     const uint32_t size)
375*36589d6bSRobert Mustacchi {
376*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
377*36589d6bSRobert Mustacchi 
378*36589d6bSRobert Mustacchi 	if (strcmp(pname, varpd_files_props[0]) != 0)
379*36589d6bSRobert Mustacchi 		return (EINVAL);
380*36589d6bSRobert Mustacchi 
381*36589d6bSRobert Mustacchi 	if (vaf->vaf_path != NULL)
382*36589d6bSRobert Mustacchi 		umem_free(vaf->vaf_path, strlen(vaf->vaf_path) + 1);
383*36589d6bSRobert Mustacchi 
384*36589d6bSRobert Mustacchi 	vaf->vaf_path = umem_alloc(size, UMEM_DEFAULT);
385*36589d6bSRobert Mustacchi 	if (vaf->vaf_path == NULL)
386*36589d6bSRobert Mustacchi 		return (ENOMEM);
387*36589d6bSRobert Mustacchi 	(void) strlcpy(vaf->vaf_path, buf, size);
388*36589d6bSRobert Mustacchi 	return (0);
389*36589d6bSRobert Mustacchi }
390*36589d6bSRobert Mustacchi 
391*36589d6bSRobert Mustacchi static int
varpd_files_save(void * arg,nvlist_t * nvp)392*36589d6bSRobert Mustacchi varpd_files_save(void *arg, nvlist_t *nvp)
393*36589d6bSRobert Mustacchi {
394*36589d6bSRobert Mustacchi 	int ret;
395*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
396*36589d6bSRobert Mustacchi 
397*36589d6bSRobert Mustacchi 	if (vaf->vaf_path == NULL)
398*36589d6bSRobert Mustacchi 		return (0);
399*36589d6bSRobert Mustacchi 
400*36589d6bSRobert Mustacchi 	if ((ret = nvlist_add_string(nvp, varpd_files_props[0],
401*36589d6bSRobert Mustacchi 	    vaf->vaf_path)) != 0)
402*36589d6bSRobert Mustacchi 		return (ret);
403*36589d6bSRobert Mustacchi 
404*36589d6bSRobert Mustacchi 	if ((ret = nvlist_add_uint64(nvp, "files/vaf_nmisses",
405*36589d6bSRobert Mustacchi 	    vaf->vaf_nmisses)) != 0)
406*36589d6bSRobert Mustacchi 		return (ret);
407*36589d6bSRobert Mustacchi 
408*36589d6bSRobert Mustacchi 	if ((ret = nvlist_add_uint64(nvp, "files/vaf_narp",
409*36589d6bSRobert Mustacchi 	    vaf->vaf_narp)) != 0)
410*36589d6bSRobert Mustacchi 		return (ret);
411*36589d6bSRobert Mustacchi 	return (0);
412*36589d6bSRobert Mustacchi }
413*36589d6bSRobert Mustacchi 
414*36589d6bSRobert Mustacchi static int
varpd_files_restore(nvlist_t * nvp,varpd_provider_handle_t * hdl,overlay_plugin_dest_t dest,void ** outp)415*36589d6bSRobert Mustacchi varpd_files_restore(nvlist_t *nvp, varpd_provider_handle_t *hdl,
416*36589d6bSRobert Mustacchi     overlay_plugin_dest_t dest, void **outp)
417*36589d6bSRobert Mustacchi {
418*36589d6bSRobert Mustacchi 	varpd_files_t *vaf;
419*36589d6bSRobert Mustacchi 	char *str;
420*36589d6bSRobert Mustacchi 	int ret;
421*36589d6bSRobert Mustacchi 	uint64_t nmisses, narp;
422*36589d6bSRobert Mustacchi 
423*36589d6bSRobert Mustacchi 	if (varpd_files_valid_dest(dest) == B_FALSE)
424*36589d6bSRobert Mustacchi 		return (EINVAL);
425*36589d6bSRobert Mustacchi 
426*36589d6bSRobert Mustacchi 	ret = nvlist_lookup_string(nvp, varpd_files_props[0], &str);
427*36589d6bSRobert Mustacchi 	if (ret != 0 && ret != ENOENT)
428*36589d6bSRobert Mustacchi 		return (ret);
429*36589d6bSRobert Mustacchi 	else if (ret == ENOENT)
430*36589d6bSRobert Mustacchi 		str = NULL;
431*36589d6bSRobert Mustacchi 
432*36589d6bSRobert Mustacchi 	if (nvlist_lookup_uint64(nvp, "files/vaf_nmisses", &nmisses) != 0)
433*36589d6bSRobert Mustacchi 		return (EINVAL);
434*36589d6bSRobert Mustacchi 	if (nvlist_lookup_uint64(nvp, "files/vaf_narp", &narp) != 0)
435*36589d6bSRobert Mustacchi 		return (EINVAL);
436*36589d6bSRobert Mustacchi 
437*36589d6bSRobert Mustacchi 	vaf = umem_alloc(sizeof (varpd_files_t), UMEM_DEFAULT);
438*36589d6bSRobert Mustacchi 	if (vaf == NULL)
439*36589d6bSRobert Mustacchi 		return (ENOMEM);
440*36589d6bSRobert Mustacchi 
441*36589d6bSRobert Mustacchi 	bzero(vaf, sizeof (varpd_files_t));
442*36589d6bSRobert Mustacchi 	vaf->vaf_dest = dest;
443*36589d6bSRobert Mustacchi 	if (str != NULL) {
444*36589d6bSRobert Mustacchi 		size_t len = strlen(str) + 1;
445*36589d6bSRobert Mustacchi 		vaf->vaf_path = umem_alloc(len, UMEM_DEFAULT);
446*36589d6bSRobert Mustacchi 		if (vaf->vaf_path == NULL) {
447*36589d6bSRobert Mustacchi 			umem_free(vaf, sizeof (varpd_files_t));
448*36589d6bSRobert Mustacchi 			return (ENOMEM);
449*36589d6bSRobert Mustacchi 		}
450*36589d6bSRobert Mustacchi 		(void) strlcpy(vaf->vaf_path, str, len);
451*36589d6bSRobert Mustacchi 	}
452*36589d6bSRobert Mustacchi 
453*36589d6bSRobert Mustacchi 	vaf->vaf_hdl = hdl;
454*36589d6bSRobert Mustacchi 	*outp = vaf;
455*36589d6bSRobert Mustacchi 	return (0);
456*36589d6bSRobert Mustacchi }
457*36589d6bSRobert Mustacchi 
458*36589d6bSRobert Mustacchi static void
varpd_files_proxy_arp(void * arg,varpd_arp_handle_t * vah,int kind,const struct sockaddr * sock,uint8_t * out)459*36589d6bSRobert Mustacchi varpd_files_proxy_arp(void *arg, varpd_arp_handle_t *vah, int kind,
460*36589d6bSRobert Mustacchi     const struct sockaddr *sock, uint8_t *out)
461*36589d6bSRobert Mustacchi {
462*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
463*36589d6bSRobert Mustacchi 	const struct sockaddr_in *ip;
464*36589d6bSRobert Mustacchi 	const struct sockaddr_in6 *ip6;
465*36589d6bSRobert Mustacchi 	nvpair_t *pair;
466*36589d6bSRobert Mustacchi 
467*36589d6bSRobert Mustacchi 	if (kind != VARPD_QTYPE_ETHERNET) {
468*36589d6bSRobert Mustacchi 		libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
469*36589d6bSRobert Mustacchi 		return;
470*36589d6bSRobert Mustacchi 	}
471*36589d6bSRobert Mustacchi 
472*36589d6bSRobert Mustacchi 	if (sock->sa_family != AF_INET && sock->sa_family != AF_INET6) {
473*36589d6bSRobert Mustacchi 		libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
474*36589d6bSRobert Mustacchi 		return;
475*36589d6bSRobert Mustacchi 	}
476*36589d6bSRobert Mustacchi 
477*36589d6bSRobert Mustacchi 	ip = (const struct sockaddr_in *)sock;
478*36589d6bSRobert Mustacchi 	ip6 = (const struct sockaddr_in6 *)sock;
479*36589d6bSRobert Mustacchi 	for (pair = nvlist_next_nvpair(vaf->vaf_nvl, NULL); pair != NULL;
480*36589d6bSRobert Mustacchi 	    pair = nvlist_next_nvpair(vaf->vaf_nvl, pair)) {
481*36589d6bSRobert Mustacchi 		char *mac, *ipstr;
482*36589d6bSRobert Mustacchi 		nvlist_t *data;
483*36589d6bSRobert Mustacchi 		struct in_addr ia;
484*36589d6bSRobert Mustacchi 		struct in6_addr ia6;
485*36589d6bSRobert Mustacchi 		struct ether_addr ether, *e;
486*36589d6bSRobert Mustacchi 		e = &ether;
487*36589d6bSRobert Mustacchi 
488*36589d6bSRobert Mustacchi 		if (nvpair_type(pair) != DATA_TYPE_NVLIST)
489*36589d6bSRobert Mustacchi 			continue;
490*36589d6bSRobert Mustacchi 
491*36589d6bSRobert Mustacchi 		mac = nvpair_name(pair);
492*36589d6bSRobert Mustacchi 		if (nvpair_value_nvlist(pair, &data) != 0)
493*36589d6bSRobert Mustacchi 			continue;
494*36589d6bSRobert Mustacchi 
495*36589d6bSRobert Mustacchi 
496*36589d6bSRobert Mustacchi 		if (sock->sa_family == AF_INET) {
497*36589d6bSRobert Mustacchi 			if (nvlist_lookup_string(data, "arp", &ipstr) != 0)
498*36589d6bSRobert Mustacchi 				continue;
499*36589d6bSRobert Mustacchi 
500*36589d6bSRobert Mustacchi 			if (inet_pton(AF_INET, ipstr, &ia) != 1)
501*36589d6bSRobert Mustacchi 				continue;
502*36589d6bSRobert Mustacchi 
503*36589d6bSRobert Mustacchi 			if (bcmp(&ia, &ip->sin_addr,
504*36589d6bSRobert Mustacchi 			    sizeof (struct in_addr)) != 0)
505*36589d6bSRobert Mustacchi 				continue;
506*36589d6bSRobert Mustacchi 		} else {
507*36589d6bSRobert Mustacchi 			if (nvlist_lookup_string(data, "ndp", &ipstr) != 0)
508*36589d6bSRobert Mustacchi 				continue;
509*36589d6bSRobert Mustacchi 
510*36589d6bSRobert Mustacchi 			if (inet_pton(AF_INET6, ipstr, &ia6) != 1)
511*36589d6bSRobert Mustacchi 				continue;
512*36589d6bSRobert Mustacchi 
513*36589d6bSRobert Mustacchi 			if (bcmp(&ia6, &ip6->sin6_addr,
514*36589d6bSRobert Mustacchi 			    sizeof (struct in6_addr)) != 0)
515*36589d6bSRobert Mustacchi 				continue;
516*36589d6bSRobert Mustacchi 		}
517*36589d6bSRobert Mustacchi 
518*36589d6bSRobert Mustacchi 		if (ether_aton_r(mac, e) == NULL) {
519*36589d6bSRobert Mustacchi 			libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
520*36589d6bSRobert Mustacchi 			return;
521*36589d6bSRobert Mustacchi 		}
522*36589d6bSRobert Mustacchi 
523*36589d6bSRobert Mustacchi 		bcopy(e, out, ETHERADDRL);
524*36589d6bSRobert Mustacchi 		libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_OK);
525*36589d6bSRobert Mustacchi 		return;
526*36589d6bSRobert Mustacchi 	}
527*36589d6bSRobert Mustacchi 
528*36589d6bSRobert Mustacchi 	libvarpd_plugin_arp_reply(vah, VARPD_LOOKUP_DROP);
529*36589d6bSRobert Mustacchi }
530*36589d6bSRobert Mustacchi 
531*36589d6bSRobert Mustacchi static void
varpd_files_proxy_dhcp(void * arg,varpd_dhcp_handle_t * vdh,int type,const overlay_targ_lookup_t * otl,uint8_t * out)532*36589d6bSRobert Mustacchi varpd_files_proxy_dhcp(void *arg, varpd_dhcp_handle_t *vdh, int type,
533*36589d6bSRobert Mustacchi     const overlay_targ_lookup_t *otl, uint8_t *out)
534*36589d6bSRobert Mustacchi {
535*36589d6bSRobert Mustacchi 	varpd_files_t *vaf = arg;
536*36589d6bSRobert Mustacchi 	nvlist_t *nvl;
537*36589d6bSRobert Mustacchi 	char macstr[ETHERADDRSTRL], *mac;
538*36589d6bSRobert Mustacchi 	struct ether_addr a, *addr;
539*36589d6bSRobert Mustacchi 
540*36589d6bSRobert Mustacchi 	addr = &a;
541*36589d6bSRobert Mustacchi 	if (type != VARPD_QTYPE_ETHERNET) {
542*36589d6bSRobert Mustacchi 		libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
543*36589d6bSRobert Mustacchi 		return;
544*36589d6bSRobert Mustacchi 	}
545*36589d6bSRobert Mustacchi 
546*36589d6bSRobert Mustacchi 	if (ether_ntoa_r((struct ether_addr *)otl->otl_srcaddr,
547*36589d6bSRobert Mustacchi 	    macstr) == NULL) {
548*36589d6bSRobert Mustacchi 		libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
549*36589d6bSRobert Mustacchi 		return;
550*36589d6bSRobert Mustacchi 	}
551*36589d6bSRobert Mustacchi 
552*36589d6bSRobert Mustacchi 	if (nvlist_lookup_nvlist(vaf->vaf_nvl, macstr, &nvl) != 0) {
553*36589d6bSRobert Mustacchi 		libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
554*36589d6bSRobert Mustacchi 		return;
555*36589d6bSRobert Mustacchi 	}
556*36589d6bSRobert Mustacchi 
557*36589d6bSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "dhcp-proxy", &mac) != 0) {
558*36589d6bSRobert Mustacchi 		libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
559*36589d6bSRobert Mustacchi 		return;
560*36589d6bSRobert Mustacchi 	}
561*36589d6bSRobert Mustacchi 
562*36589d6bSRobert Mustacchi 	if (ether_aton_r(mac, addr) == NULL) {
563*36589d6bSRobert Mustacchi 		libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_DROP);
564*36589d6bSRobert Mustacchi 		return;
565*36589d6bSRobert Mustacchi 	}
566*36589d6bSRobert Mustacchi 
567*36589d6bSRobert Mustacchi 	bcopy(addr, out, ETHERADDRL);
568*36589d6bSRobert Mustacchi 	libvarpd_plugin_dhcp_reply(vdh, VARPD_LOOKUP_OK);
569*36589d6bSRobert Mustacchi }
570*36589d6bSRobert Mustacchi 
571*36589d6bSRobert Mustacchi static const varpd_plugin_ops_t varpd_files_ops = {
572*36589d6bSRobert Mustacchi 	0,
573*36589d6bSRobert Mustacchi 	varpd_files_create,
574*36589d6bSRobert Mustacchi 	varpd_files_start,
575*36589d6bSRobert Mustacchi 	varpd_files_stop,
576*36589d6bSRobert Mustacchi 	varpd_files_destroy,
577*36589d6bSRobert Mustacchi 	NULL,
578*36589d6bSRobert Mustacchi 	varpd_files_lookup,
579*36589d6bSRobert Mustacchi 	varpd_files_nprops,
580*36589d6bSRobert Mustacchi 	varpd_files_propinfo,
581*36589d6bSRobert Mustacchi 	varpd_files_getprop,
582*36589d6bSRobert Mustacchi 	varpd_files_setprop,
583*36589d6bSRobert Mustacchi 	varpd_files_save,
584*36589d6bSRobert Mustacchi 	varpd_files_restore,
585*36589d6bSRobert Mustacchi 	varpd_files_proxy_arp,
586*36589d6bSRobert Mustacchi 	varpd_files_proxy_dhcp
587*36589d6bSRobert Mustacchi };
588*36589d6bSRobert Mustacchi 
589*36589d6bSRobert Mustacchi #pragma init(varpd_files_init)
590*36589d6bSRobert Mustacchi static void
varpd_files_init(void)591*36589d6bSRobert Mustacchi varpd_files_init(void)
592*36589d6bSRobert Mustacchi {
593*36589d6bSRobert Mustacchi 	int err;
594*36589d6bSRobert Mustacchi 	varpd_plugin_register_t *vpr;
595*36589d6bSRobert Mustacchi 
596*36589d6bSRobert Mustacchi 	vpr = libvarpd_plugin_alloc(VARPD_CURRENT_VERSION, &err);
597*36589d6bSRobert Mustacchi 	if (vpr == NULL)
598*36589d6bSRobert Mustacchi 		return;
599*36589d6bSRobert Mustacchi 
600*36589d6bSRobert Mustacchi 	vpr->vpr_mode = OVERLAY_TARGET_DYNAMIC;
601*36589d6bSRobert Mustacchi 	vpr->vpr_name = "files";
602*36589d6bSRobert Mustacchi 	vpr->vpr_ops = &varpd_files_ops;
603*36589d6bSRobert Mustacchi 	(void) libvarpd_plugin_register(vpr);
604*36589d6bSRobert Mustacchi 	libvarpd_plugin_free(vpr);
605*36589d6bSRobert Mustacchi }
606