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 = ðer;
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 = ðer;
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