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 55 static status_func_t status; 56 static usage_func_t usage; 57 static cmdloop_branch_t branch; 58 59 static void carp_constructor(void) __attribute__((constructor)); 60 static void carp_status(prop_dictionary_t, prop_dictionary_t); 61 static int setcarp_advbase(prop_dictionary_t, prop_dictionary_t); 62 static int setcarp_advskew(prop_dictionary_t, prop_dictionary_t); 63 static int setcarp_passwd(prop_dictionary_t, prop_dictionary_t); 64 static int setcarp_vhid(prop_dictionary_t, prop_dictionary_t); 65 static int setcarp_state(prop_dictionary_t, prop_dictionary_t); 66 static int setcarpdev(prop_dictionary_t, prop_dictionary_t); 67 68 static const char *carp_states[] = { CARP_STATES }; 69 70 /* from if_carp.c */ 71 enum carpstateval { INIT = 0, BACKUP, MASTER }; 72 73 struct 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 82 struct pinteger parse_advbase = PINTEGER_INITIALIZER1(&parse_advbase, "advbase", 83 0, 255, 10, setcarp_advbase, "advbase", &command_root.pb_parser); 84 85 struct pinteger parse_advskew = PINTEGER_INITIALIZER1(&parse_advskew, "advskew", 86 0, 254, 10, setcarp_advskew, "advskew", &command_root.pb_parser); 87 88 struct piface carpdev = PIFACE_INITIALIZER(&carpdev, "carpdev", setcarpdev, 89 "carpdev", &command_root.pb_parser); 90 91 struct pkw carpstate = PKW_INITIALIZER(&carpstate, "carp state", setcarp_state, 92 "carp_state", carpstatekw, __arraycount(carpstatekw), 93 &command_root.pb_parser); 94 95 struct pstr pass = PSTR_INITIALIZER(&pass, "pass", setcarp_passwd, 96 "pass", &command_root.pb_parser); 97 98 struct pinteger parse_vhid = PINTEGER_INITIALIZER1(&vhid, "vhid", 99 0, 255, 10, setcarp_vhid, "vhid", &command_root.pb_parser); 100 101 static 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 113 struct pkw carp = PKW_INITIALIZER(&carp, "CARP", NULL, NULL, 114 carpkw, __arraycount(carpkw), NULL); 115 116 static void 117 carp_set(prop_dictionary_t env, struct carpreq *carpr) 118 { 119 if (indirect_ioctl(env, SIOCSVH, carpr) == -1) 120 err(EXIT_FAILURE, "SIOCSVH"); 121 } 122 123 static int 124 carp_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 131 static void 132 carp_get(prop_dictionary_t env, struct carpreq *carpr) 133 { 134 if (carp_get1(env, carpr) == -1) 135 err(EXIT_FAILURE, "SIOCGVH"); 136 } 137 138 static void 139 carp_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 160 int 161 setcarp_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 183 int 184 setcarp_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 202 int 203 setcarp_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 */ 222 int 223 setcarp_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 */ 242 static int 243 setcarp_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 */ 262 int 263 setcarpdev(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 283 static void 284 carp_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 292 static void 293 carp_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