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 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 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 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 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 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 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 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 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