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