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";
70 pfh_hook = pfil_add_hook(&pha);
72 pla.pa_version = PFIL_VERSION;
73 pla.pa_flags = PFIL_IN | PFIL_HEADPTR | PFIL_HOOKPTR;
74 pla.pa_hook = pfh_hook;
75 pla.pa_head = V_inet6_pfil_head;
81 static void unregister_hook(void) {
82 if (!hook_added) return;
83 pfil_remove_hook(pfh_hook);
88 static struct pfil_head *pfh_inet6 = NULL;
90 // when module is loaded from /boot/loader.conf, pfh_inet6 is not already initialized,
91 // so postpone registration
92 static void register_hook() {
93 if (hook_added) return;
95 if (pfh_inet6 == NULL) {
96 if ((pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6)) == NULL) {
98 uprintf("NDPROXY WARNING: pfil_head_get returned null\n");
99 printf("NDPROXY WARNING: pfil_head_get returned null\n");
105 const int ret = pfil_add_hook(packet, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
108 uprintf("NDPROXY WARNING: can not add hook (err=%d)\n", ret);
109 printf("NDPROXY WARNING: can not add hook (err=%d)\n", ret);
116 static void unregister_hook() {
119 if (hook_added && (ret = pfil_remove_hook(packet, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6))) {
121 uprintf("NDPROXY WARNING: can not remove hook (err=%d)\n", ret);
122 printf("NDPROXY WARNING: can not remove hook (err=%d)\n", ret);
129 // called when the module is loaded or unloaded
130 static int event_handler(struct module *module, const int event, void *arg) {
135 uprintf("NDPROXY loaded\n");
136 printf("NDPROXY loaded\n");
145 uprintf("NDPROXY unloaded\n");
146 printf("NDPROXY unloaded\n");
159 // declare module data
161 static moduledata_t ndproxy_conf = {
162 "ndproxy", // module name
163 event_handler, // event handler
166 DECLARE_MODULE(ndproxy, ndproxy_conf, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
168 // declare sysctl interface used to configure the behaviour of the module
170 SYSCTL_DECL(_net_inet6);
172 #define GENERIC_CB_STRING \
173 if (arg1 == NULL) { \
174 printf("NDPROXY ERROR: conf arg is null\n"); \
178 if (strlen((char *) arg1) > sizeof conf_str - 1) return E2BIG; \
180 strncpy(conf_str, (char *) arg1, sizeof conf_str); \
181 conf_str[(sizeof conf_str) - 1] = '\0'; \
183 ret = SYSCTL_OUT(req, conf_str, sizeof conf_str); \
184 if (ret || !req->newptr) return ret; \
186 /* the caller asks to set a new value */ \
188 if ((req->newlen - req->newidx) >= arg2) return EINVAL; \
189 arg2 = (req->newlen - req->newidx); \
190 ret = SYSCTL_IN(req, arg1, arg2); \
191 ((char *)arg1)[arg2] = '\0'; \
194 ////////////////////////////////////////////////////////////////////////////////
195 // net.inet6.ndproxyconf_uplink_interface
197 // declare the sysctl node named net.inet6.ndproxyconf_uplink_interface
198 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");
200 ////////////////////////////////////////////////////////////////////////////////
201 // net.inet6.ndproxyconf_{up,down}link_mac_address
203 // storage string for the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
205 // reserved for a future use
206 static char ndproxy_conf_str_uplink_mac_address[MACMAXSIZE + 1] = "";
208 static char ndproxy_conf_str_downlink_mac_address[MACMAXSIZE + 1] = "";
210 // get or update the value of the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
211 static int cb_string_mac_addr(SYSCTL_HANDLER_ARGS, char xconf_str[MACMAXSIZE + 1], struct ether_addr *xconf_val, bool *xconf_isset) {
212 char conf_str[MACMAXSIZE + 1];
213 struct ether_addr _ndproxy_conf_link_mac_address;
220 if (!strlen(xconf_str)) {
221 *xconf_isset = false;
225 char *curp = xconf_str;
227 strcpy(tmpstr, curp);
228 ret = parse_mac(tmpstr, &_ndproxy_conf_link_mac_address);
232 printf("NDPROXY INFO: parsed address: [");
233 printf_macaddr_network_format(&_ndproxy_conf_link_mac_address);
237 strncpy(xconf_str, conf_str, sizeof conf_str);
238 xconf_str[sizeof conf_str - 1] = 0;
242 *xconf_val = _ndproxy_conf_link_mac_address;
247 // get or update the value of the sysctl node named net.inet6.ndproxyconf_downlink_mac_address
248 static int cb_string_downlink_mac_addr(SYSCTL_HANDLER_ARGS) {
249 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);
253 // reserved for a future use
254 // get or update the value of the sysctl node named net.inet6.ndproxyconf_uplink_mac_address
255 static int cb_string_uplink_mac_addr(SYSCTL_HANDLER_ARGS) {
256 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);
260 // declare the sysctl node named net.inet6.ndproxyconf_{up,down}link_mac_address
261 // format: NN:NN:NN:NN:NN:NN
262 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");
263 // 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
264 // 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");
266 ////////////////////////////////////////////////////////////////////////////////
267 // net.inet6.ndproxyconf_exception_ipv6_addresses && net.inet6.ndproxyconf_uplink_ipv6_addresses
269 // storage string for the sysctl node named net.inet6.ndproxyconf_exception_ipv6_addresses
270 static char ndproxy_conf_str_exception_ipv6_addresses[CONF_NEXCEPTIONS_SIZE] = "";
272 // storage string for the sysctl node named net.inet6.ndproxyconf_uplink_ipv6_addresses
273 static char ndproxy_conf_str_uplink_ipv6_addresses[CONF_NUPLINK_SIZE] = "";
275 // get or update the value of the sysctl node named net.inet6.ndproxyconf_{uplink,exception}_ipv6_addresses
276 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) {
277 char conf_str[nentries_size];
278 struct in6_addr _ndproxy_conf_ipv6_addresses[nentries_max];
279 int _ndproxy_conf_ipv6_naddresses = 0;
286 if (!strlen(ndproxy_conf_str_ipv6_addresses)) {
287 *ndproxy_conf_ipv6_naddresses = 0;
291 char *curp = ndproxy_conf_str_ipv6_addresses;
294 char tmpstr[nentries_size];
295 delim = strchr(curp, ';');
297 strncpy(tmpstr, curp, delim - curp);
298 tmpstr[delim - curp] = 0;
299 } else strcpy(tmpstr, curp);
300 ret = parse_ipv6(tmpstr, _ndproxy_conf_ipv6_addresses + _ndproxy_conf_ipv6_naddresses);
303 printf("NDPROXY INFO: parsed address: [");
304 printf_ip6addr_network_format(_ndproxy_conf_ipv6_addresses + _ndproxy_conf_ipv6_naddresses);
308 strncpy(ndproxy_conf_str_ipv6_addresses, conf_str, nentries_size);
309 ndproxy_conf_str_ipv6_addresses[nentries_size - 1] = 0;
312 _ndproxy_conf_ipv6_naddresses++;
313 } while (delim != NULL && (curp = ++delim) < (char *) (ndproxy_conf_str_ipv6_addresses + nentries_size) && _ndproxy_conf_ipv6_naddresses < nentries_max);
316 strncpy(ndproxy_conf_str_ipv6_addresses, conf_str, nentries_size);
317 ndproxy_conf_str_ipv6_addresses[nentries_size - 1] = 0;
321 bcopy(_ndproxy_conf_ipv6_addresses, ndproxy_conf_ipv6_addresses, _ndproxy_conf_ipv6_naddresses * sizeof(struct in6_addr));
322 *ndproxy_conf_ipv6_naddresses = _ndproxy_conf_ipv6_naddresses;
327 static int cb_string_list_exception(SYSCTL_HANDLER_ARGS) {
328 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);
331 static int cb_string_list_uplink(SYSCTL_HANDLER_ARGS) {
332 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);
335 // declare the sysctl node named net.inet6.ndproxyconf_exception_ipv6_addresses
336 // format: NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:{NNNN:NNNN,XXX.XXX.XXX.XXX};...;...
337 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");
339 // declare the sysctl node named net.inet6.ndproxyconf_uplink_ipv6_addresses
340 // format: NNNN:NNNN:NNNN:NNNN:NNNN:NNNN:{NNNN:NNNN,XXX.XXX.XXX.XXX};...;...
341 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");
343 ////////////////////////////////////////////////////////////////////////////////
344 // net.inet6.ndproxycount
346 static int cb_count(SYSCTL_HANDLER_ARGS) {
350 printf("NDPROXY INFO: count\n");
353 return sysctl_handle_int(oidp, arg1, arg2, req);
356 SYSCTL_OID(_net_inet6, OID_AUTO, ndproxycount, CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &ndproxy_conf_count, 0, cb_count, "I", "fire an event");