control.c revision 1.9
1/* $OpenBSD: control.c,v 1.9 2004/01/04 19:39:46 henning Exp $ */ 2 3/* 4 * Copyright (c) 2003 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/types.h> 20#include <sys/stat.h> 21#include <sys/socket.h> 22#include <sys/un.h> 23#include <errno.h> 24#include <stdlib.h> 25#include <string.h> 26#include <unistd.h> 27 28#include "bgpd.h" 29#include "session.h" 30 31#define CONTROL_BACKLOG 5 32 33struct { 34 int fd; 35} control_state; 36 37struct ctl_conn *control_connbyfd(int); 38 39int 40control_init(void) 41{ 42 struct sockaddr_un sun; 43 int fd; 44 mode_t old_umask; 45 46 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 47 log_err("control_init: socket"); 48 return (-1); 49 } 50 51 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 52 bzero(&sun, sizeof(sun)); 53 sun.sun_family = AF_UNIX; 54 strlcpy(sun.sun_path, SOCKET_NAME, sizeof(sun.sun_path)); 55 56 if (unlink(SOCKET_NAME) == -1) 57 if (errno != ENOENT) { 58 log_err("unlink %s", SOCKET_NAME); 59 return (-1); 60 } 61 62 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { 63 log_err("control_init: bind: %s", SOCKET_NAME); 64 return (-1); 65 } 66 67 if (chmod(SOCKET_NAME, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { 68 log_err("control_init chmod"); 69 return (-1); 70 } 71 72 umask(old_umask); 73 74 control_state.fd = fd; 75 76 return (fd); 77} 78 79int 80control_listen(void) 81{ 82 if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { 83 log_err("control_listen: listen"); 84 return (-1); 85 } 86 87 return (control_state.fd); 88} 89 90void 91control_shutdown(void) 92{ 93 close(control_state.fd); 94} 95 96void 97control_cleanup(void) 98{ 99 unlink(SOCKET_NAME); 100} 101 102void 103control_accept(int listenfd) 104{ 105 int connfd; 106 socklen_t len; 107 struct sockaddr_un sun; 108 uid_t uid; 109 gid_t gid; 110 struct ctl_conn *ctl_conn; 111 112 len = sizeof(sun); 113 if ((connfd = accept(listenfd, 114 (struct sockaddr *)&sun, &len)) == -1) { 115 if (errno == EWOULDBLOCK || errno == EINTR) 116 return; 117 else 118 log_err("session_control_accept"); 119 } 120 121 if (getpeereid(connfd, &uid, &gid) == -1) { 122 log_err("session_control_accept"); 123 return; 124 } 125 126 if (uid) { 127 log_err("Connection to control socket with uid %ld", uid); 128 return; 129 } 130 131 if ((ctl_conn = malloc(sizeof(struct ctl_conn))) == NULL) { 132 log_err("session_control_accept"); 133 return; 134 } 135 136 imsg_init(&ctl_conn->ibuf, connfd); 137 138 TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entries); 139} 140 141struct ctl_conn * 142control_connbyfd(int fd) 143{ 144 struct ctl_conn *c; 145 146 for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.sock != fd; 147 c = TAILQ_NEXT(c, entries)) 148 ; /* nothing */ 149 150 return (c); 151} 152 153void 154control_close(int fd) 155{ 156 struct ctl_conn *c; 157 158 if ((c = control_connbyfd(fd)) == NULL) { 159 log_err("control_close: fd %d: not found", fd); 160 return; 161 } 162 163 TAILQ_REMOVE(&ctl_conns, c, entries); 164 165 close(c->ibuf.sock); 166 free(c); 167} 168 169int 170control_dispatch_msg(struct pollfd *pfd, int i) 171{ 172 struct imsg imsg; 173 struct ctl_conn *c; 174 int n; 175 struct peer *p; 176 struct bgpd_addr *addr; 177 178 if ((c = control_connbyfd(pfd->fd)) == NULL) { 179 log_err("control_dispatch_msg: fd %d: not found", pfd->fd); 180 return (0); 181 } 182 183 if (imsg_read(&c->ibuf) <= 0) { 184 control_close(pfd->fd); 185 return (1); 186 } 187 188 for (;;) { 189 if ((n = imsg_get(&c->ibuf, &imsg)) == -1) { 190 control_close(pfd->fd); 191 return (1); 192 } 193 194 if (n == 0) 195 break; 196 197 switch (imsg.hdr.type) { 198 case IMSG_CTL_SHOW_NEIGHBOR: 199 if (imsg.hdr.len == IMSG_HEADER_SIZE + 200 sizeof(struct bgpd_addr)) { 201 addr = imsg.data; 202 p = getpeerbyip(addr->v4.s_addr); 203 if (p != NULL) 204 imsg_compose(&c->ibuf, 205 IMSG_CTL_SHOW_NEIGHBOR, 206 0, p, sizeof(struct peer)); 207 } else 208 for (p = peers; p != NULL; p = p->next) 209 imsg_compose(&c->ibuf, 210 IMSG_CTL_SHOW_NEIGHBOR, 211 0, p, sizeof(struct peer)); 212 imsg_compose(&c->ibuf, IMSG_CTL_END, 0, NULL, 0); 213 break; 214 case IMSG_CTL_RELOAD: 215 imsg_compose_parent(IMSG_CTL_RELOAD, 0, NULL, 0); 216 break; 217 default: 218 break; 219 } 220 imsg_free(&imsg); 221 } 222 223 return (0); 224} 225