1/* $NetBSD: pfsync.c Exp $ */ 2/*- 3 * Copyright (c) 2009 The NetBSD Foundation, Inc. 4 * All rights reserved. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29#ifndef lint 30__RCSID("$NetBSD: pfsync.c Exp $"); 31#endif /* not lint */ 32 33#include <sys/param.h> 34#include <sys/ioctl.h> 35#include <sys/socket.h> 36#include <sys/sockio.h> 37 38#include <net/if.h> 39#include <net/route.h> 40#include <net/pfvar.h> 41#include <net/if_pfsync.h> 42 43#include <arpa/inet.h> 44 45#include <stdio.h> 46#include <string.h> 47#include <stdlib.h> 48#include <unistd.h> 49#include <err.h> 50#include <errno.h> 51#include <util.h> 52 53#include "env.h" 54#include "parse.h" 55#include "extern.h" 56 57static status_func_t status; 58static usage_func_t usage; 59static cmdloop_branch_t branch; 60 61static void pfsync_constructor(void) __attribute__((constructor)); 62static void pfsync_status(prop_dictionary_t, prop_dictionary_t); 63static int setpfsync_maxupd(prop_dictionary_t, prop_dictionary_t); 64static int setpfsync_peer(prop_dictionary_t, prop_dictionary_t); 65static int setpfsyncdev(prop_dictionary_t, prop_dictionary_t); 66 67struct pinteger parse_maxupd = PINTEGER_INITIALIZER1(&parse_maxupd, "maxupd", 68 0, 255, 10, setpfsync_maxupd, "maxupd", &command_root.pb_parser); 69 70struct piface pfsyncdev = PIFACE_INITIALIZER(&pfsyncdev, "syncdev", setpfsyncdev, 71 "syncdev", &command_root.pb_parser); 72 73struct paddr parse_sync_peer = PADDR_INITIALIZER(&parse_sync_peer, "syncpeer", 74 setpfsync_peer, "syncpeer", NULL, NULL, NULL, &command_root.pb_parser); 75 76static const struct kwinst pfsynckw[] = { 77 {.k_word = "maxupd", .k_nextparser = &parse_maxupd.pi_parser}, 78 {.k_word = "syncdev", .k_nextparser = &pfsyncdev.pif_parser}, 79 {.k_word = "-syncdev", .k_key = "syncdev", .k_type = KW_T_STR, 80 .k_str = "", .k_exec = setpfsyncdev, 81 .k_nextparser = &command_root.pb_parser}, 82 {.k_word = "syncpeer", .k_nextparser = &parse_sync_peer.pa_parser}, 83 {.k_word = "-syncpeer", .k_key = "syncpeer", .k_type = KW_T_STR, 84 .k_str = "", .k_exec = setpfsync_peer, 85 .k_nextparser = &command_root.pb_parser} 86}; 87 88struct pkw pfsync = PKW_INITIALIZER(&pfsync, "pfsync", NULL, NULL, 89 pfsynckw, __arraycount(pfsynckw), NULL); 90 91static void 92pfsync_set(prop_dictionary_t env, struct pfsyncreq *pfsyncr) 93{ 94 if (indirect_ioctl(env, SIOCSETPFSYNC, pfsyncr) == -1) 95 err(EXIT_FAILURE, "SIOCSETPFSYNC"); 96} 97 98static int 99pfsync_get1(prop_dictionary_t env, struct pfsyncreq *pfsyncr) 100{ 101 memset(pfsyncr, 0, sizeof(*pfsyncr)); 102 103 return indirect_ioctl(env, SIOCGETPFSYNC, pfsyncr); 104} 105 106static void 107pfsync_get(prop_dictionary_t env, struct pfsyncreq *pfsyncr) 108{ 109 if (pfsync_get1(env, pfsyncr) == -1) 110 err(EXIT_FAILURE, "SIOCGETPFSYNC"); 111} 112 113static void 114pfsync_status(prop_dictionary_t env, prop_dictionary_t oenv) 115{ 116 struct pfsyncreq pfsyncr; 117 118 if (pfsync_get1(env, &pfsyncr) == -1) 119 return; 120 121 if (pfsyncr.pfsyncr_syncdev[0] != '\0') { 122 printf("\tpfsync: syncdev: %s ", pfsyncr.pfsyncr_syncdev); 123 if (pfsyncr.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP) 124 printf("syncpeer: %s ", 125 inet_ntoa(pfsyncr.pfsyncr_syncpeer)); 126 printf("maxupd: %d\n", pfsyncr.pfsyncr_maxupdates); 127 } 128} 129 130/* ARGSUSED */ 131int 132setpfsync_maxupd(prop_dictionary_t env, prop_dictionary_t oenv) 133{ 134 struct pfsyncreq pfsyncr; 135 uint8_t maxupd; 136 137 if (!prop_dictionary_get_uint8(env, "maxupd", &maxupd)) { 138 errno = ENOENT; 139 return -1; 140 } 141 142 pfsync_get(env, &pfsyncr); 143 144 pfsyncr.pfsyncr_maxupdates = maxupd; 145 146 pfsync_set(env, &pfsyncr); 147 return 0; 148} 149 150 151/* ARGSUSED */ 152int 153setpfsyncdev(prop_dictionary_t env, prop_dictionary_t oenv) 154{ 155 struct pfsyncreq pfsyncr; 156 const char *dev; 157 158 if (!prop_dictionary_get_cstring_nocopy(env, "syncdev", &dev)) { 159 errno = ENOENT; 160 return -1; 161 } 162 163 pfsync_get(env, &pfsyncr); 164 165 strlcpy(pfsyncr.pfsyncr_syncdev, dev, sizeof(pfsyncr.pfsyncr_syncdev)); 166 167 pfsync_set(env, &pfsyncr); 168 return 0; 169} 170 171/* ARGSUSED */ 172int 173setpfsync_peer(prop_dictionary_t env, prop_dictionary_t oenv) 174{ 175 struct pfsyncreq pfsyncr; 176 prop_data_t data; 177 const struct paddr_prefix *peerpfx; 178 const struct sockaddr_in *s; 179 180 data = (prop_data_t)prop_dictionary_get(env, "syncpeer"); 181 if (data == NULL) { 182 errno = ENOENT; 183 return -1; 184 } 185 186 pfsync_get(env, &pfsyncr); 187 188 peerpfx = prop_data_data_nocopy(data); 189 190 if (peerpfx != NULL) { 191 // Only AF_INET is supported for now 192 if (peerpfx->pfx_addr.sa_family != AF_INET) { 193 errno = ENOENT; 194 return -1; 195 } 196 197 198 s = (const struct sockaddr_in*)&peerpfx->pfx_addr; 199 200 memcpy(&pfsyncr.pfsyncr_syncpeer.s_addr, &s->sin_addr, 201 MIN(sizeof(pfsyncr.pfsyncr_syncpeer.s_addr), 202 peerpfx->pfx_addr.sa_len)); 203 } else { 204 memset(&pfsyncr.pfsyncr_syncpeer.s_addr, 0, 205 sizeof(pfsyncr.pfsyncr_syncpeer.s_addr)); 206 } 207 208 pfsync_set(env, &pfsyncr); 209 210 return 0; 211} 212 213static void 214pfsync_usage(prop_dictionary_t env) 215{ 216 fprintf(stderr, 217 "\t[ maxupd n ] [ syncdev iface ] [syncpeer peer_addr]\n"); 218} 219 220static void 221pfsync_constructor(void) 222{ 223 cmdloop_branch_init(&branch, &pfsync.pk_parser); 224 register_cmdloop_branch(&branch); 225 status_func_init(&status, pfsync_status); 226 usage_func_init(&usage, pfsync_usage); 227 register_status(&status); 228 register_usage(&usage); 229} 230