xref: /openbsd/usr.sbin/sasyncd/net_ctl.c (revision 46f033a3)
1 /*	$OpenBSD: net_ctl.c,v 1.11 2016/07/18 21:22:09 benno Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 H�kan Olsson.  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  *
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 BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * This code was written under funding by Multicom Security AB.
30  */
31 
32 
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include "sasyncd.h"
45 #include "net.h"
46 
47 struct ctlmsg {
48 	u_int32_t	type;
49 	u_int32_t	data;
50 	u_int32_t	data2;
51 };
52 
53 int snapcount = 0;
54 
55 static int
net_ctl_check_state(struct syncpeer * p,enum RUNSTATE nstate)56 net_ctl_check_state(struct syncpeer *p, enum RUNSTATE nstate)
57 {
58 	if (nstate < INIT || nstate > FAIL) {
59 		log_msg(0, "net_ctl: got bad state %d from peer \"%s\"",
60 		    nstate, p->name);
61 		net_ctl_send_error(p, CTL_STATE);
62 		return -1;
63 	}
64 	if (cfgstate.runstate == MASTER && nstate == MASTER) {
65 		log_msg(0, "net_ctl: got bad state MASTER from peer \"%s\"",
66 		    p->name);
67 		net_ctl_send_error(p, CTL_STATE);
68 		return -1;
69 	}
70 	if (p->runstate != nstate) {
71 		p->runstate = nstate;
72 		log_msg(1, "net_ctl: peer \"%s\" state change to %s", p->name,
73 		    carp_state_name(nstate));
74 	}
75 	return 0;
76 }
77 
78 void
net_ctl_handle_msg(struct syncpeer * p,u_int8_t * msg,u_int32_t msglen)79 net_ctl_handle_msg(struct syncpeer *p, u_int8_t *msg, u_int32_t msglen)
80 {
81 	struct ctlmsg	*ctl = (struct ctlmsg *)msg;
82 	enum RUNSTATE	 nstate;
83 	enum CTLTYPE	 ctype;
84 	static char	*ct, *ctltype[] = CTLTYPES;
85 
86 	if (msglen < sizeof *ctl) {
87 		log_msg(0, "net_ctl: got bad control message from peer \"%s\"",
88 		    p->name);
89 		net_ctl_send_error(p, CTL_UNKNOWN);
90 		return;
91 	}
92 
93 	switch (ntohl(ctl->type)) {
94 	case CTL_ENDSNAP:
95 		log_msg(2, "net_ctl: got CTL_ENDSNAP from peer \"%s\"",
96 		    p->name);
97 
98 		/* XXX More sophistication required to handle multiple peers. */
99 		if (carp_demoted) {
100 			snapcount++;
101 			if (snapcount >= cfgstate.peercnt)
102 				monitor_carpundemote(NULL);
103 		}
104 		break;
105 
106 	case CTL_STATE:
107 		log_msg(2, "net_ctl: got CTL_STATE from peer \"%s\"", p->name);
108 		nstate = (enum RUNSTATE)ntohl(ctl->data);
109 		if (net_ctl_check_state(p, nstate) == 0)
110 			net_ctl_send_ack(p, CTL_STATE, cfgstate.runstate);
111 		break;
112 
113 	case CTL_ERROR:
114 		log_msg(1, "net_ctl: got ERROR from peer \"%s\"", p->name);
115 
116 		switch (ntohl(ctl->data)) {
117 		case RESERVED: /* PFKEY -- nothing to do here for now */
118 			break;
119 
120 		case CTL_STATE:
121 			nstate = cfgstate.runstate;
122 			carp_check_state();
123 			if (nstate != cfgstate.runstate)
124 				net_ctl_send_state(p);
125 			break;
126 
127 		case CTL_UNKNOWN:
128 		default:
129 			break;
130 		}
131 		break;
132 
133 	case CTL_ACK:
134 		ctype = (enum CTLTYPE)ntohl(ctl->data);
135 		if (ctype < RESERVED || ctype > CTL_UNKNOWN)
136 			ct = "<unknown>";
137 		else
138 			ct = ctltype[ctype];
139 		log_msg(2, "net_ctl: got %s ACK from peer \"%s\"", ct,
140 		    p->name);
141 		if (ctype == CTL_STATE) {
142 			nstate = (enum RUNSTATE)ntohl(ctl->data2);
143 			net_ctl_check_state(p, nstate);
144 		}
145 	break;
146 
147 	case CTL_UNKNOWN:
148 	default:
149 		log_msg(1, "net_ctl: got unknown msg type %u from peer \"%s\"",
150 		    ntohl(ctl->type), p->name);
151 		break;
152 	}
153 }
154 
155 static int
net_ctl_send(struct syncpeer * p,u_int32_t type,u_int32_t d,u_int32_t d2)156 net_ctl_send(struct syncpeer *p, u_int32_t type, u_int32_t d, u_int32_t d2)
157 {
158 	struct ctlmsg	*m = malloc(sizeof *m);
159 
160 	if (!m) {
161 		log_err("malloc(%zu)", sizeof *m);
162 		return -1;
163 	}
164 
165 	memset(m, 0, sizeof *m);
166 	m->type = htonl(type);
167 	m->data = htonl(d);
168 	m->data2 = htonl(d2);
169 
170 	return net_queue(p, MSG_SYNCCTL, (u_int8_t *)m, sizeof *m);
171 }
172 
173 int
net_ctl_send_ack(struct syncpeer * p,enum CTLTYPE prevtype,u_int32_t code)174 net_ctl_send_ack(struct syncpeer *p, enum CTLTYPE prevtype, u_int32_t code)
175 {
176 	return net_ctl_send(p, CTL_ACK, (u_int32_t)prevtype, code);
177 }
178 
179 int
net_ctl_send_state(struct syncpeer * p)180 net_ctl_send_state(struct syncpeer *p)
181 {
182 	return net_ctl_send(p, CTL_STATE, (u_int32_t)cfgstate.runstate, 0);
183 }
184 
185 int
net_ctl_send_error(struct syncpeer * p,enum CTLTYPE prevtype)186 net_ctl_send_error(struct syncpeer *p, enum CTLTYPE prevtype)
187 {
188 	return net_ctl_send(p, CTL_ERROR, (u_int32_t)prevtype, 0);
189 }
190 
191 int
net_ctl_send_endsnap(struct syncpeer * p)192 net_ctl_send_endsnap(struct syncpeer *p)
193 {
194 	return net_ctl_send(p, CTL_ENDSNAP, 0, 0);
195 }
196 
197 /* After a CARP tracker state change, send an state ctl msg to all peers. */
198 void
net_ctl_update_state(void)199 net_ctl_update_state(void)
200 {
201 	struct syncpeer *p;
202 
203 	/* We may have new peers available.  */
204 	net_connect();
205 
206 	for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) {
207 		if (p->socket == -1)
208 			continue;
209 		log_msg(2, "net_ctl: sending my state %s to peer \"%s\"",
210 		    carp_state_name(cfgstate.runstate), p->name);
211 		net_ctl_send_state(p);
212 	}
213 }
214