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 #include "opt_inet.h" 31 #include "opt_inet6.h" 32 33 #include <sys/param.h> 34 #include <sys/errno.h> 35 36 #include <netinet/in.h> 37 38 #include <netinet6/ip6_var.h> 39 #include <netinet6/scope6_var.h> 40 41 #include <netpfil/pf/pfsync_nv.h> 42 43 int 44 pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl, 45 struct sockaddr_storage *sa) 46 { 47 int af; 48 49 if (!nvlist_exists_number(nvl, "af")) 50 return (EINVAL); 51 if (!nvlist_exists_binary(nvl, "address")) 52 return (EINVAL); 53 54 af = nvlist_get_number(nvl, "af"); 55 56 switch (af) { 57 #ifdef INET 58 case AF_INET: { 59 struct sockaddr_in *in = (struct sockaddr_in *)sa; 60 size_t len; 61 const void *addr = nvlist_get_binary(nvl, "address", &len); 62 in->sin_family = af; 63 if (len != sizeof(*in)) 64 return (EINVAL); 65 66 memcpy(in, addr, sizeof(*in)); 67 break; 68 } 69 #endif 70 #ifdef INET6 71 case AF_INET6: { 72 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 73 size_t len; 74 int error; 75 const void *addr = nvlist_get_binary(nvl, "address", &len); 76 in6->sin6_family = af; 77 if (len != sizeof(*in6)) 78 return (EINVAL); 79 80 memcpy(in6, addr, sizeof(*in6)); 81 82 error = sa6_embedscope(in6, V_ip6_use_defzone); 83 if (error) 84 return (error); 85 86 break; 87 } 88 #endif 89 default: 90 return (EINVAL); 91 } 92 93 return (0); 94 } 95 96 nvlist_t * 97 pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa) 98 { 99 nvlist_t *nvl; 100 101 nvl = nvlist_create(0); 102 if (nvl == NULL) { 103 return (nvl); 104 } 105 106 switch (sa->ss_family) { 107 #ifdef INET 108 case AF_INET: { 109 struct sockaddr_in *in = (struct sockaddr_in *)sa; 110 nvlist_add_number(nvl, "af", in->sin_family); 111 nvlist_add_binary(nvl, "address", in, sizeof(*in)); 112 break; 113 } 114 #endif 115 #ifdef INET6 116 case AF_INET6: { 117 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa; 118 sa6_recoverscope(in6); 119 nvlist_add_number(nvl, "af", in6->sin6_family); 120 nvlist_add_binary(nvl, "address", in6, sizeof(*in6)); 121 break; 122 } 123 #endif 124 default: 125 return NULL; 126 } 127 128 return (nvl); 129 } 130 131 int 132 pfsync_nvstatus_to_kstatus(const nvlist_t *nvl, struct pfsync_kstatus *status) 133 { 134 struct sockaddr_storage addr; 135 int error; 136 137 if (!nvlist_exists_number(nvl, "maxupdates")) 138 return (EINVAL); 139 if (!nvlist_exists_number(nvl, "flags")) 140 return (EINVAL); 141 142 status->maxupdates = nvlist_get_number(nvl, "maxupdates"); 143 status->version = nvlist_get_number(nvl, "version"); 144 status->flags = nvlist_get_number(nvl, "flags"); 145 146 if (nvlist_exists_string(nvl, "syncdev")) 147 strlcpy(status->syncdev, nvlist_get_string(nvl, "syncdev"), 148 IFNAMSIZ); 149 150 if (nvlist_exists_nvlist(nvl, "syncpeer")) { 151 memset(&addr, 0, sizeof(addr)); 152 if ((error = pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "syncpeer"), &addr)) != 0) 153 return (error); 154 155 status->syncpeer = addr; 156 } else { 157 memset(&status->syncpeer, 0, sizeof(status->syncpeer)); 158 } 159 160 return (0); 161 } 162