2 * Copyright (c) 2015-2019 Alexandre Fenyo <alex@fenyo.net> - http://www.fenyo.net
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/kernel.h>
30 #include <sys/malloc.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <sys/module.h>
34 #include <sys/sysctl.h>
37 #include <net/if_var.h>
38 #include <net/ethernet.h>
39 #include <netinet/in.h>
43 #include <netinet6/ip6_var.h>
51 static int hook_added = false;
55 static pfil_hook_t pfh_hook;
57 static void register_hook(void) {
58 struct pfil_hook_args pha;
59 struct pfil_link_args pla;
61 if (hook_added) return;
63 pha.pa_version = PFIL_VERSION;
64 pha.pa_type = PFIL_TYPE_IP6;
65 pha.pa_flags = PFIL_IN;
66 pha.pa_modname = "ndproxy";
67 pha.pa_ruleset = NULL;
68 pha.pa_rulname = "default-in6";
69 pha.pa_mbuf_chk = packet;
70 pha.pa_mem_chk = NULL;
71 pfh_hook = pfil_add_hook(&pha);
73 pla.pa_version = PFIL_VERSION;
74 pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR;
75 pla.pa_hook = pfh_hook;
76 pla.pa_head = V_inet6_pfil_head;
82 static void unregister_hook(void) {
83 if (!hook_added) return;
84 pfil_remove_hook(pfh_hook);
89 static struct pfil_head *pfh_inet6 = NULL;
91 // when module is loaded from /boot/loader.conf, pfh_inet6 is not already initialized,
92 // so postpone registration
93 static void register_hook() {
94 if (hook_added) return;
96 if (pfh_inet6 == NULL) {
97 if ((pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6)) == NULL) {
99 uprintf("NDPROXY WARNING: pfil_head_get returned null\n");
100 printf("NDPROXY WARNING: pfil_head_get returned null\n");
106 const int ret = pfil_add_hook(packet, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
109 uprintf("NDPROXY WARNING: can not add hook (err=%d)\n", ret);
110 printf("NDPROXY WARNING: can not add hook (err=%d)\n", ret);
117 static void unregister_hook() {
120 if (hook_added && (ret = pfil_remove_hook(packet, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6))) {
122 uprintf("NDPROXY WARNING: can not remove hook (err=%d)\n", ret);
123 printf("NDPROXY WARNING: can not remove hook (err=%d)\n", ret);
130 // called when the module is loaded or unloaded
131 static int event_handler(struct module *module, const int event, void *arg) {
136 uprintf("NDPROXY loaded\n");
137 printf("NDPROXY loaded\n");
146 uprintf("NDPROXY unloaded\n");
147 printf("NDPROXY unloaded\n");
160 // declare module data
162 static moduledata_t ndproxy_conf = {
163 "ndproxy", // module name
164 event_handler, // event handler
167 DECLARE_MODULE(ndproxy, ndproxy_conf, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
169 // declare sysctl interface used to configure the behaviour of the module
171 SYSCTL_DECL(_net_inet6);
173 #define GENERIC_CB_STRING \
174 if (arg1 == NULL) { \
175 printf("NDPROXY ERROR: conf arg is null\n"); \
179 if (strlen((char *) arg1) > sizeof conf_str - 1) return E2BIG; \
181 strncpy(conf_str, (char *) arg1, sizeof conf_str); \
182 conf_str[(sizeof conf_str) - 1] = '\0'; \
184 ret = SYSCTL_OUT(req, conf_str, sizeof conf_str); \
185 if (ret || !req->newptr) return ret; \
187 /* the caller asks to set a new value */ \
189 if ((req->newlen - req->newidx) >= arg2) return EINVAL; \
190 arg2 = (req->newlen - req->newidx); \
191 ret = SYSCTL_IN(req, arg1, arg2); \
192 ((char *)arg1)[arg2] = '\0'; \
195 ////////////////////////////////////////////////////////////////////////////////
196 // net.inet6.ndproxyconf_uplink_interface
198 // declare the sysctl node named net.inet6.ndproxyconf_uplink_interface
199 SYSCTL_STRING(_net_inet6, OID_AUTO, ndproxyconf_uplink_interface, CTLFLAG_RW, ndproxy_conf_str_uplink_interface, sizeof ndproxy_conf_str_uplink_interface, "uplink interface name");
201 ////////////////////////////////////////////////////////////////////////////////
202 // net.inet6.ndproxyconf_{up,down}link_mac_address
204 // storage string for the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
206 // reserved for a future use
207 static char ndproxy_conf_str_uplink_mac_address[MACMAXSIZE + 1] = "";
209 static char ndproxy_conf_str_downlink_mac_address[MACMAXSIZE + 1] = "";
211 // get or update the value of the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
212 static int cb_string_mac_addr(SYSCTL_HANDLER_ARGS, char xconf_str[MACMAXSIZE + 1], struct ether_addr *xconf_val, bool *xconf_isset) {
213 char conf_str[MACMAXSIZE + 1];
214 struct ether_addr _ndproxy_conf_link_mac_address;
221 if (!strlen(xconf_str)) {
222 *xconf_isset = false;
226 char *curp = xconf_str;
228 strcpy(tmpstr, curp);
229 ret = parse_mac(tmpstr, &_ndproxy_conf_link_mac_address);
233 printf("NDPROXY INFO: parsed address: [");
234 printf_macaddr_network_format(&_ndproxy_conf_link_mac_address);
238 strncpy(xconf_str, conf_str, sizeof conf_str);
239 xconf_str[sizeof conf_str - 1] = 0;
243 *xconf_val = _ndproxy_conf_link_mac_address;
248 // get or update the value of the sysctl node named net.inet6.ndproxyconf_downlink_mac_address
249 static int cb_string_downlink_mac_addr(SYSCTL_HANDLER_ARGS) {
250 return cb_string_mac_addr(oidp, arg1, arg2, req, ndproxy_conf_str_downlink_mac_address, &ndproxy_conf_downlink_mac_address, &ndproxy_conf_downlink_mac_address_isset);
254 // reserved for a future use
255 // get or update the value of the sysctl node named net.inet6.ndproxyconf_uplink_mac_address
256 static int cb_string_uplink_mac_addr(SYSCTL_HANDLER_ARGS) {
257 return cb_string_mac_addr(oidp, arg1, arg2, req, ndproxy_conf_str_uplink_mac_address, &ndproxy_conf_uplink_mac_address, &ndproxy_conf_uplink_mac_address_isset);
261 // declare the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
262 // format: NN:NN:NN:NN:NN:NN
263 SYSCTL_OID(_net_inet6, OID_AUTO, ndproxyconf_downlink_mac_address, CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW, ndproxy_conf_str_downlink_mac_address, sizeof ndproxy_conf_str_downlink_mac_address, cb_string_downlink_mac_addr, "S", "downlink mac adress");
264 // the uplink mac address is reserved for a future use when it could be used to filter uplink packets instead of using the uplink ipv6 addresses
265 // SYSCTL_OID(_net_inet6, OID_AUTO, ndproxyconf_uplink_mac_address, CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW, ndproxy_conf_str_uplink_mac_address, sizeof ndproxy_conf_str_uplink_mac_address, cb_string_uplink_mac_addr, "S", "uplink mac adress");
267 ////////////////////////////////////////////////////////////////////////////////
268 // net.inet6.ndproxyconf_exception_ipv6_addresses && net.inet6.ndproxyconf_uplink_ipv6_addresses
270 // storage string for the sysctl node named net.inet6.ndproxyconf_exception_ipv6_addresses
271 static char ndproxy_conf_str_exception_ipv6_addresses[CONF_NEXCEPTIONS_SIZE] = "";
273 // storage string for the sysctl node named net.inet6.ndproxyconf_uplink_ipv6_addresses
274 static char ndproxy_conf_str_uplink_ipv6_addresses[CONF_NUPLINK_SIZE] = "";
276 // get or update the value of the sysctl node named net.inet6.ndproxyconf_{uplink,exception}_ipv6_addresses
277 static int cb_string_list(SYSCTL_HANDLER_ARGS, int nentries_size, int nentries_max, char *ndproxy_conf_str_ipv6_addresses, struct in6_addr *ndproxy_conf_ipv6_addresses, int *ndproxy_conf_ipv6_naddresses) {
278 char conf_str[nentries_size];
279 struct in6_addr _ndproxy_conf_ipv6_addresses[nentries_max];
280 int _ndproxy_conf_ipv6_naddresses = 0;
287 if (!strlen(ndproxy_conf_str_ipv6_addresses)) {
288 *ndproxy_conf_ipv6_naddresses = 0;
292 char *curp = ndproxy_conf_str_ipv6_addresses;
295 char tmpstr[nentries_size];
296 delim = strchr(curp, ';');
298 strncpy(tmpstr, curp, delim - curp);
299 tmpstr[delim - curp] = 0;
300 } else strcpy(tmpstr, curp);
301 ret = parse_ipv6(tmpstr, _ndproxy_conf_ipv6_addresses + _ndproxy_conf_ipv6_naddresses);
304 printf("NDPROXY INFO: parsed address: [");
305 printf_ip6addr_network_format(_ndproxy_conf_ipv6_addresses + _ndproxy_conf_ipv6_naddresses);
309 strncpy(ndproxy_conf_str_ipv6_addresses, conf_str, nentries_size);
310 ndproxy_conf_str_ipv6_addresses[nentries_size - 1] = 0;
313 _ndproxy_conf_ipv6_naddresses++;
314 } while (delim != NULL && (curp = ++delim) < (char *) (ndproxy_conf_str_ipv6_addresses + nentries_size) && _ndproxy_conf_ipv6_naddresses < nentries_max);
317 strncpy(ndproxy_conf_str_ipv6_addresses, conf_str, nentries_size);
318 ndproxy_conf_str_ipv6_addresses[nentries_size - 1] = 0;
322 bcopy(_ndproxy_conf_ipv6_addresses, ndproxy_conf_ipv6_addresses, _ndproxy_conf_ipv6_naddresses * sizeof(struct in6_addr));
323 *ndproxy_conf_ipv6_naddresses = _ndproxy_conf_ipv6_naddresses;
328 static int cb_string_list_exception(SYSCTL_HANDLER_ARGS) {
329 return cb_string_list(oidp, arg1, arg2, req, CONF_NEXCEPTIONS_SIZE, CONF_NEXCEPTIONS_MAX, ndproxy_conf_str_exception_ipv6_addresses, ndproxy_conf_exception_ipv6_addresses, &ndproxy_conf_exception_ipv6_naddresses);
332 static int cb_string_list_uplink(SYSCTL_HANDLER_ARGS) {
333 return cb_string_list(oidp, arg1, arg2, req, CONF_NUPLINK_SIZE, CONF_NUPLINK_MAX, ndproxy_conf_str_uplink_ipv6_addresses, ndproxy_conf_uplink_ipv6_addresses, &ndproxy_conf_uplink_ipv6_naddresses);
336 // declare the sysctl node named net.inet6.ndproxyconf_exception_ipv6_addresses
337 // format: NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:{NNNN:NNNN,XXX.XXX.XXX.XXX};...;...
338 SYSCTL_OID(_net_inet6, OID_AUTO, ndproxyconf_exception_ipv6_addresses, CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW, ndproxy_conf_str_exception_ipv6_addresses, sizeof ndproxy_conf_str_exception_ipv6_addresses, cb_string_list_exception, "S", "do not proxy this list of IPv6 adresses");
340 // declare the sysctl node named net.inet6.ndproxyconf_uplink_ipv6_addresses
341 // format: NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:{NNNN:NNNN,XXX.XXX.XXX.XXX};...;...
342 SYSCTL_OID(_net_inet6, OID_AUTO, ndproxyconf_uplink_ipv6_addresses, CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_RW, ndproxy_conf_str_uplink_ipv6_addresses, sizeof ndproxy_conf_str_uplink_ipv6_addresses, cb_string_list_uplink, "S", "uplink router IPv6 adresses");
344 ////////////////////////////////////////////////////////////////////////////////
345 // net.inet6.ndproxycount
347 static int cb_count(SYSCTL_HANDLER_ARGS) {
351 printf("NDPROXY INFO: count\n");
354 return sysctl_handle_int(oidp, arg1, arg2, req);
357 SYSCTL_OID(_net_inet6, OID_AUTO, ndproxycount, CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &ndproxy_conf_count, 0, cb_count, "I", "fire an event");