From b9decf4304d2204173a8d8a706e003cdde2b1bf7 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Thu, 29 Nov 2012 10:58:30 +0100 Subject: move glougloud to old --- old/glougloud/BUGS.txt | 10 + old/glougloud/Makefile | 12 + old/glougloud/README.txt | 51 +++ old/glougloud/external/README.txt | 8 + old/glougloud/external/imsg-buffer.c | 305 +++++++++++++ old/glougloud/external/imsg.c | 301 +++++++++++++ old/glougloud/external/imsg.h | 118 +++++ old/glougloud/external/imsgev.c | 170 ++++++++ old/glougloud/external/imsgev.h | 49 +++ old/glougloud/external/queue.h | 568 ++++++++++++++++++++++++ old/glougloud/glougloud.c | 487 +++++++++++++++++++++ old/glougloud/glougloud.h | 79 ++++ old/glougloud/server.c | 238 +++++++++++ old/glougloud/user.c | 806 +++++++++++++++++++++++++++++++++++ old/glougloud/util.c | 192 +++++++++ 15 files changed, 3394 insertions(+) create mode 100644 old/glougloud/BUGS.txt create mode 100644 old/glougloud/Makefile create mode 100644 old/glougloud/README.txt create mode 100644 old/glougloud/external/README.txt create mode 100644 old/glougloud/external/imsg-buffer.c create mode 100644 old/glougloud/external/imsg.c create mode 100644 old/glougloud/external/imsg.h create mode 100644 old/glougloud/external/imsgev.c create mode 100644 old/glougloud/external/imsgev.h create mode 100644 old/glougloud/external/queue.h create mode 100644 old/glougloud/glougloud.c create mode 100644 old/glougloud/glougloud.h create mode 100644 old/glougloud/server.c create mode 100644 old/glougloud/user.c create mode 100644 old/glougloud/util.c (limited to 'old/glougloud') diff --git a/old/glougloud/BUGS.txt b/old/glougloud/BUGS.txt new file mode 100644 index 0000000..8380e70 --- /dev/null +++ b/old/glougloud/BUGS.txt @@ -0,0 +1,10 @@ +#0000 TITLE +DESCRIPTION + +=== TODO === + +#0001 fatal() messages should be printed on stderr +see util.c fatal() + + +=== DONE === diff --git a/old/glougloud/Makefile b/old/glougloud/Makefile new file mode 100644 index 0000000..d37dde2 --- /dev/null +++ b/old/glougloud/Makefile @@ -0,0 +1,12 @@ +PROG = glougloud +OBJS = glougloud.o server.o user.o util.o external/imsgev.o external/imsg-buffer.o external/imsg.o +CFLAGS+=-Wall -g +LDFLAGS=-lpcap -levent -lutil + +all: + make $(OBJS) + $(CC) $(OBJS) -o $(PROG) $(LDFLAGS) + +clean: + rm -f $(PROG) *~ *.o external/*.o + diff --git a/old/glougloud/README.txt b/old/glougloud/README.txt new file mode 100644 index 0000000..8a8c702 --- /dev/null +++ b/old/glougloud/README.txt @@ -0,0 +1,51 @@ +glougloud - glouglou daemon, for network traffic visualisation in real time + + +=== Requirements === + +* libglouglou + +Known to work on OpenBSD 5.1 and Linux 3.4 + + +=== Installation === + +git clone git@meg:glouglou + +sudo useradd -d /var/empty/ -s /sbin/nologin _glougloud + + +=== Usage === + +* Run the daemon + +cd glouglou/glougloud/ +sudo ./glougloud + +It logs to /var/log/glougloud. +For the moment it monitors lo0 interface. + +* Connect to the daemon + +nc -vvv -u 127.0.0.1 4430 |hexdump -C + +You get informations of traffic flowing on the monitored interface. + + +=== Notes on architecture and security === + +glougloud is architectured in 3 processes: + * main process, runs as root, opens the capture interfaces with +libpcap and resolves DNS names + * server process, runs as _glougloud user and chrooted in _glougloud +home, listens and accepts or refuses clients connections + * user process, runs as _glougloud user and chrooted in _glougloud +home, parses the captured network traffic and sends a summary to the +connected clients + +The 3 processes exchanges messages througt messages, with OpenBSD imsg +framework. + +Note that glougloud activates extra protections on pcap capture only +on OpenBSD by reimplementing some of libpcap functions, see +glougloud.c my_pcap_open_live() diff --git a/old/glougloud/external/README.txt b/old/glougloud/external/README.txt new file mode 100644 index 0000000..7e7509f --- /dev/null +++ b/old/glougloud/external/README.txt @@ -0,0 +1,8 @@ +- imsg framework, and IPC mechanism from OpenBSD - +imsg-buffer.c +imsg.c +imsg.h +imsgev.c +imsgev.h +- queue implementation, from OpenBSD - +queue.h diff --git a/old/glougloud/external/imsg-buffer.c b/old/glougloud/external/imsg-buffer.c new file mode 100644 index 0000000..9f04757 --- /dev/null +++ b/old/glougloud/external/imsg-buffer.c @@ -0,0 +1,305 @@ +/* $OpenBSD: imsg-buffer.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "imsg.h" + +int ibuf_realloc(struct ibuf *, size_t); +void ibuf_enqueue(struct msgbuf *, struct ibuf *); +void ibuf_dequeue(struct msgbuf *, struct ibuf *); + +struct ibuf * +ibuf_open(size_t len) +{ + struct ibuf *buf; + + if ((buf = calloc(1, sizeof(struct ibuf))) == NULL) + return (NULL); + if ((buf->buf = malloc(len)) == NULL) { + free(buf); + return (NULL); + } + buf->size = buf->max = len; + buf->fd = -1; + + return (buf); +} + +struct ibuf * +ibuf_dynamic(size_t len, size_t max) +{ + struct ibuf *buf; + + if (max < len) + return (NULL); + + if ((buf = ibuf_open(len)) == NULL) + return (NULL); + + if (max > 0) + buf->max = max; + + return (buf); +} + +int +ibuf_realloc(struct ibuf *buf, size_t len) +{ + u_char *b; + + /* on static buffers max is eq size and so the following fails */ + if (buf->wpos + len > buf->max) { + errno = ENOMEM; + return (-1); + } + + b = realloc(buf->buf, buf->wpos + len); + if (b == NULL) + return (-1); + buf->buf = b; + buf->size = buf->wpos + len; + + return (0); +} + +int +ibuf_add(struct ibuf *buf, const void *data, size_t len) +{ + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (-1); + + memcpy(buf->buf + buf->wpos, data, len); + buf->wpos += len; + return (0); +} + +void * +ibuf_reserve(struct ibuf *buf, size_t len) +{ + void *b; + + if (buf->wpos + len > buf->size) + if (ibuf_realloc(buf, len) == -1) + return (NULL); + + b = buf->buf + buf->wpos; + buf->wpos += len; + return (b); +} + +void * +ibuf_seek(struct ibuf *buf, size_t pos, size_t len) +{ + /* only allowed to seek in already written parts */ + if (pos + len > buf->wpos) + return (NULL); + + return (buf->buf + pos); +} + +size_t +ibuf_size(struct ibuf *buf) +{ + return (buf->wpos); +} + +size_t +ibuf_left(struct ibuf *buf) +{ + return (buf->max - buf->wpos); +} + +void +ibuf_close(struct msgbuf *msgbuf, struct ibuf *buf) +{ + ibuf_enqueue(msgbuf, buf); +} + +int +ibuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + + bzero(&iov, sizeof(iov)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - buf->rpos; + i++; + } + +again: + if ((n = writev(msgbuf->fd, iov, i)) == -1) { + if (errno == EAGAIN || errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_free(struct ibuf *buf) +{ + free(buf->buf); + free(buf); +} + +void +msgbuf_init(struct msgbuf *msgbuf) +{ + msgbuf->queued = 0; + msgbuf->fd = -1; + TAILQ_INIT(&msgbuf->bufs); +} + +void +msgbuf_drain(struct msgbuf *msgbuf, size_t n) +{ + struct ibuf *buf, *next; + + for (buf = TAILQ_FIRST(&msgbuf->bufs); buf != NULL && n > 0; + buf = next) { + next = TAILQ_NEXT(buf, entry); + if (buf->rpos + n >= buf->wpos) { + n -= buf->wpos - buf->rpos; + ibuf_dequeue(msgbuf, buf); + } else { + buf->rpos += n; + n = 0; + } + } +} + +void +msgbuf_clear(struct msgbuf *msgbuf) +{ + struct ibuf *buf; + + while ((buf = TAILQ_FIRST(&msgbuf->bufs)) != NULL) + ibuf_dequeue(msgbuf, buf); +} + +int +msgbuf_write(struct msgbuf *msgbuf) +{ + struct iovec iov[IOV_MAX]; + struct ibuf *buf; + unsigned int i = 0; + ssize_t n; + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + bzero(&iov, sizeof(iov)); + bzero(&msg, sizeof(msg)); + TAILQ_FOREACH(buf, &msgbuf->bufs, entry) { + if (i >= IOV_MAX) + break; + iov[i].iov_base = buf->buf + buf->rpos; + iov[i].iov_len = buf->wpos - 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.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + 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; + } + +again: + if ((n = sendmsg(msgbuf->fd, &msg, 0)) == -1) { + if (errno == EAGAIN || errno == EINTR) + goto again; + if (errno == ENOBUFS) + errno = EAGAIN; + return (-1); + } + + if (n == 0) { /* connection closed */ + errno = 0; + return (0); + } + + /* + * assumption: fd got sent if sendmsg sent anything + * this works because fds are passed one at a time + */ + if (buf != NULL && buf->fd != -1) { + close(buf->fd); + buf->fd = -1; + } + + msgbuf_drain(msgbuf, n); + + return (1); +} + +void +ibuf_enqueue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_INSERT_TAIL(&msgbuf->bufs, buf, entry); + msgbuf->queued++; +} + +void +ibuf_dequeue(struct msgbuf *msgbuf, struct ibuf *buf) +{ + TAILQ_REMOVE(&msgbuf->bufs, buf, entry); + + if (buf->fd != -1) + close(buf->fd); + + msgbuf->queued--; + ibuf_free(buf); +} diff --git a/old/glougloud/external/imsg.c b/old/glougloud/external/imsg.c new file mode 100644 index 0000000..05e57c7 --- /dev/null +++ b/old/glougloud/external/imsg.c @@ -0,0 +1,301 @@ +/* $OpenBSD: imsg.c,v 1.2 2012/06/02 21:46:53 gilles Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "imsg.h" + +int imsg_fd_overhead = 0; + +int imsg_get_fd(struct imsgbuf *); + +void +imsg_init(struct imsgbuf *ibuf, int fd) +{ + msgbuf_init(&ibuf->w); + bzero(&ibuf->r, sizeof(ibuf->r)); + ibuf->fd = fd; + ibuf->w.fd = fd; + ibuf->pid = getpid(); + TAILQ_INIT(&ibuf->fds); +} + +ssize_t +imsg_read(struct imsgbuf *ibuf) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int) * 1)]; + } cmsgbuf; + struct iovec iov; + ssize_t n = -1; + int fd; + struct imsg_fd *ifd; + + 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.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL) + return (-1); + +again: + if (getdtablecount() + imsg_fd_overhead + + (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int) + >= getdtablesize()) { + errno = EAGAIN; + return (-1); + } + + if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + if (errno == EMSGSIZE) + goto fail; + if (errno != EINTR && errno != EAGAIN) + goto fail; + goto again; + } + + ibuf->r.wpos += n; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int i; + int j; + + /* + * We only accept one file descriptor. Due to C + * padding rules, our control buffer might contain + * more than one fd, and we must close them. + */ + j = ((char *)cmsg + cmsg->cmsg_len - + (char *)CMSG_DATA(cmsg)) / sizeof(int); + for (i = 0; i < j; i++) { + fd = ((int *)CMSG_DATA(cmsg))[i]; + if (i == 0) { + ifd->fd = fd; + TAILQ_INSERT_TAIL(&ibuf->fds, ifd, + entry); + ifd = NULL; + } else + close(fd); + } + } + /* we do not handle other ctl data level */ + } + +fail: + if (ifd) + free(ifd); + return (n); +} + +ssize_t +imsg_get(struct imsgbuf *ibuf, struct imsg *imsg) +{ + size_t av, left, datalen; + + av = ibuf->r.wpos; + + if (IMSG_HEADER_SIZE > av) + return (0); + + memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr)); + if (imsg->hdr.len < IMSG_HEADER_SIZE || + imsg->hdr.len > MAX_IMSGSIZE) { + errno = ERANGE; + return (-1); + } + if (imsg->hdr.len > av) + return (0); + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE; + if ((imsg->data = malloc(datalen)) == NULL) + return (-1); + + if (imsg->hdr.flags & IMSGF_HASFD) + imsg->fd = imsg_get_fd(ibuf); + else + imsg->fd = -1; + + memcpy(imsg->data, ibuf->r.rptr, datalen); + + if (imsg->hdr.len < av) { + left = av - imsg->hdr.len; + memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left); + ibuf->r.wpos = left; + } else + ibuf->r.wpos = 0; + + return (datalen + IMSG_HEADER_SIZE); +} + +int +imsg_compose(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, void *data, u_int16_t datalen) +{ + struct ibuf *wbuf; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + if (imsg_add(wbuf, data, datalen) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +int +imsg_composev(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + struct ibuf *wbuf; + int i, datalen = 0; + + for (i = 0; i < iovcnt; i++) + datalen += iov[i].iov_len; + + if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL) + return (-1); + + for (i = 0; i < iovcnt; i++) + if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) + return (-1); + + wbuf->fd = fd; + + imsg_close(ibuf, wbuf); + + return (1); +} + +/* ARGSUSED */ +struct ibuf * +imsg_create(struct imsgbuf *ibuf, u_int32_t type, u_int32_t peerid, + pid_t pid, u_int16_t datalen) +{ + struct ibuf *wbuf; + struct imsg_hdr hdr; + + datalen += IMSG_HEADER_SIZE; + if (datalen > MAX_IMSGSIZE) { + errno = ERANGE; + return (NULL); + } + + hdr.type = type; + hdr.flags = 0; + hdr.peerid = peerid; + if ((hdr.pid = pid) == 0) + hdr.pid = ibuf->pid; + if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) { + return (NULL); + } + if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) + return (NULL); + + return (wbuf); +} + +int +imsg_add(struct ibuf *msg, void *data, u_int16_t datalen) +{ + if (datalen) + if (ibuf_add(msg, data, datalen) == -1) { + ibuf_free(msg); + return (-1); + } + return (datalen); +} + +void +imsg_close(struct imsgbuf *ibuf, struct ibuf *msg) +{ + struct imsg_hdr *hdr; + + hdr = (struct imsg_hdr *)msg->buf; + + hdr->flags &= ~IMSGF_HASFD; + if (msg->fd != -1) + hdr->flags |= IMSGF_HASFD; + + hdr->len = (u_int16_t)msg->wpos; + + ibuf_close(&ibuf->w, msg); +} + +void +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); +} + +int +imsg_flush(struct imsgbuf *ibuf) +{ + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) < 0) + return (-1); + return (0); +} + +void +imsg_clear(struct imsgbuf *ibuf) +{ + int fd; + + msgbuf_clear(&ibuf->w); + while ((fd = imsg_get_fd(ibuf)) != -1) + close(fd); +} diff --git a/old/glougloud/external/imsg.h b/old/glougloud/external/imsg.h new file mode 100644 index 0000000..25cc2c4 --- /dev/null +++ b/old/glougloud/external/imsg.h @@ -0,0 +1,118 @@ +/* $OpenBSD: imsg.h,v 1.2 2010/06/23 07:53:55 nicm Exp $ */ + +/* + * Copyright (c) 2006, 2007 Pierre-Yves Ritschard + * Copyright (c) 2006, 2007, 2008 Reyk Floeter + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IMSG_H_ +#define _IMSG_H_ + +/* compat hacks added by laurent */ +#if !defined(__OpenBSD__) +#define IOV_MAX 1024 +#define getdtablecount(x) 3 +#endif + +#define IBUF_READ_SIZE 65535 +#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) +#define MAX_IMSGSIZE 16384 + +struct ibuf { + TAILQ_ENTRY(ibuf) entry; + u_char *buf; + size_t size; + size_t max; + size_t wpos; + size_t rpos; + int fd; +}; + +struct msgbuf { + TAILQ_HEAD(, ibuf) bufs; + u_int32_t queued; + int fd; +}; + +struct ibuf_read { + u_char buf[IBUF_READ_SIZE]; + u_char *rptr; + size_t wpos; +}; + +struct imsg_fd { + TAILQ_ENTRY(imsg_fd) entry; + int fd; +}; + +struct imsgbuf { + TAILQ_HEAD(, imsg_fd) fds; + struct ibuf_read r; + struct msgbuf w; + int fd; + pid_t pid; +}; + +#define IMSGF_HASFD 1 + +struct imsg_hdr { + u_int32_t type; + u_int16_t len; + u_int16_t flags; + u_int32_t peerid; + u_int32_t pid; +}; + +struct imsg { + struct imsg_hdr hdr; + int fd; + void *data; +}; + + +/* buffer.c */ +struct ibuf *ibuf_open(size_t); +struct ibuf *ibuf_dynamic(size_t, size_t); +int ibuf_add(struct ibuf *, const void *, size_t); +void *ibuf_reserve(struct ibuf *, size_t); +void *ibuf_seek(struct ibuf *, size_t, size_t); +size_t ibuf_size(struct ibuf *); +size_t ibuf_left(struct ibuf *); +void ibuf_close(struct msgbuf *, struct ibuf *); +int ibuf_write(struct msgbuf *); +void ibuf_free(struct ibuf *); +void msgbuf_init(struct msgbuf *); +void msgbuf_clear(struct msgbuf *); +int msgbuf_write(struct msgbuf *); +void msgbuf_drain(struct msgbuf *, size_t); + +/* imsg.c */ +void imsg_init(struct imsgbuf *, int); +ssize_t imsg_read(struct imsgbuf *); +ssize_t imsg_get(struct imsgbuf *, struct imsg *); +int imsg_compose(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, void *, u_int16_t); +int imsg_composev(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + int, const struct iovec *, int); +struct ibuf *imsg_create(struct imsgbuf *, u_int32_t, u_int32_t, pid_t, + u_int16_t); +int imsg_add(struct ibuf *, void *, u_int16_t); +void imsg_close(struct imsgbuf *, struct ibuf *); +void imsg_free(struct imsg *); +int imsg_flush(struct imsgbuf *); +void imsg_clear(struct imsgbuf *); + +#endif diff --git a/old/glougloud/external/imsgev.c b/old/glougloud/external/imsgev.c new file mode 100644 index 0000000..6b92d79 --- /dev/null +++ b/old/glougloud/external/imsgev.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2009 Eric Faurot + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "imsgev.h" + +void imsgev_add(struct imsgev *); +void imsgev_dispatch(int, short, void *); +void imsgev_disconnect(struct imsgev *, int); + +void +imsgev_init(struct imsgev *iev, int fd, void *data, + void (*callback)(struct imsgev *, int, struct imsg *), + void (*needfd)(struct imsgev *)) +{ + imsg_init(&iev->ibuf, fd); + iev->terminate = 0; + + iev->data = data; + iev->handler = imsgev_dispatch; + iev->callback = callback; + iev->needfd = needfd; + + iev->events = EV_READ; + event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); + event_add(&iev->ev, NULL); +} + +int +imsgev_compose(struct imsgev *iev, u_int16_t type, u_int32_t peerid, + uint32_t pid, int fd, void *data, u_int16_t datalen) +{ + int r; + + r = imsg_compose(&iev->ibuf, type, peerid, pid, fd, data, datalen); + if (r != -1) + imsgev_add(iev); + + return (r); +} + +void +imsgev_close(struct imsgev *iev) +{ + iev->terminate = 1; + imsgev_add(iev); +} + +void +imsgev_clear(struct imsgev *iev) +{ + event_del(&iev->ev); + msgbuf_clear(&iev->ibuf.w); + close(iev->ibuf.fd); +} + +void +imsgev_add(struct imsgev *iev) +{ + short events = 0; + + if (!iev->terminate) + events = EV_READ; + if (iev->ibuf.w.queued || iev->terminate) + events |= EV_WRITE; + + /* optimization: skip event_{del/set/add} if already set */ + if (events == iev->events) + return; + + iev->events = events; + event_del(&iev->ev); + event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); + event_add(&iev->ev, NULL); +} + +void +imsgev_dispatch(int fd, short ev, void *humppa) +{ + struct imsgev *iev = humppa; + struct imsgbuf *ibuf = &iev->ibuf; + struct imsg imsg; + ssize_t n; + + iev->events = 0; + + if (ev & EV_READ) { + if ((n = imsg_read(ibuf)) == -1) { + /* if we don't have enough fds, free one up and retry */ + if (errno == EAGAIN) { + iev->needfd(iev); + n = imsg_read(ibuf); + } + + if (n == -1) { + imsgev_disconnect(iev, IMSGEV_EREAD); + return; + } + } + if (n == 0) { + /* + * Connection is closed for reading, and we assume + * it is also closed for writing, so we error out + * if write data is pending. + */ + imsgev_disconnect(iev, + (iev->ibuf.w.queued) ? IMSGEV_EWRITE : IMSGEV_DONE); + return; + } + } + + if (ev & EV_WRITE) { + /* + * We wanted to write data out but the connection is either + * closed, or some error occured. Both case are not recoverable + * from the imsg perspective, so we treat it as a WRITE error. + */ + if ((n = msgbuf_write(&ibuf->w)) != 1) { + imsgev_disconnect(iev, IMSGEV_EWRITE); + return; + } + } + + while (iev->terminate == 0) { + if ((n = imsg_get(ibuf, &imsg)) == -1) { + imsgev_disconnect(iev, IMSGEV_EIMSG); + return; + } + if (n == 0) + break; + iev->callback(iev, IMSGEV_IMSG, &imsg); + imsg_free(&imsg); + } + + if (iev->terminate && iev->ibuf.w.queued == 0) { + imsgev_disconnect(iev, IMSGEV_DONE); + return; + } + + imsgev_add(iev); +} + +void +imsgev_disconnect(struct imsgev *iev, int code) +{ + iev->callback(iev, code, NULL); +} diff --git a/old/glougloud/external/imsgev.h b/old/glougloud/external/imsgev.h new file mode 100644 index 0000000..a0d0947 --- /dev/null +++ b/old/glougloud/external/imsgev.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009 Eric Faurot + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __IMSGEV_H__ +#define __IMSGEV_H__ + +#include +#include "imsg.h" + +#define IMSG_LEN(m) ((m)->hdr.len - IMSG_HEADER_SIZE) + +struct imsgev { + struct imsgbuf ibuf; + void (*handler)(int, short, void *); + struct event ev; + void *data; + short events; + int terminate; + void (*callback)(struct imsgev *, int, struct imsg *); + void (*needfd)(struct imsgev *); +}; + +#define IMSGEV_IMSG 0 +#define IMSGEV_DONE 1 +#define IMSGEV_EREAD 2 +#define IMSGEV_EWRITE 3 +#define IMSGEV_EIMSG 4 + +void imsgev_init(struct imsgev *, int, void *, void (*)(struct imsgev *, + int, struct imsg *), void (*)(struct imsgev *)); +int imsgev_compose(struct imsgev *, u_int16_t, u_int32_t, u_int32_t, int, + void *, u_int16_t); +void imsgev_close(struct imsgev *); +void imsgev_clear(struct imsgev *); + +#endif /* __IMSGEV_H__ */ diff --git a/old/glougloud/external/queue.h b/old/glougloud/external/queue.h new file mode 100644 index 0000000..622301d --- /dev/null +++ b/old/glougloud/external/queue.h @@ -0,0 +1,568 @@ +/* $OpenBSD: queue.h,v 1.36 2012/04/11 13:29:14 naddy Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = CIRCLEQ_LAST(head, headname); \ + (var) != CIRCLEQ_END(head) && \ + ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/old/glougloud/glougloud.c b/old/glougloud/glougloud.c new file mode 100644 index 0000000..49a1608 --- /dev/null +++ b/old/glougloud/glougloud.c @@ -0,0 +1,487 @@ +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glougloud.h" +#include "external/imsgev.h" +#if defined(__OpenBSD__) +#include "pcap-int.h" +#endif + +struct server_proc { + pid_t pid; + int fd[2]; + struct imsgev iev; +}; +struct user_proc { + pid_t pid; + int fd[2]; + struct imsgev iev; +}; +enum user_status { + USER_REQUESTED, + USER_ACCEPTED +}; +struct user { + LIST_ENTRY(user) entry; + struct sockaddr_in addr; + enum user_status status; +}; + +// XXX CONF +#define PCAP_INTERFACE "lo" +#define PCAP_SNAPLEN 100 +#define PCAP_FILTER "not port 4430 and not port 53" + +static void imsgev_server(struct imsgev *, int, struct imsg *); +static void imsgev_user(struct imsgev *, int, struct imsg *); +static void imsgev_server_needfd(struct imsgev *); +static void imsgev_user_needfd(struct imsgev *); + +struct server_proc *srv_proc; +struct user_proc *usr_proc; +LIST_HEAD(, user) usr_list; +int net_socket; + +#if defined(__OPENBSD__) +void __dead +#else +void +#endif +usage(void) +{ + extern char *__progname; + + fprintf(stderr, "usage: %s [-vi]", + __progname); + exit(1); +} + +static void +sig_handler(int sig, short why, void *data) +{ + log_info("got signal %d", sig); + if (sig == SIGINT || sig == SIGTERM) + event_loopexit(NULL); +} + +/* + * reimplement pcap_open_live with more restrictions on the bpf fd : + * - open device read only + * - lock the fd + * based on OpenBSD tcpdump, privsep_pcap.c v1.16 + */ + +static pcap_t * +my_pcap_open_live(const char *dev, int slen, int promisc, int to_ms, + char *ebuf, u_int dlt, u_int dirfilt) +{ +#if defined(__OpenBSD__) + struct bpf_version bv; + u_int v; + pcap_t *p; + char bpf[sizeof "/dev/bpf0000000000"]; + int fd, n = 0; + struct ifreq ifr; + + p = xmalloc(sizeof(*p)); + bzero(p, sizeof(*p)); + + /* priv part */ + + do { + snprintf(bpf, sizeof(bpf), "/dev/bpf%d", n++); + fd = open(bpf, O_RDONLY); + } while (fd < 0 && errno == EBUSY); + if (fd < 0) + return NULL; + + v = 32768; /* XXX this should be a user-accessible hook */ + ioctl(fd, BIOCSBLEN, &v); + + strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, &ifr) < 0) + return NULL; + + if (dlt != (u_int) -1 && ioctl(fd, BIOCSDLT, &dlt)) + return NULL; + + if (promisc) + /* this is allowed to fail */ + ioctl(fd, BIOCPROMISC, NULL); + if (ioctl(fd, BIOCSDIRFILT, &dirfilt) < 0) + return NULL; + + /* lock the descriptor */ + if (ioctl(fd, BIOCLOCK, NULL) < 0) + return NULL; + + /* end of priv part */ + + /* fd is locked, can only use 'safe' ioctls */ + if (ioctl(fd, BIOCVERSION, &bv) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCVERSION: %s", + pcap_strerror(errno)); + return NULL; + } + + if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, + "kernel bpf filter out of date"); + return NULL; + } + + p->fd = fd; + p->snapshot = slen; + + /* Get the data link layer type. */ + if (ioctl(fd, BIOCGDLT, &v) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGDLT: %s", + pcap_strerror(errno)); + return NULL; + } +#if _BSDI_VERSION - 0 >= 199510 + /* The SLIP and PPP link layer header changed in BSD/OS 2.1 */ + switch (v) { + + case DLT_SLIP: + v = DLT_SLIP_BSDOS; + break; + + case DLT_PPP: + v = DLT_PPP_BSDOS; + break; + } +#endif + p->linktype = v; + + /* XXX hack from tcpdump */ + if (p->linktype == DLT_PFLOG && p->snapshot < 160) + p->snapshot = 160; + + /* set timeout */ + if (to_ms != 0) { + struct timeval to; + to.tv_sec = to_ms / 1000; + to.tv_usec = (to_ms * 1000) % 1000000; + if (ioctl(p->fd, BIOCSRTIMEOUT, &to) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCSRTIMEOUT: %s", + pcap_strerror(errno)); + return NULL; + } + } + + if (ioctl(fd, BIOCGBLEN, &v) < 0) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "BIOCGBLEN: %s", + pcap_strerror(errno)); + return NULL; + } + p->bufsize = v; + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", + pcap_strerror(errno)); + return NULL; + } + return p; +#else /* defined(__OpenBSD__) */ + return pcap_open_live(dev, slen, promisc, to_ms, ebuf); +#endif +} + +int +main(int argc, char **argv) +{ + struct sockaddr_in sock_addr; + struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; + char errbuf[PCAP_ERRBUF_SIZE]; + struct bpf_program bprog; + pcap_t *pcap; + int loglevel = 0, logpinvalid = 0; + int op; + int sock_on = 1; + + if (geteuid() != 0) + errx(1, "need root privileges"); + + while ((op = getopt(argc, argv, "hvi")) != -1) { + switch (op) { + case 'h': + usage(); + /* NOTREACHED */ + case 'v': + loglevel++; + break; + case 'i': + logpinvalid = 1; + break; + default: + usage(); + /* NOTREACHED */ + } + } + + log_init(loglevel, logpinvalid); + event_init(); + + net_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (net_socket < 0) + fatal("server: socket failed"); + setsockopt(net_socket, SOL_SOCKET, SO_REUSEADDR, + &sock_on, sizeof(sock_on)); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); + sock_addr.sin_port = htons(4430); + if (bind(net_socket, (struct sockaddr *)&sock_addr, + sizeof(sock_addr)) != 0) + fatal("server: socket bind failed, %s", strerror(errno)); + fd_nonblock(net_socket); + + srv_proc = xmalloc(sizeof(struct server_proc)); + socketpair_prepare(srv_proc->fd); + srv_proc->pid = server_init(srv_proc->fd); + close(srv_proc->fd[1]); + imsgev_init(&srv_proc->iev, srv_proc->fd[0], NULL, imsgev_server, imsgev_server_needfd); + + pcap = my_pcap_open_live(PCAP_INTERFACE, PCAP_SNAPLEN, 1, PCAP_TO, errbuf, -1, 0); + if (pcap == NULL) + fatal("capture: pcap_open_live failed on interface %s\n" + "with snaplen %d : %s", + PCAP_INTERFACE, PCAP_SNAPLEN, errbuf); + if (pcap_compile(pcap, &bprog, PCAP_FILTER, 0, 0) < 0) + fatal("capture: pcap_compile failed with filter %s : %s", + PCAP_FILTER, pcap_geterr(pcap)); + if (pcap_setfilter(pcap, &bprog) < 0) + fatal("capture: pcap_setfilter failed : %s", + pcap_geterr(pcap)); + + usr_proc = xmalloc(sizeof(struct user_proc)); + socketpair_prepare(usr_proc->fd); + usr_proc->pid = user_init(usr_proc->fd, pcap); + close(usr_proc->fd[1]); + imsgev_init(&usr_proc->iev, usr_proc->fd[0], NULL, imsgev_user, imsgev_user_needfd); + + signal_set(&ev_sigint, SIGINT, sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + log_info("entering event loop"); + event_dispatch(); + + log_info("exiting"); + exit(0); +} + +static struct user * +finduser(struct sockaddr_in *remote) { + struct user *usr; + struct sockaddr_in *u; + + LIST_FOREACH(usr, &usr_list, entry) { + u = &usr->addr; + if (u->sin_addr.s_addr == remote->sin_addr.s_addr && + u->sin_port == remote->sin_port) + return usr; + } + return NULL; +} + +static void +srvconn(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_srvconn *req; + struct imsg_srvconn res; + struct imsg_usrconn req2; + struct user *usr; + + req = imsg->data; + + if (req->deco) { + log_tmp("srvconn deco"); + usr = finduser(&req->addr); + if (!usr) + fatal("trying to deco an inexistant user !"); + + addrcpy(&req2.addr, &usr->addr); + req2.deco = 1; + imsgev_compose(&usr_proc->iev, IMSG_USRCONN_REQ, 0, 0, -1, + &req2, sizeof(req2)); + + LIST_REMOVE(usr, entry); + free(usr); + + return; + } + + if (req->addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { + log_tmp("srvconn accepted"); + + usr = xmalloc(sizeof(struct user)); + addrcpy(&usr->addr, &req->addr); + usr->status = USER_REQUESTED; + LIST_INSERT_HEAD(&usr_list, usr, entry); + + addrcpy(&req2.addr, &req->addr); + req2.deco = 0; + imsgev_compose(&usr_proc->iev, IMSG_USRCONN_REQ, 0, 0, -1, + &req2, sizeof(req2)); + } + else + { + log_tmp("srvconn refused"); + res.ok = 0; + addrcpy(&res.addr, &req->addr); + imsgev_compose(iev, IMSG_SRVCONN_RES, 0, 0, -1, + &res, sizeof(res)); + } + +} + +static void +imsgev_server(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + log_debug("%s, got imsg %i on fd %i", + __func__, imsg->hdr.type, iev->ibuf.fd); + switch (imsg->hdr.type) { + case IMSG_SRVCONN_REQ: + srvconn(iev, imsg); + break; + default: + fatal("%s, unexpected imsg %d", + __func__, imsg->hdr.type); + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("imsgev server read/write error"); + /* NOTREACHED */ + break; + case IMSGEV_DONE: + event_loopexit(NULL); + break; + } +} + +static void +usrconn(struct imsgev *iev, struct imsg *imsg) +{ + struct user *usr; + struct imsg_usrconn *res; + struct imsg_srvconn res2; + + res = imsg->data; + + usr = finduser(&res->addr); + if (!usr || usr->status != USER_REQUESTED) + fatal("received usrconn result that wasn't initiated !"); + usr->status = USER_ACCEPTED; + + addrcpy(&res2.addr, &res->addr); + res2.ok = 1; + imsgev_compose(&srv_proc->iev, IMSG_SRVCONN_RES, 0, 0, -1, + &res2, sizeof(res2)); +} + +/* XXX drop imsg when msgbuf->queued is too high ? */ +/* XXX review that func for correctness and security */ +static void +usrdns(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_usrdns_req *req; + struct imsg_usrdns_res res; + struct hostent *ent; + int len; + char *name; + extern int h_errno; + struct in_addr addr; + + req = imsg->data; + + res.addr.s_addr = req->addr.s_addr; + addr.s_addr = htonl(req->addr.s_addr); + ent = gethostbyaddr(&addr, sizeof(addr), AF_INET); + if (ent) { + len = strlen(ent->h_name); + if (len > DNSNAME_MAX) + name = ent->h_name - DNSNAME_MAX; /* keep right part */ + else + name = ent->h_name; + strncpy(res.name, name, sizeof(res.name)); + } else { + log_debug("usrdns failed for %x : %s", + addr, hstrerror(h_errno)); + res.name[0] = '\0'; + } + + imsgev_compose(&usr_proc->iev, IMSG_USRDNS_RES, 0, 0, -1, + &res, sizeof(res)); +} + +static void +imsgev_user(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + log_debug("%s, got imsg %i on fd %i", + __func__, imsg->hdr.type, iev->ibuf.fd); + switch (imsg->hdr.type) { + case IMSG_USRCONN_RES: + usrconn(iev, imsg); + break; + case IMSG_USRDNS_REQ: + usrdns(iev, imsg); + break; + default: + fatal("%s, unexpected imsg %d", + __func__, imsg->hdr.type); + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("imsgev user read/write error"); + /* NOTREACHED */ + break; + case IMSGEV_DONE: + event_loopexit(NULL); + break; + } +} + +static void +imsgev_server_needfd(struct imsgev *iev) +{ + fatal("imsgev_server_needfd"); +} + +static void +imsgev_user_needfd(struct imsgev *iev) +{ + fatal("imsgev_user_needfd"); +} diff --git a/old/glougloud/glougloud.h b/old/glougloud/glougloud.h new file mode 100644 index 0000000..c4f0a4a --- /dev/null +++ b/old/glougloud/glougloud.h @@ -0,0 +1,79 @@ +#include + +#include + +#include +#include + +#include + +#include "external/queue.h" + +#if !defined(__OpenBSD__) +#define setproctitle(x) {} +#endif + +#define GLOUGLOUD_USER "_glougloud" +#define PCAP_COUNT 20 +#define PCAP_TO 300 + +/* ipc */ + +enum imsg_type { + IMSG_SRVCONN_REQ, + IMSG_SRVCONN_RES, + IMSG_USRCONN_REQ, + IMSG_USRCONN_RES, + IMSG_USRDNS_REQ, + IMSG_USRDNS_RES +}; + +/* XXX restore the _req _res structs, so that we have less bytes going on + * the pipe */ +struct imsg_srvconn { + struct sockaddr_in addr; + u_short ok; + u_short deco; +}; +struct imsg_usrconn { + struct sockaddr_in addr; + u_short ok; + u_short deco; +}; +struct imsg_usrdns_req { + struct in_addr addr; +}; +struct imsg_usrdns_res { + struct in_addr addr; + char name[DNSNAME_MAX]; +}; + +/* glougloud.c */ + +extern int net_socket; + +/* server.c */ + +int server_init(int *); + +/* user.c */ + +int user_init(int *, pcap_t *pcap); + +/* util.c */ + +void log_init(int, int); +void log_pinvalid(const char *, ...); +void log_tmp(const char *, ...); +void log_debug(const char *, ...); +void log_info(const char *, ...); +void log_warn(const char *, ...); +void fatal(const char *, ...); + +void *xmalloc(size_t); +void *xcalloc(size_t, size_t); +void fd_nonblock(int); +void droppriv(); +void addrcpy(struct sockaddr_in *, struct sockaddr_in *); +void socketpair_prepare(int *); + diff --git a/old/glougloud/server.c b/old/glougloud/server.c new file mode 100644 index 0000000..4fb0be6 --- /dev/null +++ b/old/glougloud/server.c @@ -0,0 +1,238 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "glougloud.h" +#include "external/imsgev.h" + +#define USER_TIMEOUT 300 +#define USERTIMER 10 + +struct server { + struct imsgev iev; + struct event ev; + + struct event usrtimer_ev; + struct timeval usrtimer_tv; + time_t time; +}; +enum user_status { + USER_REQUESTED, + USER_ACCEPTED, + USER_REFUSED +}; +struct user { + LIST_ENTRY(user) entry; + struct sockaddr_in addr; + enum user_status status; + time_t lastseen; +}; + +static void imsgev_main(struct imsgev *, int, struct imsg *); +static void imsgev_main_needfd(struct imsgev *); +static void receive(int, short, void *); +static void ev_usrtimer(int, short, void *); + +struct server *srv; +LIST_HEAD(, user) usr_list; + +static void +sig_handler(int sig, short why, void *data) +{ + log_info("server: got signal %d", sig); + if (sig == SIGINT || sig == SIGTERM) + event_loopexit(NULL); +} + +int +server_init(int fd[2]) +{ + struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; + int pid; + + pid = fork(); + if (pid < 0) + fatal("server fork"); + if (pid > 0) + return pid; + + setproctitle("server"); + event_init(); + close(fd[0]); + + signal_set(&ev_sigint, SIGINT, sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + srv = xmalloc(sizeof(struct server)); + imsgev_init(&srv->iev, fd[1], NULL, imsgev_main, imsgev_main_needfd); + srv->time = time(NULL); + + event_set(&srv->ev, net_socket, EV_READ|EV_PERSIST, receive, NULL); + event_add(&srv->ev, NULL); + + srv->usrtimer_tv.tv_sec = USERTIMER; + srv->usrtimer_tv.tv_usec = 0; + evtimer_set(&srv->usrtimer_ev, ev_usrtimer, NULL); + if (event_add(&srv->usrtimer_ev, &srv->usrtimer_tv) == -1) + fatal("server: event_add usrtimr failed: %s", strerror(errno)); + + droppriv(); + + log_info("server: entering event loop"); + event_dispatch(); + + log_info("server: exiting"); + exit(0); +} + +static struct user * +finduser(struct sockaddr_in *remote) { + struct user *usr; + struct sockaddr_in *u; + + LIST_FOREACH(usr, &usr_list, entry) { + u = &usr->addr; + if (u->sin_addr.s_addr == remote->sin_addr.s_addr && + u->sin_port == remote->sin_port) + return usr; + } + return NULL; +} + +static void +srvconn(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_srvconn *res; + struct user *usr; + + res = imsg->data; + usr = finduser(&res->addr); + if (!usr || usr->status != USER_REQUESTED) + fatal("server: received srvconn response for inexistant connection"); + if (res->ok) { + usr->status = USER_ACCEPTED; + } else { + usr->status = USER_REFUSED; + } +} + +static void +imsgev_main(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + log_debug("server: %s got imsg %i on fd %i", + __func__, imsg->hdr.type, iev->ibuf.fd); + switch (imsg->hdr.type) { + case IMSG_SRVCONN_RES: + srvconn(iev, imsg); + break; + default: + fatal("%s, unexpected imsg %d", + __func__, imsg->hdr.type); + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("server: imsgev read/write error (%d)", code); + /* NOTREACHED */ + break; + case IMSGEV_DONE: + event_loopexit(NULL); + /* NOTREACHED */ + break; + } +} + +static void +imsgev_main_needfd(struct imsgev *iev) +{ + fatal("server: imsgev_main_needfd"); +} + +static void +receive(int fd, short why, void *data) +{ + struct sockaddr_in remote; + struct imsg_srvconn req; + socklen_t len; + char buf[16384]; + struct user *usr; + int rv; + + len = sizeof(remote); + rv = recvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr *)&remote, &len); + if (rv < 0) { + log_warn("server: recvfrom failed"); + return; + } + usr = finduser(&remote); + if (usr) { + switch (usr->status) { + case USER_ACCEPTED: + log_tmp("server: data for existing user"); + break; + case USER_REQUESTED: + log_warn("server: data for not yet accepted user"); + break; + case USER_REFUSED: + log_warn("server: data for banned user !"); + break; + } + } else { + log_debug("server: new user request"); + + usr = xmalloc(sizeof(struct user)); + addrcpy(&usr->addr, &remote); + usr->status = USER_REQUESTED; + usr->lastseen = srv->time; + LIST_INSERT_HEAD(&usr_list, usr, entry); + + addrcpy(&req.addr, &remote); + req.deco = 0; + imsgev_compose(&srv->iev, IMSG_SRVCONN_REQ, 0, 0, -1, + &req, sizeof(req)); + } +} + +static void +ev_usrtimer(int fd, short why, void *data) +{ + struct user *usr, *usrtmp; + struct imsg_srvconn req; + + srv->time = time(NULL); + + LIST_FOREACH_SAFE(usr, &usr_list, entry, usrtmp) { + if (srv->time > usr->lastseen + USER_TIMEOUT) { + addrcpy(&req.addr, &usr->addr); + req.deco = 1; + imsgev_compose(&srv->iev, IMSG_SRVCONN_REQ, 0, 0, -1, + &req, sizeof(req)); + + LIST_REMOVE(usr, entry); + free(usr); + } + } + + if (event_add(&srv->usrtimer_ev, &srv->usrtimer_tv) == -1) + fatal("server: event_add usrtimer failed : %s", strerror(errno)); +} diff --git a/old/glougloud/user.c b/old/glougloud/user.c new file mode 100644 index 0000000..ae9734f --- /dev/null +++ b/old/glougloud/user.c @@ -0,0 +1,806 @@ +#include +#include +#include +#include + +#if !defined(__OpenBSD__) +#define __FAVOR_BSD +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "glougloud.h" +#include "external/imsgev.h" + +/* XXX a user process should be able to have multiple clients, so that we + * can send the same data to multiple machines with almost no overhead */ + +#define NULL_HDRLEN 4 // XXX portable ? +#define NODE_MAX_WITHOUT_TIMEOUT 1000 +#define NODE_TIMEOUT 300 // XXX conf ? +#define CONN_TIMEOUT 300 // XXX conf ? +#define CONN_TIMEOUT_UDP 20 // XXX conf ? +#define CONN_TIMEOUT_ICMP 10 // XXX conf ? +#define CONN_FREEIDS_COUNT 65536 /* 2^16 as long as freeids are u_int16_t */ +#define CONNTIMER 5 // XXX conf ? + +struct node { + LIST_ENTRY(node) entry; + struct in_addr addr; + time_t lastseen; + int used; + short namelen; +#define NODENAME_WAITING -1 +#define NODENAME_FAILED -2 + char *name; +}; + +enum connstate { + CONNSTATE_ESTABLISHED, + CONNSTATE_TCPFIN, + CONNSTATE_TCPFIN2 +}; + +struct conn { + LIST_ENTRY(conn) entry; + u_int id; + enum connstate state; + struct node *src; + u_int src_port; + struct node *dst; + u_int dst_port; + u_int proto; + u_int size; + time_t lastseen; +}; + +struct user { + LIST_ENTRY(user) entry; + struct sockaddr_in addr; +}; + +struct capture { + int fd; + struct imsgev iev; + + pcap_t *pcap; + struct event pcap_ev; + struct timeval pcap_tv; + pcap_handler pcap_handler; + + LIST_HEAD(, conn) conn_list; + LIST_HEAD(, node) node_list; + int node_count; + u_int16_t conn_freeids[CONN_FREEIDS_COUNT]; + int conn_freeids_ptr; + struct event conntimer_ev; + struct timeval conntimer_tv; + time_t time; + + int pinvalid; + int ptruncated; +}; + +struct phandler { + pcap_handler f; + int type; +}; + +static void ip_handle(struct ip *, const u_char *, u_int); +static void sendto_all(struct packet *, int); +static struct node *node_add(struct in_addr *); +static void node_del(struct node *); +static struct node *node_find(struct in_addr *); +static void conn_add(struct in_addr *, int, struct in_addr *, int, int, int); +static void conn_data(struct conn *, int, int); +static void conn_del(struct conn *); +static pcap_handler lookup_phandler(int); +static struct user *finduser(struct sockaddr_in *); + +static void phandler_ether(u_char *, + const struct pcap_pkthdr *, const u_char *); +static void phandler_loop(u_char *, + const struct pcap_pkthdr *, const u_char *); +static void ev_pcap(int, short, void *); +static void ev_timer(int, short, void *); + +static void usrconn(struct imsgev *, struct imsg *); +static void imsgev_main(struct imsgev *, int, struct imsg *); +static void imsgev_main_needfd(struct imsgev *); + +static struct phandler phandlers[] = { + { phandler_ether, DLT_EN10MB }, + { phandler_ether, DLT_IEEE802 }, + { phandler_loop, DLT_LOOP }, + { NULL, 0 }, +}; +struct capture *cap; +LIST_HEAD(, user) usr_list; +int usr_count = 0; + +static void +sig_handler(int sig, short why, void *data) +{ + log_info("user: got signal %d", sig); + if (sig == SIGINT || sig == SIGTERM) + event_loopexit(NULL); +} + +int +user_init(int fd[2], pcap_t *pcap) +{ + struct event ev_sigint, ev_sigterm, ev_sigchld, ev_sighup; + int pid, i; + + pid = fork(); + if (pid < 0) + fatal("user fork"); + if (pid > 0) + return pid; + + setproctitle("user"); + event_init(); + close(fd[0]); + + signal_set(&ev_sigint, SIGINT, sig_handler, NULL); + signal_set(&ev_sigterm, SIGTERM, sig_handler, NULL); + signal_set(&ev_sigchld, SIGCHLD, sig_handler, NULL); + signal_set(&ev_sighup, SIGHUP, sig_handler, NULL); + signal_add(&ev_sigint, NULL); + signal_add(&ev_sigterm, NULL); + signal_add(&ev_sigchld, NULL); + signal_add(&ev_sighup, NULL); + signal(SIGPIPE, SIG_IGN); + + cap = xcalloc(1, sizeof(struct capture)); + cap->fd = fd[1]; + imsgev_init(&cap->iev, cap->fd, NULL, imsgev_main, imsgev_main_needfd); + for (i=0; iconn_freeids[i] = i; + cap->time = time(NULL); + + cap->pcap = pcap; + cap->pcap_handler = lookup_phandler(pcap_datalink(pcap)); + cap->pcap_tv.tv_sec = 0; + cap->pcap_tv.tv_usec = PCAP_TO; + event_set(&cap->pcap_ev, pcap_fileno(cap->pcap), + EV_READ, ev_pcap, NULL); + + cap->conntimer_tv.tv_sec = CONNTIMER; + cap->conntimer_tv.tv_usec = 0; + evtimer_set(&cap->conntimer_ev, ev_timer, NULL); + if (event_add(&cap->conntimer_ev, &cap->conntimer_tv) == -1) + fatal("user: event_add conntimer failed: %s", strerror(errno)); + + droppriv(); + + log_info("user: entering event loop"); + event_dispatch(); + + log_info("user: exiting"); + exit(0); +} + +/* + * Parse an IP packet and descide what to do with it. + * 'ip' is a pointer the the captured IP packet + * 'pend' is a pointer to the end of the captured IP packet + * 'wirelen' is the size of the IP packet off the wire + */ +#define NOTCAPTURED(v) ((u_char *)v > (u_char *)pend - sizeof(*v)) +#define NOTRECEIVED(v) (wirelen < sizeof(v)) +static void +ip_handle(struct ip *ip, const u_char *pend, u_int wirelen) +{ + u_int len, ip_hlen, off; + const u_char *cp; + struct tcphdr *tcph; + struct udphdr *udph; + struct icmp *icmp; + struct in_addr src, dst; + u_int src_port, dst_port; + u_int size, proto, close, response; + struct conn *c, *conn; + + if (NOTCAPTURED(ip)) { + log_pinvalid("user: ip truncated (ip %x pend %x sizeof(ip) %d", + ip, pend, sizeof(ip)); + cap->ptruncated++; + return; + } + + if (ip->ip_v != IPVERSION) { + log_pinvalid("user: invalid ip version"); + cap->pinvalid++; + return; + } + + len = ntohs(ip->ip_len); + if (wirelen < len) { + log_pinvalid("user: ip too small"); + cap->pinvalid++; + len = wirelen; + } + + ip_hlen = ip->ip_hl * 4; + if (ip_hlen < sizeof(struct ip) || ip_hlen > len) { + log_pinvalid("user: ip_hlen invalid, %d", ip_hlen); + cap->pinvalid++; + return; + } + len -= ip_hlen; + + src.s_addr = ntohl(ip->ip_src.s_addr); + dst.s_addr = ntohl(ip->ip_dst.s_addr); + src_port = 0; + dst_port = 0; + proto = IPPROTO_IP; + size = len; + close = 0; + + off = ntohs(ip->ip_off); + if ((off & IP_OFFMASK) == 0) { + cp = (const u_char *)ip + ip_hlen; + switch (ip->ip_p) { + + case IPPROTO_TCP: + tcph = (struct tcphdr *)cp; + if (NOTCAPTURED(&tcph->th_flags)) { + log_pinvalid("user: tcp truncated"); + cap->ptruncated++; + return; + } + if (NOTRECEIVED(*tcph)) { + log_pinvalid("user: tcp too small"); + cap->pinvalid++; + return; + } + src_port = ntohs(tcph->th_sport); + dst_port = ntohs(tcph->th_dport); + proto = IPPROTO_TCP; + size = len - sizeof(*tcph); + if ((tcph->th_flags & TH_FIN) && + (tcph->th_flags & TH_ACK)) + close = 1; + break; + + case IPPROTO_UDP: + udph = (struct udphdr *)cp; + if (NOTCAPTURED(&udph->uh_dport)) { + log_pinvalid("user: udp truncated, " + "ip %x, udph %x, uh_port %x, pend %x, ip_hlen %d", + ip, udph, &udph->uh_dport, pend, ip_hlen); + cap->ptruncated++; + return; + } + if (NOTRECEIVED(*udph)) { + log_pinvalid("user: udp too small"); + cap->pinvalid++; + return; + } + src_port = ntohs(udph->uh_sport); + dst_port = ntohs(udph->uh_dport); + proto = IPPROTO_UDP; + size = len - sizeof(*udph); + break; + + case IPPROTO_ICMP: + icmp = (struct icmp *)cp; + if (NOTRECEIVED(*icmp)) { + log_pinvalid("user: icmp too small"); + cap->pinvalid++; + return; + } + proto = IPPROTO_ICMP; + size = len - sizeof(*icmp); + break; + + default: + log_warn("user: unknown ip protocol !"); + break; + } + } else { + /* + * if this isn't the first frag, we're missing the + * next level protocol header. + */ + log_tmp("user: got a fragmented ip packet !"); + } + + conn = NULL; + LIST_FOREACH(c, &cap->conn_list, entry) { + if (((c->src->addr.s_addr == src.s_addr && + c->src_port == src_port && + c->dst->addr.s_addr == dst.s_addr && + c->dst_port == dst_port) || + (c->src->addr.s_addr == dst.s_addr && + c->src_port == dst_port && + c->dst->addr.s_addr == src.s_addr && + c->dst_port == src_port)) && + c->proto == proto) { + conn = c; + if (c->src->addr.s_addr == src.s_addr) + response = 0; + else + response = 1; + break; + } + } + + if (conn) { + if (!close) { + conn_data(conn, size, response); + } else { + conn_del(conn); + } + } else { + if (!close) { + conn_add(&src, src_port, &dst, dst_port, proto, size); + } else { + log_warn("user: captured connection close w/o open !"); + } + } +} + +/* XXX all the packets must have data htos */ +static void +sendto_all(struct packet *p, int size) +{ + struct user *usr; + + log_debug("SEND PACKET (size %.2d): %x %x", size, p->ver, p->type); + + LIST_FOREACH(usr, &usr_list, entry) { + if (sendto(net_socket, p, size, 0, + (struct sockaddr *)&usr->addr, sizeof(usr->addr)) == -1) + log_warn("send_to failed: %s", strerror(errno)); + } +} + +static struct node * +node_add(struct in_addr *addr) +{ + struct node *n; + struct imsg_usrdns_req req; + + log_debug("user: node_add"); + + n = xcalloc(1, sizeof(struct node)); + n->addr.s_addr = addr->s_addr; + n->namelen = NODENAME_WAITING; + n->lastseen = cap->time; + LIST_INSERT_HEAD(&cap->node_list, n, entry); + cap->node_count++; + + req.addr.s_addr = addr->s_addr; + imsgev_compose(&cap->iev, IMSG_USRDNS_REQ, 0, 0, -1, + &req, sizeof(req)); + + return n; +} + +static void +node_del(struct node *n) +{ + if (n->used) + fatal("user: trying to remove a used node !"); + log_debug("user: node_del"); + + LIST_REMOVE(n, entry); + free(n->name); + free(n); + cap->node_count--; +} + +static struct node * +node_find(struct in_addr *remote) +{ + struct node *n; + + LIST_FOREACH(n, &cap->node_list, entry) + if (n->addr.s_addr == remote->s_addr) + return n; + return NULL; +} + +static void +conn_add(struct in_addr *src, int src_port, struct in_addr *dst, int dst_port, int proto, int size) +{ + struct packet p; + struct conn *c; + struct node *srcnode; + struct node *dstnode; + int id; + + log_debug("user: conn_add, %x:%d->%x:%d %d [%d]", + src->s_addr, src_port, dst->s_addr, dst_port, proto, size); + if (cap->conn_freeids_ptr == CONN_FREEIDS_COUNT) { + log_warn("user: out of connection identifiers !"); + return; + } + + id = cap->conn_freeids[cap->conn_freeids_ptr]; + cap->conn_freeids_ptr++; + + srcnode = node_find(src); + if (!srcnode) + srcnode = node_add(src); + srcnode->used++; + dstnode = node_find(dst); + if (!dstnode) + dstnode = node_add(dst); + dstnode->used++; + + c = xmalloc(sizeof(struct conn)); + c->id = id; + c->state = CONNSTATE_ESTABLISHED; + c->src = srcnode; + c->src_port = src_port; + c->dst = dstnode; + c->dst_port = dst_port; + c->proto = proto; + c->size = size; + c->lastseen = cap->time; + LIST_INSERT_HEAD(&cap->conn_list, c, entry); + + bzero(&p, sizeof(p)); + p.ver = PACKET_VERSION; + p.type = PACKET_NEWCONN; + p.newconn_id = id; + p.newconn_src = htonl(src->s_addr); + p.newconn_dst = htonl(dst->s_addr); + p.newconn_proto = proto; + p.newconn_size = htons(size << 8); + sendto_all(&p, PACKET_NEWCONN_SIZE); +} + +static void +conn_data(struct conn *c, int size, int response) +{ + struct packet p; + + log_debug("user: conn_data"); + + c->lastseen = cap->time; + + bzero(&p, sizeof(p)); + p.ver = PACKET_VERSION; + p.type = PACKET_DATA; + p.data_connid = c->id; + p.data_size = htons(size << 8 | response); //XXX + sendto_all(&p, PACKET_DATA_SIZE); +} + +static void +conn_del(struct conn *c) +{ + struct packet p; + + log_debug("user: conn_del"); + + if (c->proto == IPPROTO_TCP) { + switch (c->state) { + case CONNSTATE_ESTABLISHED: + c->state = CONNSTATE_TCPFIN; + return; + case CONNSTATE_TCPFIN: + c->state = CONNSTATE_TCPFIN2; + return; + case CONNSTATE_TCPFIN2: + break; + } + } + + bzero(&p, sizeof(p)); + p.ver = PACKET_VERSION; + p.type = PACKET_DELCONN; + p.delconn_id = c->id; + sendto_all(&p, PACKET_DELCONN_SIZE); + + if (cap->conn_freeids_ptr == 0) + fatal("cap->conn_freeids_ptr == 0"); + cap->conn_freeids_ptr--; + cap->conn_freeids[cap->conn_freeids_ptr] = c->id; + + c->src->used--; + c->dst->used--; + + LIST_REMOVE(c, entry); + free(c); +} + +static pcap_handler +lookup_phandler(int type) +{ + struct phandler *p; + + for (p = phandlers; p->f; ++p) { + if (type == p->type) + return p->f; + } + fatal("user: unknown data link type 0x%x", type); + /* NOTREACHED */ + return NULL; +} + +static struct user * +finduser(struct sockaddr_in *remote) +{ + struct user *usr; + struct sockaddr_in *u; + + LIST_FOREACH(usr, &usr_list, entry) { + u = &usr->addr; + if (u->sin_addr.s_addr == remote->sin_addr.s_addr && + u->sin_port == remote->sin_port) + return usr; + } + return NULL; +} + +static void +phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p) +{ + struct ether_header *ep; + struct ip *ip; + u_short ether_type; + const u_char *pend; + u_int len; + + log_debug("user: pcap handler ethernet !"); + + /* XXX here i assume that packets are alligned, which might not + * be the case when using dump files, says tcpdump sources */ + + ep = (struct ether_header *)p; + pend = p + h->caplen; + len = h->len - sizeof(struct ether_header); + + + ether_type = ntohs(ep->ether_type); + if (ether_type <= ETHERMTU) + log_tmp("llc packet !"); + else { + switch (ether_type) { + case ETHERTYPE_IP: + log_tmp("ether IP"); + ip = (struct ip *)((u_char *)ep + sizeof(struct ether_header)); + ip_handle(ip, pend, len); + break; + default: + log_tmp("non ip packet !"); + break; + } + } +} + +static void +phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p) +{ + struct ip *ip; + struct ether_header *ep; + u_short ether_type; + u_int family; + const u_char *pend; + u_int len; + + log_debug("user: pcap handler loop !"); + + /* XXX here i assume that packets are alligned, which might not + * be the case when using dump files, says tcpdump sources */ + + pend = p + h->caplen; + len = h->len; + + memcpy((char *)&family, (char *)p, sizeof(family)); + family = ntohl(family); + switch (family) { + case AF_INET: + log_tmp("loop family AF_INET"); + ip = (struct ip *)(p + NULL_HDRLEN); + len -= NULL_HDRLEN; + ip_handle(ip, pend, len); + break; +#if defined(__OpenBSD__) + case AF_LINK: +#else + case AF_LOCAL: +#endif + ep = (struct ether_header *)(p + NULL_HDRLEN); + ether_type = ntohs(ep->ether_type); + if (ether_type <= ETHERMTU) + log_tmp("llc packet !"); + else { + switch (ether_type) { + case ETHERTYPE_IP: + log_tmp("loop family AF_LINK IP"); + ip = (struct ip *)((u_char *)ep + sizeof(*ep)); + len -= NULL_HDRLEN + sizeof(*ep); + ip_handle(ip, pend, len); + break; + default: + log_tmp("loop non ip packet !"); + break; + } + } + default: + log_tmp("unknown family %x !", family); + break; + } +} + +static void +ev_pcap(int fd, short why, void *data) +{ + log_tmp("ev_pcap"); + pcap_dispatch(cap->pcap, PCAP_COUNT, cap->pcap_handler, NULL); + + /* reschedule */ + if (event_add(&cap->pcap_ev, &cap->pcap_tv) == -1) + fatal("user: event_add pcap failed : %s", strerror(errno)); +} + +static void +ev_timer(int fd, short why, void *data) +{ + struct conn *c, *ctmp; + struct node *n, *ntmp; + int i, to; + + log_debug("ev_timer"); + cap->time = time(NULL); + + i = 0; + LIST_FOREACH_SAFE(c, &cap->conn_list, entry, ctmp) { + switch (c->proto) { + case IPPROTO_UDP: + to = CONN_TIMEOUT_UDP; + break; + case IPPROTO_ICMP: + to = CONN_TIMEOUT_ICMP; + break; + default: + to = CONN_TIMEOUT; + break; + } + if (cap->time > c->lastseen + to) + conn_del(c); + else + i++; + } + + if (cap->node_count > NODE_MAX_WITHOUT_TIMEOUT) { + LIST_FOREACH_SAFE(n, &cap->node_list, entry, ntmp) { + if (n->used == 0 && + cap->time > n->lastseen + NODE_TIMEOUT) + node_del(n); + } + } + + log_debug("user: ev_timer leaving with %d active connections and %d active nodes", i, cap->node_count); + if (event_add(&cap->conntimer_ev, &cap->conntimer_tv) == -1) + fatal("user: event_add conntimer failed : %s", strerror(errno)); +} + +static void +usrconn(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_usrconn *req; + struct imsg_usrconn res; + struct user *usr; + + req = imsg->data; + + if (req->deco) { + usr = finduser(&req->addr); + if (!usr) + fatal("user: trying to deco an inexistant user !"); + LIST_REMOVE(usr, entry); + free(usr); + usr_count--; + if (usr_count == 0) + event_del(&cap->pcap_ev); + + return; + } + + usr = xmalloc(sizeof(struct user)); + addrcpy(&usr->addr, &req->addr); + LIST_INSERT_HEAD(&usr_list, usr, entry); + if (usr_count == 0) { + if (event_add(&cap->pcap_ev, &cap->pcap_tv) == -1) + fatal("user: event_add failed : %s", strerror(errno)); + } + usr_count++; + + addrcpy(&res.addr, &usr->addr); + res.ok = 1; + imsgev_compose(&cap->iev, IMSG_USRCONN_RES, 0, 0, -1, + &res, sizeof(res)); +} + +static void +usrdns(struct imsgev *iev, struct imsg *imsg) +{ + struct imsg_usrdns_res *res; + struct node *n; + struct packet p; + + res = imsg->data; + + n = node_find(&res->addr); + if (!n) + fatal("user: received usrdns response for inexistant node !"); + if (n->namelen != NODENAME_WAITING) + fatal("user: received usrdns response for a nonwaiting node!"); + + if (res->name[0] == '\0') { + log_debug("user: resolv for %x failed", res->addr.s_addr); + n->namelen = NODENAME_FAILED; + return; + } + n->namelen = strnlen(res->name, DNSNAME_MAX); + n->name = strndup(res->name, DNSNAME_MAX); + + log_debug("user: sending node name of %x is %s", + n->addr.s_addr, n->name); + bzero(&p, sizeof(p)); + p.ver = PACKET_VERSION; + p.type = PACKET_NAME; + p.name_addr = htonl(n->addr.s_addr); + p.name_len = n->namelen; + strncpy(p.name_fqdn, n->name, sizeof(p.name_fqdn)); + sendto_all(&p, PACKET_NAME_SIZE + p.name_len); +} + +static void +imsgev_main(struct imsgev *iev, int code, struct imsg *imsg) +{ + switch (code) { + case IMSGEV_IMSG: + log_debug("user: %s got imsg %i on fd %i", + __func__, imsg->hdr.type, iev->ibuf.fd); + switch (imsg->hdr.type) { + case IMSG_USRCONN_REQ: + usrconn(iev, imsg); + break; + case IMSG_USRDNS_RES: + usrdns(iev, imsg); + break; + default: + fatal("user: %s, unexpected imsg %d", + __func__, imsg->hdr.type); + } + break; + case IMSGEV_EREAD: + case IMSGEV_EWRITE: + case IMSGEV_EIMSG: + fatal("user: imsgev read/write error"); + /* NOTREACHED */ + break; + case IMSGEV_DONE: + event_loopexit(NULL); + /* NOTREACHED */ + break; + } +} + +static void +imsgev_main_needfd(struct imsgev *iev) +{ + fatal("server: imsgev_main_needfd"); +} diff --git a/old/glougloud/util.c b/old/glougloud/util.c new file mode 100644 index 0000000..c077bd3 --- /dev/null +++ b/old/glougloud/util.c @@ -0,0 +1,192 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "glougloud.h" + +FILE *logfile; +int loglevel; +int logpinvalid; + +#define LOGFILE "/var/log/glougloud" +#define LOG_FORCED -2 +#define LOG_FATAL -1 +#define LOG_WARN 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 + +static void logit(int, const char *, const char *, va_list); + +void +log_init(int level, int pinvalid) +{ + logfile = fopen(LOGFILE, "a+"); + if (!logfile) { + printf("cannot open log file %s!\n", LOGFILE); + exit(1); + } + loglevel = level; + logpinvalid = pinvalid; +} + +void +log_tmp(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_FORCED, "XXX ", msg, ap); + va_end(ap); +} +void +log_pinvalid(const char *msg, ...) +{ + va_list ap; + + if (!logpinvalid) + return; + + va_start(ap, msg); + logit(LOG_FORCED, "pinvalid: ", msg, ap); + va_end(ap); +} +void +log_debug(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_DEBUG, "", msg, ap); + va_end(ap); +} +void +log_info(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_INFO, "", msg, ap); + va_end(ap); +} +void +log_warn(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_WARN, "", msg, ap); + va_end(ap); +} +#if defined(__OpenBSD__) +void __dead +#else +void +#endif +fatal(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + logit(LOG_FATAL, "fatal: ", msg, ap); + va_end(ap); + + exit(1); +} + +/* XXX mpsafe */ +static void +logit(int level, const char *prefix, const char *msg, va_list ap) +{ + time_t clock; + + if (level <= loglevel) { + time(&clock); + fprintf(logfile, "%d ", (int)clock); + vfprintf(logfile, prefix, ap); + vfprintf(logfile, msg, ap); + fprintf(logfile, "\n"); + fflush(logfile); + } +} + +void * +xmalloc(size_t size) +{ + void *ptr; + + if (size == 0) + fatal("xmalloc: zero size"); + ptr = malloc(size); + if (ptr == NULL) + fatal("xmalloc: out of memory (allocating %lu bytes)", (u_long) size); + return ptr; +} + +void * +xcalloc(size_t nmemb, size_t size) +{ + void *ptr; + + if (size == 0) + fatal("xcalloc: zero size"); + ptr = calloc(nmemb, size); + if (ptr == NULL) + fatal("xcalloc: out of memory (allocating %lu bytes)", (u_long) size); + return ptr; +} + +void +fd_nonblock(int fd) +{ + int flags = fcntl(fd, F_GETFL, 0); + int rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (rc == -1) + log_warn("failed to set fd %i non-blocking", fd); +} + +void +droppriv() +{ + struct passwd *pw; + + pw = getpwnam(GLOUGLOUD_USER); + if (!pw) + fatal("unknown user %s", GLOUGLOUD_USER); + if (chroot(pw->pw_dir) != 0) + fatal("unable to chroot"); + if (chdir("/") != 0) + fatal("unable to chdir"); + if (setgroups(1, &pw->pw_gid) == -1) + fatal("setgroups() failed"); + if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) + fatal("setresgid failed"); + if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) + fatal("setresuid() failed"); + endpwent(); +} + +void +addrcpy(struct sockaddr_in *dst, struct sockaddr_in *src) +{ + dst->sin_addr.s_addr = src->sin_addr.s_addr; + dst->sin_port = src->sin_port; + dst->sin_family = src->sin_family; +} + +void +socketpair_prepare(int fd[2]) +{ + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1) + fatal("socketpair_prepare"); + fd_nonblock(fd[0]); + fd_nonblock(fd[1]); +} + -- cgit v1.2.3-59-g8ed1b