1 /* $OpenBSD: carp.c,v 1.8 2011/05/05 12:01:43 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/socket.h> 21 #include <sys/ioctl.h> 22 23 #include <net/if.h> 24 25 #include <errno.h> 26 #include <string.h> 27 #include <stdlib.h> 28 #include <unistd.h> 29 #include <event.h> 30 31 #include <openssl/ssl.h> 32 33 #include "relayd.h" 34 35 struct carpgroup { 36 TAILQ_ENTRY(carpgroup) entry; 37 char *group; 38 int do_demote; 39 int changed_by; 40 }; 41 42 TAILQ_HEAD(carpgroups, carpgroup) carpgroups = 43 TAILQ_HEAD_INITIALIZER(carpgroups); 44 45 struct carpgroup *carp_group_find(char *group); 46 int carp_demote_ioctl(char *, int); 47 48 struct carpgroup * 49 carp_group_find(char *group) 50 { 51 struct carpgroup *c; 52 53 TAILQ_FOREACH(c, &carpgroups, entry) 54 if (!strcmp(c->group, group)) 55 return (c); 56 57 return (NULL); 58 } 59 60 int 61 carp_demote_init(char *group, int force) 62 { 63 struct carpgroup *c; 64 int level; 65 66 if ((c = carp_group_find(group)) == NULL) { 67 if ((c = calloc(1, sizeof(struct carpgroup))) == NULL) { 68 log_warn("%s: calloc", __func__); 69 return (-1); 70 } 71 if ((c->group = strdup(group)) == NULL) { 72 log_warn("%s: strdup, __func__"); 73 free(c); 74 return (-1); 75 } 76 77 /* only demote if this group already is demoted */ 78 if ((level = carp_demote_get(group)) == -1) { 79 free(c->group); 80 free(c); 81 return (-1); 82 } 83 if (level > 0 || force) 84 c->do_demote = 1; 85 86 TAILQ_INSERT_TAIL(&carpgroups, c, entry); 87 } 88 89 return (0); 90 } 91 92 void 93 carp_demote_shutdown(void) 94 { 95 struct carpgroup *c; 96 97 while ((c = TAILQ_FIRST(&carpgroups)) != NULL) { 98 TAILQ_REMOVE(&carpgroups, c, entry); 99 if (c->do_demote && c->changed_by > 0) 100 carp_demote_ioctl(c->group, -c->changed_by); 101 102 free(c->group); 103 free(c); 104 } 105 } 106 107 int 108 carp_demote_get(char *group) 109 { 110 int s; 111 struct ifgroupreq ifgr; 112 113 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 114 log_warn("%s: socket", __func__); 115 return (-1); 116 } 117 118 bzero(&ifgr, sizeof(ifgr)); 119 if (strlcpy(ifgr.ifgr_name, group, sizeof(ifgr.ifgr_name)) >= 120 sizeof(ifgr.ifgr_name)) { 121 log_warn("%s: invalid group", __func__); 122 return (-1); 123 } 124 125 if (ioctl(s, SIOCGIFGATTR, (caddr_t)&ifgr) == -1) { 126 if (errno == ENOENT) 127 log_warnx("%s: group \"%s\" does not exist", 128 __func__, group); 129 else 130 log_warn("%s: ioctl", __func__); 131 close(s); 132 return (-1); 133 } 134 135 close(s); 136 return ((int)ifgr.ifgr_attrib.ifg_carp_demoted); 137 } 138 139 int 140 carp_demote_set(char *group, int demote) 141 { 142 struct carpgroup *c; 143 144 if ((c = carp_group_find(group)) == NULL) { 145 log_warnx("%s: carp group %s not found", __func__, group); 146 return (-1); 147 } 148 149 if (c->changed_by + demote < 0) { 150 log_warnx("%s: changed_by + demote < 0", __func__); 151 return (-1); 152 } 153 154 if (c->do_demote && carp_demote_ioctl(group, demote) == -1) 155 return (-1); 156 157 c->changed_by += demote; 158 159 /* enable demotion when we return to 0, i. e. all sessions up */ 160 if (demote < 0 && c->changed_by == 0) 161 c->do_demote = 1; 162 163 return (0); 164 } 165 166 int 167 carp_demote_reset(char *group, int value) 168 { 169 int level; 170 int demote = 0; 171 172 if (value < 0) { 173 log_warnx("%s: value < 0", __func__); 174 return (-1); 175 } 176 177 if ((level = carp_demote_get(group)) == -1) 178 return (-1); 179 if (level == value) 180 return (0); 181 182 demote -= level; 183 demote += value; 184 185 if (carp_demote_ioctl(group, demote) == -1) 186 return (-1); 187 188 return (0); 189 } 190 191 int 192 carp_demote_ioctl(char *group, int demote) 193 { 194 int s, res; 195 struct ifgroupreq ifgr; 196 197 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 198 log_warn("%s: socket", __func__); 199 return (-1); 200 } 201 202 bzero(&ifgr, sizeof(ifgr)); 203 if (strlcpy(ifgr.ifgr_name, group, sizeof(ifgr.ifgr_name)) >= 204 sizeof(ifgr.ifgr_name)) { 205 log_warn("%s: invalid group", __func__); 206 return (-1); 207 } 208 ifgr.ifgr_attrib.ifg_carp_demoted = demote; 209 210 if ((res = ioctl(s, SIOCSIFGATTR, (caddr_t)&ifgr)) == -1) 211 log_warn("%s: unable to %s the demote state " 212 "of group '%s'", __func__, 213 (demote > 0) ? "increment" : "decrement", group); 214 else 215 log_info("%s the demote state of group '%s'", 216 (demote > 0) ? "incremented" : "decremented", group); 217 218 close(s); 219 return (res); 220 } 221