1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022 InnoGames GmbH 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include "opt_inet.h" 33 #include "opt_inet6.h" 34 35 #include <sys/param.h> 36 #include <sys/errno.h> 37 38 #include <netinet/in.h> 39 40 #include <netinet6/ip6_var.h> 41 #include <netinet6/scope6_var.h> 42 43 #include <netpfil/pf/pfsync_nv.h> 44 45 int 46 pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl, 47 struct sockaddr_storage *sa) 48 { 49 int af; 50 51 if (!nvlist_exists_number(nvl, "af")) 52 return (EINVAL); 53 if (!nvlist_exists_binary(nvl, "address")) 54 return (EINVAL); 55 56 af = nvlist_get_number(nvl, "af"); 57 58 switch (af) { 59 #ifdef INET 60 case AF_INET: { 61 struct sockaddr_in *in = (struct sockaddr_in *)sa; 62 size_t len; 63 const void *addr = nvlist_get_binary(nvl, "address", &len); 64 in->sin_family = af; 65 if (len != sizeof(*in)) 66 return (EINVAL); 67 68 memcpy(in, addr, sizeof(*in)); 69 break; 70 } 71 #endif 72 #ifdef INET6 73 case AF_INET6: { 74 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 75 size_t len; 76 int error; 77 const void *addr = nvlist_get_binary(nvl, "address", &len); 78 in6->sin6_family = af; 79 if (len != sizeof(*in6)) 80 return (EINVAL); 81 82 memcpy(in6, addr, sizeof(*in6)); 83 84 error = sa6_embedscope(in6, V_ip6_use_defzone); 85 if (error) 86 return (error); 87 88 break; 89 } 90 #endif 91 default: 92 return (EINVAL); 93 } 94 95 return (0); 96 } 97 98 nvlist_t * 99 pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa) 100 { 101 nvlist_t *nvl; 102 103 nvl = nvlist_create(0); 104 if (nvl == NULL) { 105 return (nvl); 106 } 107 108 switch (sa->ss_family) { 109 #ifdef INET 110 case AF_INET: { 111 struct sockaddr_in *in = (struct sockaddr_in *)sa; 112 nvlist_add_number(nvl, "af", in->sin_family); 113 nvlist_add_binary(nvl, "address", in, sizeof(*in)); 114 break; 115 } 116 #endif 117 #ifdef INET6 118 case AF_INET6: { 119 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 120 sa6_recoverscope(in6); 121 nvlist_add_number(nvl, "af", in6->sin6_family); 122 nvlist_add_binary(nvl, "address", in6, sizeof(*in6)); 123 break; 124 } 125 #endif 126 default: 127 return NULL; 128 } 129 130 return (nvl); 131 } 132 133 int 134 pfsync_nvstatus_to_kstatus(const nvlist_t *nvl, struct pfsync_kstatus *status) 135 { 136 struct sockaddr_storage addr; 137 int error; 138 139 if (!nvlist_exists_number(nvl, "maxupdates")) 140 return (EINVAL); 141 if (!nvlist_exists_number(nvl, "flags")) 142 return (EINVAL); 143 144 status->maxupdates = nvlist_get_number(nvl, "maxupdates"); 145 status->version = nvlist_get_number(nvl, "version"); 146 status->flags = nvlist_get_number(nvl, "flags"); 147 148 if (nvlist_exists_string(nvl, "syncdev")) 149 strlcpy(status->syncdev, nvlist_get_string(nvl, "syncdev"), 150 IFNAMSIZ); 151 152 if (nvlist_exists_nvlist(nvl, "syncpeer")) { 153 memset(&addr, 0, sizeof(addr)); 154 if ((error = pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "syncpeer"), &addr)) != 0) 155 return (error); 156 157 status->syncpeer = addr; 158 } else { 159 memset(&status->syncpeer, 0, sizeof(status->syncpeer)); 160 } 161 162 return (0); 163 } 164