aboutsummaryrefslogtreecommitdiffstats
path: root/old/glougloud
diff options
context:
space:
mode:
Diffstat (limited to 'old/glougloud')
-rw-r--r--old/glougloud/BUGS.txt10
-rw-r--r--old/glougloud/Makefile12
-rw-r--r--old/glougloud/README.txt51
-rw-r--r--old/glougloud/external/README.txt8
-rw-r--r--old/glougloud/external/imsg-buffer.c305
-rw-r--r--old/glougloud/external/imsg.c301
-rw-r--r--old/glougloud/external/imsg.h118
-rw-r--r--old/glougloud/external/imsgev.c170
-rw-r--r--old/glougloud/external/imsgev.h49
-rw-r--r--old/glougloud/external/queue.h568
-rw-r--r--old/glougloud/glougloud.c487
-rw-r--r--old/glougloud/glougloud.h79
-rw-r--r--old/glougloud/server.c238
-rw-r--r--old/glougloud/user.c806
-rw-r--r--old/glougloud/util.c192
15 files changed, 3394 insertions, 0 deletions
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 <henning@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <henning@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <pyr@openbsd.org>
+ * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * 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 <eric@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <eric@openbsd.org>
+ *
+ * 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 <event.h>
+#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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <pcap.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#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 <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <pcap.h>
+
+#include <libglouglou.h>
+
+#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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+#include <time.h>
+
+#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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#if !defined(__OpenBSD__)
+#define __FAVOR_BSD
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <pcap.h>
+
+#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; i<CONN_FREEIDS_COUNT-1; i++)
+ cap->conn_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 <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <pwd.h>
+#include <string.h>
+
+#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]);
+}
+