1/* $NetBSD: carp.c,v 1.15 2023/03/26 01:04:16 mlelstv Exp $ */ 2 3/* 4 * Copyright (c) 2002 Michael Shalayeff. All rights reserved. 5 * Copyright (c) 2003 Ryan McBride. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30#ifndef lint 31__RCSID("$NetBSD: carp.c,v 1.15 2023/03/26 01:04:16 mlelstv Exp $"); 32#endif /* not lint */ 33 34#include <sys/param.h> 35#include <sys/ioctl.h> 36#include <sys/socket.h> 37#include <sys/sockio.h> 38 39#include <net/if.h> 40#include <netinet/ip_carp.h> 41#include <net/route.h> 42 43#include <stdio.h> 44#include <string.h> 45#include <stdlib.h> 46#include <unistd.h> 47#include <err.h> 48#include <errno.h> 49#include <util.h> 50 51#include "env.h" 52#include "parse.h" 53#include "extern.h" 54 55static status_func_t status; 56static usage_func_t usage; 57static cmdloop_branch_t branch; 58 59static void carp_constructor(void) __attribute__((constructor)); 60static void carp_status(prop_dictionary_t, prop_dictionary_t); 61static int setcarp_advbase(prop_dictionary_t, prop_dictionary_t); 62static int setcarp_advskew(prop_dictionary_t, prop_dictionary_t); 63static int setcarp_passwd(prop_dictionary_t, prop_dictionary_t); 64static int setcarp_vhid(prop_dictionary_t, prop_dictionary_t); 65static int setcarp_state(prop_dictionary_t, prop_dictionary_t); 66static int setcarpdev(prop_dictionary_t, prop_dictionary_t); 67 68static const char *carp_states[] = { CARP_STATES }; 69 70/* from if_carp.c */ 71enum carpstateval { INIT = 0, BACKUP, MASTER }; 72 73struct kwinst carpstatekw[] = { 74 {.k_word = "INIT", .k_type = KW_T_INT, .k_int = INIT, 75 .k_nextparser = &command_root.pb_parser} 76 , {.k_word = "BACKUP", .k_type = KW_T_INT, .k_int = BACKUP, 77 .k_nextparser = &command_root.pb_parser} 78 , {.k_word = "MASTER", .k_type = KW_T_INT, .k_int = MASTER, 79 .k_nextparser = &command_root.pb_parser} 80}; 81 82struct pinteger parse_advbase = PINTEGER_INITIALIZER1(&parse_advbase, "advbase", 83 0, 255, 10, setcarp_advbase, "advbase", &command_root.pb_parser); 84 85struct pinteger parse_advskew = PINTEGER_INITIALIZER1(&parse_advskew, "advskew", 86 0, 254, 10, setcarp_advskew, "advskew", &command_root.pb_parser); 87 88struct piface carpdev = PIFACE_INITIALIZER(&carpdev, "carpdev", setcarpdev, 89 "carpdev", &command_root.pb_parser); 90 91struct pkw carpstate = PKW_INITIALIZER(&carpstate, "carp state", setcarp_state, 92 "carp_state", carpstatekw, __arraycount(carpstatekw), 93 &command_root.pb_parser); 94 95struct pstr pass = PSTR_INITIALIZER(&pass, "pass", setcarp_passwd, 96 "pass", &command_root.pb_parser); 97 98struct pinteger parse_vhid = PINTEGER_INITIALIZER1(&vhid, "vhid", 99 0, 255, 10, setcarp_vhid, "vhid", &command_root.pb_parser); 100 101static const struct kwinst carpkw[] = { 102 {.k_word = "advbase", .k_nextparser = &parse_advbase.pi_parser} 103 , {.k_word = "advskew", .k_nextparser = &parse_advskew.pi_parser} 104 , {.k_word = "carpdev", .k_nextparser = &carpdev.pif_parser} 105 , {.k_word = "-carpdev", .k_key = "carpdev", .k_type = KW_T_STR, 106 .k_str = "", .k_exec = setcarpdev, 107 .k_nextparser = &command_root.pb_parser} 108 , {.k_word = "pass", .k_nextparser = &pass.ps_parser} 109 , {.k_word = "state", .k_nextparser = &carpstate.pk_parser} 110 , {.k_word = "vhid", .k_nextparser = &parse_vhid.pi_parser} 111}; 112 113struct pkw carp = PKW_INITIALIZER(&carp, "CARP", NULL, NULL, 114 carpkw, __arraycount(carpkw), NULL); 115 116static void 117carp_set(prop_dictionary_t env, struct carpreq *carpr) 118{ 119 if (indirect_ioctl(env, SIOCSVH, carpr) == -1) 120 err(EXIT_FAILURE, "SIOCSVH"); 121} 122 123static int 124carp_get1(prop_dictionary_t env, struct carpreq *carpr) 125{ 126 memset(carpr, 0, sizeof(*carpr)); 127 128 return indirect_ioctl(env, SIOCGVH, carpr); 129} 130 131static void 132carp_get(prop_dictionary_t env, struct carpreq *carpr) 133{ 134 if (carp_get1(env, carpr) == -1) 135 err(EXIT_FAILURE, "SIOCGVH"); 136} 137 138static void 139carp_status(prop_dictionary_t env, prop_dictionary_t oenv) 140{ 141 const char *state; 142 struct carpreq carpr; 143 144 if (carp_get1(env, &carpr) == -1) 145 return; 146 147 if (carpr.carpr_vhid <= 0) 148 return; 149 if (carpr.carpr_state > CARP_MAXSTATE) 150 state = "<UNKNOWN>"; 151 else 152 state = carp_states[carpr.carpr_state]; 153 154 printf("\tcarp: %s carpdev %s vhid %d advbase %d advskew %d\n", 155 state, carpr.carpr_carpdev[0] != '\0' ? 156 carpr.carpr_carpdev : "none", carpr.carpr_vhid, 157 carpr.carpr_advbase, carpr.carpr_advskew); 158} 159 160int 161setcarp_passwd(prop_dictionary_t env, prop_dictionary_t oenv) 162{ 163 struct carpreq carpr; 164 prop_data_t data; 165 166 data = (prop_data_t)prop_dictionary_get(env, "pass"); 167 if (data == NULL) { 168 errno = ENOENT; 169 return -1; 170 } 171 172 carp_get(env, &carpr); 173 174 memset(carpr.carpr_key, 0, sizeof(carpr.carpr_key)); 175 /* XXX Should hash the password into the key here, perhaps? */ 176 strlcpy((char *)carpr.carpr_key, prop_data_value(data), 177 MIN(CARP_KEY_LEN, prop_data_size(data))); 178 179 carp_set(env, &carpr); 180 return 0; 181} 182 183int 184setcarp_vhid(prop_dictionary_t env, prop_dictionary_t oenv) 185{ 186 struct carpreq carpr; 187 int64_t vhid; 188 189 if (!prop_dictionary_get_int64(env, "vhid", &vhid)) { 190 errno = ENOENT; 191 return -1; 192 } 193 194 carp_get(env, &carpr); 195 196 carpr.carpr_vhid = vhid; 197 198 carp_set(env, &carpr); 199 return 0; 200} 201 202int 203setcarp_advskew(prop_dictionary_t env, prop_dictionary_t oenv) 204{ 205 struct carpreq carpr; 206 int64_t advskew; 207 208 if (!prop_dictionary_get_int64(env, "advskew", &advskew)) { 209 errno = ENOENT; 210 return -1; 211 } 212 213 carp_get(env, &carpr); 214 215 carpr.carpr_advskew = advskew; 216 217 carp_set(env, &carpr); 218 return 0; 219} 220 221/* ARGSUSED */ 222int 223setcarp_advbase(prop_dictionary_t env, prop_dictionary_t oenv) 224{ 225 struct carpreq carpr; 226 int64_t advbase; 227 228 if (!prop_dictionary_get_int64(env, "advbase", &advbase)) { 229 errno = ENOENT; 230 return -1; 231 } 232 233 carp_get(env, &carpr); 234 235 carpr.carpr_advbase = advbase; 236 237 carp_set(env, &carpr); 238 return 0; 239} 240 241/* ARGSUSED */ 242static int 243setcarp_state(prop_dictionary_t env, prop_dictionary_t oenv) 244{ 245 struct carpreq carpr; 246 int64_t carp_state; 247 248 if (!prop_dictionary_get_int64(env, "carp_state", &carp_state)) { 249 errno = ENOENT; 250 return -1; 251 } 252 253 carp_get(env, &carpr); 254 255 carpr.carpr_state = carp_state; 256 257 carp_set(env, &carpr); 258 return 0; 259} 260 261/* ARGSUSED */ 262int 263setcarpdev(prop_dictionary_t env, prop_dictionary_t oenv) 264{ 265 struct carpreq carpr; 266 prop_string_t s; 267 268 s = (prop_string_t)prop_dictionary_get(env, "carpdev"); 269 if (s == NULL) { 270 errno = ENOENT; 271 return -1; 272 } 273 274 carp_get(env, &carpr); 275 276 strlcpy(carpr.carpr_carpdev, prop_string_value(s), 277 sizeof(carpr.carpr_carpdev)); 278 279 carp_set(env, &carpr); 280 return 0; 281} 282 283static void 284carp_usage(prop_dictionary_t env) 285{ 286 fprintf(stderr, 287 "\t[ advbase n ] [ advskew n ] [ carpdev iface ] " 288 "[ pass passphrase ] [ state state ] [ vhid n ]\n"); 289 290} 291 292static void 293carp_constructor(void) 294{ 295 cmdloop_branch_init(&branch, &carp.pk_parser); 296 register_cmdloop_branch(&branch); 297 status_func_init(&status, carp_status); 298 usage_func_init(&usage, carp_usage); 299 register_status(&status); 300 register_usage(&usage); 301} 302