diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 20 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 20 | ||||
-rw-r--r-- | usr.sbin/bgpd/buffer.c | 29 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 50 | ||||
-rw-r--r-- | usr.sbin/bgpd/imsg.c | 70 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 64 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 3 |
7 files changed, 188 insertions, 68 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index bce647303fc..3cfcafbd986 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.95 2004/06/06 17:38:10 henning Exp $ */ +/* $OpenBSD: bgpd.c,v 1.96 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -176,22 +176,24 @@ main(int argc, char *argv[]) log_info("startup"); - if (pipe(pipe_m2s) == -1) - fatal("pipe"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_m2s) == -1) + fatal("socketpair"); if (fcntl(pipe_m2s[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(pipe_m2s[1], F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); - if (pipe(pipe_m2r) == -1) - fatal("pipe"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_m2r) == -1) + fatal("socketpair"); if (fcntl(pipe_m2r[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(pipe_m2r[1], F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); - if (pipe(pipe_s2r) == -1) - fatal("pipe"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_s2r) == -1) + fatal("socketpair"); if (fcntl(pipe_s2r[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(pipe_s2r[1], F_SETFL, O_NONBLOCK) == -1) fatal("fcntl"); + prepare_listeners(&conf); + /* fork children */ rde_pid = rde_main(&conf, &net_l, rules_l, &mrt_l, pipe_m2r, pipe_s2r); io_pid = session_main(&conf, peer_l, &net_l, rules_l, &mrt_l, @@ -382,6 +384,8 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, return (-1); } + prepare_listeners(conf); + if (imsg_compose(&ibuf_se, IMSG_RECONF_CONF, 0, conf, sizeof(struct bgpd_config)) == -1) return (-1); @@ -407,7 +411,7 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, free(r); } while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { - if (imsg_compose(&ibuf_se, IMSG_RECONF_LISTENER, 0, + if (imsg_compose_fdpass(&ibuf_se, IMSG_RECONF_LISTENER, la->fd, la, sizeof(struct listen_addr)) == -1) return (-1); TAILQ_REMOVE(conf->listen_addrs, la, entry); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 967c45d1de2..d4d34ada083 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.126 2004/06/06 17:38:10 henning Exp $ */ +/* $OpenBSD: bgpd.h,v 1.127 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -83,6 +83,7 @@ struct buf { ssize_t size; ssize_t wpos; ssize_t rpos; + int fd; }; struct msgbuf { @@ -109,6 +110,7 @@ struct bgpd_addr { }; #define DEFAULT_LISTENER 0x01 +#define LISTENER_LISTENING 0x02 struct listen_addr { TAILQ_ENTRY(listen_addr) entry; @@ -238,11 +240,17 @@ struct network { #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define MAX_IMSGSIZE 8192 -struct imsgbuf { +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; int fd; - pid_t pid; - struct buf_read r; - struct msgbuf w; +}; + +struct imsgbuf { + int fd; + pid_t pid; + TAILQ_HEAD(fds, imsg_fd) fds; + struct buf_read r; + struct msgbuf w; }; enum imsg_type { @@ -565,11 +573,13 @@ int imsg_read(struct imsgbuf *); int imsg_get(struct imsgbuf *, struct imsg *); int imsg_compose(struct imsgbuf *, int, u_int32_t, void *, u_int16_t); int imsg_compose_pid(struct imsgbuf *, int, pid_t, void *, u_int16_t); +int imsg_compose_fdpass(struct imsgbuf *, int, int, void *, u_int16_t); struct buf *imsg_create(struct imsgbuf *, int, u_int32_t, u_int16_t); struct buf *imsg_create_pid(struct imsgbuf *, int, pid_t, u_int16_t); int imsg_add(struct buf *, void *, u_int16_t); int imsg_close(struct imsgbuf *, struct buf *); void imsg_free(struct imsg *); +int imsg_get_fd(struct imsgbuf *); /* kroute.c */ int kr_init(int); diff --git a/usr.sbin/bgpd/buffer.c b/usr.sbin/bgpd/buffer.c index 4d91dc05434..087cc0e4f69 100644 --- a/usr.sbin/bgpd/buffer.c +++ b/usr.sbin/bgpd/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.18 2004/04/29 19:56:04 deraadt Exp $ */ +/* $OpenBSD: buffer.c,v 1.19 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -45,6 +45,7 @@ buf_open(ssize_t len) return (NULL); } buf->size = len; + buf->fd = -1; return (buf); } @@ -142,17 +143,36 @@ msgbuf_write(struct msgbuf *msgbuf) struct buf *buf, *next; int i = 0; ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(int))]; bzero(&iov, sizeof(iov)); + bzero(&msg, sizeof(msg)); TAILQ_FOREACH(buf, &msgbuf->bufs, entries) { if (i >= IOV_MAX) break; iov[i].iov_base = buf->buf + buf->rpos; iov[i].iov_len = buf->size - buf->rpos; i++; + if (buf->fd != -1) + break; + } + + msg.msg_iov = iov; + msg.msg_iovlen = i; + + if (buf != NULL && buf->fd != -1) { + msg.msg_control = (caddr_t)cmsgbuf; + msg.msg_controllen = CMSG_LEN(sizeof(int)); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = buf->fd; } - if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { if (errno == EAGAIN) /* cannot write immediately */ return (0); else @@ -164,6 +184,11 @@ msgbuf_write(struct msgbuf *msgbuf) return (-2); } + if (buf != NULL && buf->fd != -1) { + shutdown(buf->fd, SHUT_RDWR); + close(buf->fd); + } + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; buf = next) { next = TAILQ_NEXT(buf, entries); diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index 151f1f515a7..b5f67b8e951 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.38 2004/06/06 17:38:10 henning Exp $ */ +/* $OpenBSD: config.c,v 1.39 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -224,3 +224,51 @@ host_v6(const char *s, struct bgpd_addr *h) return (0); } + +void +prepare_listeners(struct bgpd_config *conf) +{ + struct listen_addr *la; + int opt = 1; + + if (TAILQ_EMPTY(conf->listen_addrs)) { + if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) + fatal("setup_listeners calloc"); + la->fd = -1; + la->flags = DEFAULT_LISTENER; + la->sa.ss_len = sizeof(struct sockaddr_in); + ((struct sockaddr_in *)&la->sa)->sin_family = AF_INET; + ((struct sockaddr_in *)&la->sa)->sin_addr.s_addr = + htonl(INADDR_ANY); + ((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT); + TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); + + if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) + fatal("setup_listeners calloc"); + la->fd = -1; + la->flags = DEFAULT_LISTENER; + la->sa.ss_len = sizeof(struct sockaddr_in6); + ((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT); + TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); + } + + TAILQ_FOREACH(la, conf->listen_addrs, entry) { + if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM, + IPPROTO_TCP)) == -1) + fatal("socket"); + + opt = 1; + if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEPORT, + &opt, sizeof(opt)) == -1) + fatal("setsockopt SO_REUSEPORT"); + + if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) == + -1) { + log_warn("cannot bind to %s", + log_sockaddr((struct sockaddr *)&la->sa)); + close(la->fd); + la->fd = -1; + } + } +} diff --git a/usr.sbin/bgpd/imsg.c b/usr.sbin/bgpd/imsg.c index eb81ad58b7b..20738c25058 100644 --- a/usr.sbin/bgpd/imsg.c +++ b/usr.sbin/bgpd/imsg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg.c,v 1.25 2004/04/29 19:56:04 deraadt Exp $ */ +/* $OpenBSD: imsg.c,v 1.26 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -17,6 +17,7 @@ */ #include <sys/types.h> +#include <sys/uio.h> #include <errno.h> #include <stdlib.h> @@ -26,7 +27,7 @@ #include "bgpd.h" int imsg_compose_core(struct imsgbuf *, int, u_int32_t, void *, - u_int16_t, pid_t); + u_int16_t, pid_t, int); struct buf *imsg_create_core(struct imsgbuf *, int, u_int32_t, u_int16_t, pid_t); @@ -38,15 +39,29 @@ imsg_init(struct imsgbuf *ibuf, int fd) ibuf->fd = fd; ibuf->w.fd = fd; ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); } int imsg_read(struct imsgbuf *ibuf) { + struct msghdr msg; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE(sizeof(int))]; + struct iovec iov; ssize_t n; + int fd; + struct imsg_fd *ifd; - if ((n = read(ibuf->fd, ibuf->r.buf + ibuf->r.wpos, - sizeof(ibuf->r.buf) - ibuf->r.wpos)) == -1) { + bzero(&msg, sizeof(msg)); + iov.iov_base = ibuf->r.buf + ibuf->r.wpos; + iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { if (errno != EINTR && errno != EAGAIN) { log_warn("imsg_read: pipe read error"); return (-1); @@ -56,6 +71,19 @@ imsg_read(struct imsgbuf *ibuf) ibuf->r.wpos += n; + if ((cmsg = CMSG_FIRSTHDR(&msg)) != NULL) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + fd = (*(int *)CMSG_DATA(cmsg)); + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) + fatal("imsg_read calloc"); + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, entry); + } else + log_warn("imsg_read: got unexpected ctl data lvel %d" + "type %d", cmsg->cmsg_level, cmsg->cmsg_type); + } + return (n); } @@ -98,21 +126,29 @@ imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) int imsg_compose(struct imsgbuf *ibuf, int type, u_int32_t peerid, void *data, - u_int16_t dlen) + u_int16_t datalen) { - return (imsg_compose_core(ibuf, type, peerid, data, dlen, ibuf->pid)); + return (imsg_compose_core(ibuf, type, peerid, data, datalen, + ibuf->pid, -1)); } int imsg_compose_pid(struct imsgbuf *ibuf, int type, pid_t pid, void *data, u_int16_t datalen) { - return (imsg_compose_core(ibuf, type, 0, data, datalen, pid)); + return (imsg_compose_core(ibuf, type, 0, data, datalen, pid, -1)); +} + +int +imsg_compose_fdpass(struct imsgbuf *ibuf, int type, int fd, void *data, + u_int16_t datalen) +{ + return (imsg_compose_core(ibuf, type, 0, data, datalen, ibuf->pid, fd)); } int imsg_compose_core(struct imsgbuf *ibuf, int type, u_int32_t peerid, void *data, - u_int16_t datalen, pid_t pid) + u_int16_t datalen, pid_t pid, int fd) { struct buf *wbuf; struct imsg_hdr hdr; @@ -139,6 +175,8 @@ imsg_compose_core(struct imsgbuf *ibuf, int type, u_int32_t peerid, void *data, return (-1); } + wbuf->fd = fd; + if ((n = buf_close(&ibuf->w, wbuf)) < 0) { log_warnx("imsg_compose: buf_add error"); buf_free(wbuf); @@ -213,3 +251,19 @@ imsg_free(struct imsg *imsg) { free(imsg->data); } + +int +imsg_get_fd(struct imsgbuf *ibuf) +{ + int fd; + struct imsg_fd *ifd; + + if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL) + return (-1); + + fd = ifd->fd; + TAILQ_REMOVE(&ibuf->fds, ifd, entry); + free(ifd); + + return(fd); +} diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index eee00b97f3d..1434556ade9 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.174 2004/06/09 13:01:44 henning Exp $ */ +/* $OpenBSD: session.c,v 1.175 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -114,38 +114,18 @@ setup_listeners(u_int *la_cnt) struct listen_addr *la; u_int cnt = 0; - if (TAILQ_EMPTY(conf->listen_addrs)) { - if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) - fatal("setup_listeners calloc"); - la->fd = -1; - la->flags = DEFAULT_LISTENER; - la->sa.ss_len = sizeof(struct sockaddr_in); - ((struct sockaddr_in *)&la->sa)->sin_family = AF_INET; - ((struct sockaddr_in *)&la->sa)->sin_addr.s_addr = - htonl(INADDR_ANY); - ((struct sockaddr_in *)&la->sa)->sin_port = htons(BGP_PORT); - TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); - - if ((la = calloc(1, sizeof(struct listen_addr))) == NULL) - fatal("setup_listeners calloc"); - la->fd = -1; - la->flags = DEFAULT_LISTENER; - la->sa.ss_len = sizeof(struct sockaddr_in6); - ((struct sockaddr_in6 *)&la->sa)->sin6_family = AF_INET6; - ((struct sockaddr_in6 *)&la->sa)->sin6_port = htons(BGP_PORT); - TAILQ_INSERT_TAIL(conf->listen_addrs, la, entry); - } - TAILQ_FOREACH(la, conf->listen_addrs, entry) { la->reconf = RECONF_NONE; cnt++; - if (la->fd != -1) + if (la->flags & LISTENER_LISTENING) continue; - if ((la->fd = socket(la->sa.ss_family, SOCK_STREAM, - IPPROTO_TCP)) == -1) - fatal("socket"); + if (la->fd == -1) { + log_warn("cannot establish listener on %s: invalid fd", + log_sockaddr((struct sockaddr *)&la->sa)); + continue; + } opt = 1; if (setsockopt(la->fd, IPPROTO_TCP, TCP_MD5SIG, @@ -157,18 +137,6 @@ setup_listeners(u_int *la_cnt) fatal("setsockopt TCP_MD5SIG"); } - if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa.ss_len) == - -1) { - if (errno == EACCES) { - log_warnx("can't establish listener on %s", - log_sockaddr((struct sockaddr *)&la->sa)); - close(la->fd); - la->fd = -1; - return (-1); - } else - fatal("bind"); - } - session_socket_blockmode(la->fd, BM_NONBLOCK); if (listen(la->fd, MAX_BACKLOG)) { @@ -176,6 +144,8 @@ setup_listeners(u_int *la_cnt) fatal("listen"); } + la->flags |= LISTENER_LISTENING; + log_info("listening on %s", log_sockaddr((struct sockaddr *)&la->sa)); } @@ -234,9 +204,6 @@ session_main(struct bgpd_config *config, struct peer *cpeers, setproctitle("session engine"); bgpd_process = PROC_SE; - listener_cnt = 0; - setup_listeners(&listener_cnt); - if (pfkey_init(&sysdep) == -1) fatalx("pfkey setup failed"); @@ -247,6 +214,9 @@ session_main(struct bgpd_config *config, struct peer *cpeers, endpwent(); + listener_cnt = 0; + setup_listeners(&listener_cnt); + signal(SIGTERM, session_sighdlr); signal(SIGINT, session_sighdlr); signal(SIGPIPE, SIG_IGN); @@ -2066,18 +2036,25 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) break; } + if ((nla->fd = imsg_get_fd(ibuf)) == -1) + log_warnx("expected to receive fd for %s " + "but didn't receive any", + log_sockaddr((struct sockaddr *)&la->sa)); + if (la == NULL) { la = calloc(1, sizeof(struct listen_addr)); if (la == NULL) fatal(NULL); memcpy(&la->sa, &nla->sa, sizeof(la->sa)); - la->fd = nla->fd; la->flags = nla->flags; + la->fd = nla->fd; la->reconf = RECONF_REINIT; TAILQ_INSERT_TAIL(nconf->listen_addrs, la, entry); } else { la->reconf = RECONF_KEEP; + shutdown(nla->fd, SHUT_RDWR); + close(nla->fd); } break; case IMSG_RECONF_DONE: @@ -2118,6 +2095,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) (struct sockaddr *)&la->sa)); TAILQ_REMOVE(conf->listen_addrs, la, entry); + shutdown(la->fd, SHUT_RDWR); close(la->fd); free(la); } diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index d224198c37a..61a5a4d8951 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.55 2004/06/09 13:01:44 henning Exp $ */ +/* $OpenBSD: session.h,v 1.56 2004/06/20 17:49:46 henning Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -210,6 +210,7 @@ int parse_config(char *, struct bgpd_config *, struct mrt_head *, /* config.c */ int merge_config(struct bgpd_config *, struct bgpd_config *, struct peer *, struct listen_addrs *); +void prepare_listeners(struct bgpd_config *); /* rde.c */ int rde_main(struct bgpd_config *, struct network_head *, |