xref: /openbsd-src/usr.sbin/sasyncd/net_ctl.c (revision 46f033a3aeabbbd89c8657a0c811967f45f853fb)
1*46f033a3Sbenno /*	$OpenBSD: net_ctl.c,v 1.11 2016/07/18 21:22:09 benno Exp $	*/
27aea46c5Sho 
37aea46c5Sho /*
47aea46c5Sho  * Copyright (c) 2005 H�kan Olsson.  All rights reserved.
57aea46c5Sho  *
67aea46c5Sho  * Redistribution and use in source and binary forms, with or without
77aea46c5Sho  * modification, are permitted provided that the following conditions
87aea46c5Sho  * are met:
97aea46c5Sho  *
107aea46c5Sho  * 1. Redistributions of source code must retain the above copyright
117aea46c5Sho  *    notice, this list of conditions and the following disclaimer.
127aea46c5Sho  * 2. Redistributions in binary form must reproduce the above copyright
137aea46c5Sho  *    notice, this list of conditions and the following disclaimer in the
147aea46c5Sho  *    documentation and/or other materials provided with the distribution.
157aea46c5Sho  *
167aea46c5Sho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177aea46c5Sho  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187aea46c5Sho  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197aea46c5Sho  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207aea46c5Sho  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
217aea46c5Sho  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227aea46c5Sho  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237aea46c5Sho  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
247aea46c5Sho  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
257aea46c5Sho  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267aea46c5Sho  */
277aea46c5Sho 
287aea46c5Sho /*
297aea46c5Sho  * This code was written under funding by Multicom Security AB.
307aea46c5Sho  */
317aea46c5Sho 
327aea46c5Sho 
337aea46c5Sho #include <sys/types.h>
347aea46c5Sho #include <sys/socket.h>
357aea46c5Sho #include <sys/time.h>
367aea46c5Sho #include <netinet/in.h>
377aea46c5Sho #include <arpa/inet.h>
387aea46c5Sho 
397aea46c5Sho #include <errno.h>
4054626cc1Sho #include <stdlib.h>
417aea46c5Sho #include <string.h>
427aea46c5Sho #include <unistd.h>
437aea46c5Sho 
447aea46c5Sho #include "sasyncd.h"
457aea46c5Sho #include "net.h"
467aea46c5Sho 
477aea46c5Sho struct ctlmsg {
487aea46c5Sho 	u_int32_t	type;
497aea46c5Sho 	u_int32_t	data;
507aea46c5Sho 	u_int32_t	data2;
517aea46c5Sho };
527aea46c5Sho 
539945a12eSmcbride int snapcount = 0;
549945a12eSmcbride 
557aea46c5Sho static int
net_ctl_check_state(struct syncpeer * p,enum RUNSTATE nstate)567aea46c5Sho net_ctl_check_state(struct syncpeer *p, enum RUNSTATE nstate)
577aea46c5Sho {
587aea46c5Sho 	if (nstate < INIT || nstate > FAIL) {
591d55a410Sho 		log_msg(0, "net_ctl: got bad state %d from peer \"%s\"",
601d55a410Sho 		    nstate, p->name);
617aea46c5Sho 		net_ctl_send_error(p, CTL_STATE);
627aea46c5Sho 		return -1;
637aea46c5Sho 	}
6426bbdef8Sho 	if (cfgstate.runstate == MASTER && nstate == MASTER) {
651d55a410Sho 		log_msg(0, "net_ctl: got bad state MASTER from peer \"%s\"",
667aea46c5Sho 		    p->name);
677aea46c5Sho 		net_ctl_send_error(p, CTL_STATE);
687aea46c5Sho 		return -1;
697aea46c5Sho 	}
707aea46c5Sho 	if (p->runstate != nstate) {
717aea46c5Sho 		p->runstate = nstate;
721d55a410Sho 		log_msg(1, "net_ctl: peer \"%s\" state change to %s", p->name,
73f7670855Smcbride 		    carp_state_name(nstate));
747aea46c5Sho 	}
757aea46c5Sho 	return 0;
767aea46c5Sho }
777aea46c5Sho 
787aea46c5Sho void
net_ctl_handle_msg(struct syncpeer * p,u_int8_t * msg,u_int32_t msglen)797aea46c5Sho net_ctl_handle_msg(struct syncpeer *p, u_int8_t *msg, u_int32_t msglen)
807aea46c5Sho {
817aea46c5Sho 	struct ctlmsg	*ctl = (struct ctlmsg *)msg;
827aea46c5Sho 	enum RUNSTATE	 nstate;
837aea46c5Sho 	enum CTLTYPE	 ctype;
847aea46c5Sho 	static char	*ct, *ctltype[] = CTLTYPES;
857aea46c5Sho 
867aea46c5Sho 	if (msglen < sizeof *ctl) {
871d55a410Sho 		log_msg(0, "net_ctl: got bad control message from peer \"%s\"",
887aea46c5Sho 		    p->name);
897aea46c5Sho 		net_ctl_send_error(p, CTL_UNKNOWN);
907aea46c5Sho 		return;
917aea46c5Sho 	}
927aea46c5Sho 
937aea46c5Sho 	switch (ntohl(ctl->type)) {
949945a12eSmcbride 	case CTL_ENDSNAP:
959353ff65Skjell 		log_msg(2, "net_ctl: got CTL_ENDSNAP from peer \"%s\"",
969945a12eSmcbride 		    p->name);
979945a12eSmcbride 
989945a12eSmcbride 		/* XXX More sophistication required to handle multiple peers. */
999945a12eSmcbride 		if (carp_demoted) {
1009945a12eSmcbride 			snapcount++;
1019945a12eSmcbride 			if (snapcount >= cfgstate.peercnt)
1029945a12eSmcbride 				monitor_carpundemote(NULL);
1039945a12eSmcbride 		}
1049945a12eSmcbride 		break;
1059945a12eSmcbride 
1067aea46c5Sho 	case CTL_STATE:
1079353ff65Skjell 		log_msg(2, "net_ctl: got CTL_STATE from peer \"%s\"", p->name);
1087aea46c5Sho 		nstate = (enum RUNSTATE)ntohl(ctl->data);
1097aea46c5Sho 		if (net_ctl_check_state(p, nstate) == 0)
1107aea46c5Sho 			net_ctl_send_ack(p, CTL_STATE, cfgstate.runstate);
1117aea46c5Sho 		break;
1127aea46c5Sho 
1137aea46c5Sho 	case CTL_ERROR:
1141d55a410Sho 		log_msg(1, "net_ctl: got ERROR from peer \"%s\"", p->name);
1157aea46c5Sho 
1167aea46c5Sho 		switch (ntohl(ctl->data)) {
1177aea46c5Sho 		case RESERVED: /* PFKEY -- nothing to do here for now */
1187aea46c5Sho 			break;
1197aea46c5Sho 
1207aea46c5Sho 		case CTL_STATE:
1217aea46c5Sho 			nstate = cfgstate.runstate;
1227aea46c5Sho 			carp_check_state();
1237aea46c5Sho 			if (nstate != cfgstate.runstate)
1247aea46c5Sho 				net_ctl_send_state(p);
1257aea46c5Sho 			break;
1267aea46c5Sho 
1277aea46c5Sho 		case CTL_UNKNOWN:
1287aea46c5Sho 		default:
1297aea46c5Sho 			break;
1307aea46c5Sho 		}
1317aea46c5Sho 		break;
1327aea46c5Sho 
1337aea46c5Sho 	case CTL_ACK:
1347aea46c5Sho 		ctype = (enum CTLTYPE)ntohl(ctl->data);
1357aea46c5Sho 		if (ctype < RESERVED || ctype > CTL_UNKNOWN)
1367aea46c5Sho 			ct = "<unknown>";
1377aea46c5Sho 		else
1387aea46c5Sho 			ct = ctltype[ctype];
1399353ff65Skjell 		log_msg(2, "net_ctl: got %s ACK from peer \"%s\"", ct,
1401d55a410Sho 		    p->name);
1417aea46c5Sho 		if (ctype == CTL_STATE) {
1427aea46c5Sho 			nstate = (enum RUNSTATE)ntohl(ctl->data2);
1437aea46c5Sho 			net_ctl_check_state(p, nstate);
1447aea46c5Sho 		}
1457aea46c5Sho 	break;
1467aea46c5Sho 
1477aea46c5Sho 	case CTL_UNKNOWN:
1487aea46c5Sho 	default:
1491d55a410Sho 		log_msg(1, "net_ctl: got unknown msg type %u from peer \"%s\"",
1507aea46c5Sho 		    ntohl(ctl->type), p->name);
1517aea46c5Sho 		break;
1527aea46c5Sho 	}
1537aea46c5Sho }
1547aea46c5Sho 
1557aea46c5Sho static int
net_ctl_send(struct syncpeer * p,u_int32_t type,u_int32_t d,u_int32_t d2)1567aea46c5Sho net_ctl_send(struct syncpeer *p, u_int32_t type, u_int32_t d, u_int32_t d2)
1577aea46c5Sho {
15835de856eSderaadt 	struct ctlmsg	*m = malloc(sizeof *m);
1597aea46c5Sho 
1607aea46c5Sho 	if (!m) {
161*46f033a3Sbenno 		log_err("malloc(%zu)", sizeof *m);
1627aea46c5Sho 		return -1;
1637aea46c5Sho 	}
1647aea46c5Sho 
1657aea46c5Sho 	memset(m, 0, sizeof *m);
1667aea46c5Sho 	m->type = htonl(type);
1677aea46c5Sho 	m->data = htonl(d);
1687aea46c5Sho 	m->data2 = htonl(d2);
1697aea46c5Sho 
17054626cc1Sho 	return net_queue(p, MSG_SYNCCTL, (u_int8_t *)m, sizeof *m);
1717aea46c5Sho }
1727aea46c5Sho 
1737aea46c5Sho int
net_ctl_send_ack(struct syncpeer * p,enum CTLTYPE prevtype,u_int32_t code)1747aea46c5Sho net_ctl_send_ack(struct syncpeer *p, enum CTLTYPE prevtype, u_int32_t code)
1757aea46c5Sho {
1767aea46c5Sho 	return net_ctl_send(p, CTL_ACK, (u_int32_t)prevtype, code);
1777aea46c5Sho }
1787aea46c5Sho 
1797aea46c5Sho int
net_ctl_send_state(struct syncpeer * p)1807aea46c5Sho net_ctl_send_state(struct syncpeer *p)
1817aea46c5Sho {
1827aea46c5Sho 	return net_ctl_send(p, CTL_STATE, (u_int32_t)cfgstate.runstate, 0);
1837aea46c5Sho }
1847aea46c5Sho 
1857aea46c5Sho int
net_ctl_send_error(struct syncpeer * p,enum CTLTYPE prevtype)1867aea46c5Sho net_ctl_send_error(struct syncpeer *p, enum CTLTYPE prevtype)
1877aea46c5Sho {
1887aea46c5Sho 	return net_ctl_send(p, CTL_ERROR, (u_int32_t)prevtype, 0);
1897aea46c5Sho }
1907aea46c5Sho 
1919945a12eSmcbride int
net_ctl_send_endsnap(struct syncpeer * p)1929945a12eSmcbride net_ctl_send_endsnap(struct syncpeer *p)
1939945a12eSmcbride {
1949945a12eSmcbride 	return net_ctl_send(p, CTL_ENDSNAP, 0, 0);
1959945a12eSmcbride }
1969945a12eSmcbride 
1977aea46c5Sho /* After a CARP tracker state change, send an state ctl msg to all peers. */
1987aea46c5Sho void
net_ctl_update_state(void)1997aea46c5Sho net_ctl_update_state(void)
2007aea46c5Sho {
2017aea46c5Sho 	struct syncpeer *p;
2027aea46c5Sho 
2037aea46c5Sho 	/* We may have new peers available.  */
2041d55a410Sho 	net_connect();
2057aea46c5Sho 
2067aea46c5Sho 	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
2077aea46c5Sho 		if (p->socket == -1)
2087aea46c5Sho 			continue;
2099353ff65Skjell 		log_msg(2, "net_ctl: sending my state %s to peer \"%s\"",
210f7670855Smcbride 		    carp_state_name(cfgstate.runstate), p->name);
2117aea46c5Sho 		net_ctl_send_state(p);
2127aea46c5Sho 	}
2137aea46c5Sho }
214