socsvn commit: r287735 - in soc2015/roam: . ayiya_resp ng_ayiya
roam at FreeBSD.org
roam at FreeBSD.org
Mon Jun 29 19:03:16 UTC 2015
Author: roam
Date: Mon Jun 29 19:03:13 2015
New Revision: 287735
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=287735
Log:
Add a userland responder to non-forward packets.
ng_ayiya:
- send all packets that do not contain forwarded IPv6 data
down the "control" hook if it's connected.
- break out the signing part of ayiya_build() into ayiya_sign()
- move the m_adj() call to remove the AYIYA header from
ayiya_verify() to the consumer, the rcvdata function, since we
do need the full AYIYA packet to forward down the control hook
- add constants for the AYIYA opcodes and use them
ayiya_resp:
- write a proof-of-concept C program that uses libnetgraph to
connect to the "control" hook, wait for remote packets,
interpret them, and send packets of its own
ObQuote: "Do you, do you, do you, do you wanna dance?"
Added:
soc2015/roam/Makefile
soc2015/roam/ayiya_resp/
soc2015/roam/ayiya_resp/Makefile
soc2015/roam/ayiya_resp/main.c
Modified:
soc2015/roam/ng_ayiya/ng_ayiya.4
soc2015/roam/ng_ayiya/ng_ayiya.c
soc2015/roam/ng_ayiya/ng_ayiya.h
Added: soc2015/roam/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ soc2015/roam/Makefile Mon Jun 29 19:03:13 2015 (r287735)
@@ -0,0 +1,42 @@
+# Copyright (c) 2015 Peter Pentchev
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+SUBDIR= ayiya_resp ng_ayiya
+
+.include <bsd.subdir.mk>
+
+down:
+ cd ${.CURDIR}/ng_ayiya && ${MAKE} down
+
+up:
+ cd ${.CURDIR}/ng_ayiya && ${MAKE} up
+
+tic:
+ cd ${.CURDIR}/ng_ayiya && ${MAKE} tic
+
+clitest: tic
+ cd ${.CURDIR}/ayiya_resp && ${MAKE} clitest
+
+clitest-quiet: tic
+ cd ${.CURDIR}/ayiya_resp && ${MAKE} clitest-quiet
Added: soc2015/roam/ayiya_resp/Makefile
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ soc2015/roam/ayiya_resp/Makefile Mon Jun 29 19:03:13 2015 (r287735)
@@ -0,0 +1,42 @@
+# Copyright (c) 2015 Peter Pentchev
+# 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.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+
+PROG= ayiya_resp
+SRCS= main.c
+NO_MAN= yes
+WARNS?= 9
+DPADD= ${LIBNETGRAPH}
+LDADD= -lnetgraph
+
+CFLAGS+= -I${.CURDIR}/..
+
+.include <bsd.prog.mk>
+
+clitest:
+ sudo ${.OBJDIR}/${PROG} -v config
+ sudo ${.OBJDIR}/${PROG} -v loop
+
+clitest-quiet:
+ sudo ${.OBJDIR}/${PROG} -v config
+ sudo ${.OBJDIR}/${PROG} -q loop
Added: soc2015/roam/ayiya_resp/main.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ soc2015/roam/ayiya_resp/main.c Mon Jun 29 19:03:13 2015 (r287735)
@@ -0,0 +1,433 @@
+/*-
+ * Copyright (c) 2015 Peter Pentchev
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <netgraph.h>
+#include <ng_ayiya/ng_ayiya.h>
+
+#include <netinet/in.h>
+
+#define A_SEL_TIMEOUT 0x0000
+#define A_SEL_RD_DATA 0x0001
+#define A_SEL_WR_DATA 0x0002
+#define A_SEL_EXC 0x0004
+
+#define MOTD \
+ "1435504634\n" \
+ "Complaint In The System\n" \
+ "Welcome to the system, here's the situation;\n" \
+ "It's a bit confusing, welcome to the maze!\n"
+
+static int quiet;
+static int verbose;
+
+static void usage(int _ferr);
+static void version(void);
+static void debug(const char *fmt, ...) __printflike(1, 2);
+
+static int cmd_config(const char *cmd, char * const args[], unsigned argc);
+static int cmd_loop(const char *cmd, char * const args[], unsigned argc);
+
+static void ayiya_connect(int *, int *);
+static void ayiya_get_config(int, bool);
+static unsigned ayiya_select(int, bool, bool);
+static void send_packet(int, ayiya_opcode, const char *, size_t);
+static void send_empty_packet(int, ayiya_opcode);
+
+static struct {
+ const char *name;
+ int (*func)(const char *cmd, char * const args[], unsigned argc);
+} commands[] = {
+ { "config", cmd_config },
+ { "loop", cmd_loop },
+};
+#define COMMANDS (sizeof(commands) / sizeof(commands[0]))
+
+#define AYIYA_ND "sc_ayiya"
+
+static union {
+ struct ng_mesg msg;
+ char buf[32768];
+} ng_msgbuf;
+static char ng_msgpath[NG_PATHSIZ];
+
+int
+main(int argc, char * const argv[])
+{
+ int ch, hflag, Vflag;
+
+ hflag = Vflag = 0;
+ while (ch = getopt(argc, argv, "hqVv"), ch != -1)
+ switch (ch) {
+ case 'h':
+ hflag = 1;
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'V':
+ Vflag = 1;
+ break;
+
+ case 'v':
+ verbose++;
+ break;
+
+ default:
+ usage(1);
+ /* NOTREACHED */
+ }
+ if (Vflag)
+ version();
+ if (hflag)
+ usage(0);
+ if (Vflag || hflag)
+ return (0);
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1) {
+ warnx("No command specified");
+ usage(1);
+ }
+ const size_t len = strlen(argv[0]);
+ unsigned idx = COMMANDS;
+ for (unsigned i = 0; i < COMMANDS; i++) {
+ if (strcmp(argv[0], commands[i].name) == 0) {
+ idx = i;
+ break;
+ } else if (strncmp(argv[0], commands[i].name, len) == 0) {
+ if (idx != COMMANDS) {
+ warnx("Ambiguous command '%s'", argv[0]);
+ usage(1);
+ }
+ idx = i;
+ }
+ }
+ if (idx == COMMANDS) {
+ warnx("Unrecognized command '%s'", argv[0]);
+ usage(1);
+ }
+ return (commands[idx].func)(argv[0], argv + 1, argc - 1);
+}
+
+void
+usage(const int _ferr)
+{
+ const char * const s =
+ "Usage:\tayiya_resp [-v] config\n"
+ "\tayiya_resp [-qv] loop\n"
+ "\tayiya_resp -V | -h\n"
+ "\n"
+ "\t-h\tdisplay program usage information and exit\n"
+ "\t-n\tspecify the number of lines to checksum for each file\n"
+ "\t-q\tquiet mode; only respond, do not originate AYIYA packets\n"
+ "\t-V\tdisplay program version information and exit\n"
+ "\t-v\tverbose operation; display diagnostic output\n";
+
+ fprintf(_ferr? stderr: stdout, "%s", s);
+ if (_ferr)
+ exit(1);
+}
+
+void
+version(void)
+{
+ puts("ayiya_resp 0.1.0.dev178");
+}
+
+void
+debug(const char * const fmt, ...)
+{
+ va_list v;
+
+ va_start(v, fmt);
+ if (verbose)
+ vfprintf(stderr, fmt, v);
+ va_end(v);
+}
+
+int
+cmd_config(const char * const cmd __unused, char * const args[] __unused,
+ const unsigned argc)
+{
+ if (argc != 0)
+ errx(1, "The 'config' command expects no arguments");
+
+ int cs, ds;
+ ayiya_connect(&cs, &ds);
+ ayiya_get_config(cs, true);
+ return (0);
+}
+
+int
+cmd_loop(const char * const cmd __unused, char * const args[] __unused,
+ const unsigned argc)
+{
+ if (argc != 0)
+ errx(1, "The 'loop' command expects no arguments");
+
+ int cs, ds;
+ ayiya_connect(&cs, &ds);
+ ayiya_get_config(cs, false);
+
+ srandomdev();
+ time_t next_heartbeat = time(NULL);
+ time_t next_motd = next_heartbeat + 7 + (random() % 7);
+ for (;;) {
+ const time_t now = time(NULL);
+ debug("Loop: now %ld heartbeat %ld motd %ld\n",
+ now, next_heartbeat, next_motd);
+ const bool do_heartbeat = !quiet && now >= next_heartbeat;
+ const bool do_motd = !quiet && now >= next_motd;
+ debug("- select, heartbeat %s, motd %s\n",
+ do_heartbeat? "true": "false",
+ do_motd? "true": "false");
+ const unsigned sel = ayiya_select(ds, true,
+ do_heartbeat || do_motd);
+ if (sel == A_SEL_TIMEOUT) {
+ debug("- we got nothin'\n");
+ continue;
+ }
+ const time_t rcvat = time(NULL);
+
+ if (sel & A_SEL_WR_DATA) {
+ if (do_heartbeat) {
+ debug("Sending a heartbeat\n");
+ send_empty_packet(ds, AYIYA_OP_HEARTBEAT);
+ next_heartbeat = now + 10;
+ }
+
+ if (do_motd) {
+ debug("Sending a MOTD\n");
+ send_packet(ds, AYIYA_OP_MOTD,
+ MOTD, sizeof(MOTD) - 1);
+ next_motd = now + 7 + (random() % 7);
+ }
+ }
+
+ if (sel & A_SEL_RD_DATA) {
+ const int len = NgRecvData(ds, ng_msgbuf.buf,
+ sizeof(ng_msgbuf.buf), ng_msgpath);
+ if (len < 0)
+ err(1, "Receiving data");
+ if (len < 1) {
+ warnx("Our Netgraph socket was closed");
+ return (0);
+ }
+ debug("Got %d bytes of data:\n", len);
+ for (int d = 0; d < len; d++)
+ debug("%02hhX%c", ng_msgbuf.buf[d],
+ d % 16 == 15? '\n': ' ');
+ if (len % 16 != 0)
+ debug("\n");
+
+ const struct ng_ayiya_header * const hdr =
+ (const struct ng_ayiya_header *)ng_msgbuf.buf;
+ const size_t hlen = ayiya_offset_data(hdr);
+ const char * const data = &ng_msgbuf.buf[hlen];
+ const size_t dlen = len - hlen;
+ switch (hdr->opcode) {
+ case AYIYA_OP_HEARTBEAT:
+ printf("%jd Heartbeat received\n",
+ (intmax_t)rcvat);
+ break;
+
+ case AYIYA_OP_MOTD:
+ printf("%jd Message of the day:\n",
+ (intmax_t)rcvat);
+ for (size_t d = 0; d < dlen; d++) {
+ const char ch = data[d];
+ if (ch >= 32 || ch == '\n' || ch == '\t')
+ putchar(ch);
+ else
+ printf("%%%02hhX", ch);
+ }
+ putchar('\n');
+ break;
+
+ default:
+ debug("FIXME: handle opcode %d\n", hdr->opcode);
+ break;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+void
+ayiya_get_config(const int cs, const bool twice)
+{
+ if (NgSendMsg(cs, "c", NGM_GENERIC_COOKIE, NGM_TEXT_CONFIG, NULL, 0) == -1)
+ err(1, "Could not query the configuration of the %s AYIYA node",
+ AYIYA_ND);
+ debug("Waiting for the ng_ayiya 'config' reply\n");
+
+ unsigned sel = ayiya_select(cs, true, false);
+ if (sel == A_SEL_TIMEOUT)
+ errx(1, "Did not receive a reply from the %s AYIYA node in two seconds", AYIYA_ND);
+ else if (sel & A_SEL_EXC)
+ errx(1, "Something bad happened on the control fd %d", cs);
+ else if (!(sel & A_SEL_RD_DATA))
+ errx(1, "Something very weird happened, no data to read on the control fd %d", cs);
+
+ struct ng_mesg * const msg = &ng_msgbuf.msg;
+ if (NgRecvMsg(cs, msg, sizeof(ng_msgbuf.buf), ng_msgpath) == -1)
+ err(1, "Could not get the configuration of the %s AYIYA node",
+ AYIYA_ND);
+ debug("Got a 'config' reply from '%s': version %u cmd %X arglen %u\n",
+ ng_msgpath, msg->header.version, msg->header.cmd, msg->header.arglen);
+ char * endptr = &msg->data[msg->header.arglen];
+ if (endptr >= &ng_msgbuf.buf[sizeof(ng_msgbuf.buf)])
+ errx(1, "The 'config' response did not fit in 32K...");
+ *endptr = '\0';
+ debug("The data itself:\n%s\n", msg->data);
+
+ if (!twice)
+ return;
+ debug("OK, let's wait a second time\n");
+ sel = ayiya_select(cs, true, false);
+ if (sel != A_SEL_TIMEOUT)
+ errx(1, "Something really weird happened, ayiya_select() "
+ "returned %d for the control fd", sel);
+ debug("No data as expected\n");
+}
+
+void
+ayiya_connect(int * const cs, int * const ds)
+{
+ assert(cs != NULL && ds != NULL);
+
+ if (NgMkSockNode("ayiya_resp_ctl", cs, ds) == -1)
+ err(1, "Could not create the control socket node");
+
+ const struct ngm_connect c = {
+ .path = AYIYA_ND ":",
+ .ourhook = "c",
+ .peerhook = "control",
+ };
+ if (NgSendMsg(*cs, ".", NGM_GENERIC_COOKIE, NGM_CONNECT,
+ &c, sizeof(c)) == -1)
+ err(1, "Could not connect to the %s AYIYA node", AYIYA_ND);
+
+ int flags = fcntl(*cs, F_GETFL);
+ debug("- cs flags: %X (non-blocking: %s, append-only: %s, "
+ "direct I/O: %s, async: %s)\n", flags,
+ flags & O_NONBLOCK? "true": "false",
+ flags & O_APPEND? "true": "false",
+ flags & O_DIRECT? "true": "false",
+ flags & O_ASYNC? "true": "false");
+ if (!(flags & O_NONBLOCK) &&
+ fcntl(*cs, F_SETFL, flags | O_NONBLOCK) == -1)
+ err(1, "Could not set the control socket to non-blocking mode");
+ flags = fcntl(*ds, F_GETFL);
+ debug("- ds flags: %X (non-blocking: %s, append-only: %s, "
+ "direct I/O: %s, async: %s)\n", flags,
+ flags & O_NONBLOCK? "true": "false",
+ flags & O_APPEND? "true": "false",
+ flags & O_DIRECT? "true": "false",
+ flags & O_ASYNC? "true": "false");
+ if (!(flags & O_NONBLOCK) &&
+ fcntl(*ds, F_SETFL, flags | O_NONBLOCK) == -1)
+ err(1, "Could not set the ds socket to non-blocking mode");
+}
+
+unsigned
+ayiya_select(const int fd, const bool do_read, const bool do_write)
+{
+ fd_set rd, wr, exc;
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&exc);
+ if (do_read)
+ FD_SET(fd, &rd);
+ if (do_write)
+ FD_SET(fd, &wr);
+ FD_SET(fd, &exc);
+
+ struct timeval to = { .tv_sec = 2, .tv_usec = 0 };
+ const int res = select(fd + 1, &rd, &wr, &exc, &to);
+ if (res == 0)
+ return (A_SEL_TIMEOUT);
+ else if (res != 1)
+ errx(1, "Something really weird happened, "
+ "select() on fd %d returned %d", fd, res);
+
+ unsigned val = 0;
+ if (FD_ISSET(fd, &rd))
+ val |= A_SEL_RD_DATA;
+ if (FD_ISSET(fd, &wr))
+ val |= A_SEL_WR_DATA;
+ if (FD_ISSET(fd, &exc))
+ val |= A_SEL_EXC;
+ return (val);
+}
+
+void
+send_packet(const int ds, const ayiya_opcode op, const char * const data,
+ const size_t len)
+{
+ struct ng_ayiya_packet * const pkt =
+ (struct ng_ayiya_packet *)&ng_msgbuf.buf;
+ if (sizeof(*pkt) + len > sizeof(ng_msgbuf.buf))
+ errx(1, "Internal error: send_packet() length %zu too big, "
+ "max %zu", len, sizeof(ng_msgbuf.buf) - sizeof(*pkt));
+ pkt->hdr.idlen = 4;
+ pkt->hdr.idtype = 1; // Integer
+ pkt->hdr.siglen = sizeof(pkt->signature) / 4;
+ pkt->hdr.hshmeth = 2; // SHA1
+ pkt->hdr.autmeth = 1; // shared secret
+ pkt->hdr.opcode = op;
+ pkt->hdr.nextheader = IPPROTO_NONE;
+ pkt->hdr.epochtime = time(NULL);
+
+ if (len > 0)
+ bcopy(data, pkt + 1, len);
+
+ if (NgSendData(ds, "c", ng_msgbuf.buf, sizeof(*pkt) + len) == -1)
+ err(1, "Could not send data on the data socket");
+}
+
+void
+send_empty_packet(const int ds, const ayiya_opcode op)
+{
+ send_packet(ds, op, NULL, 0);
+}
Modified: soc2015/roam/ng_ayiya/ng_ayiya.4
==============================================================================
--- soc2015/roam/ng_ayiya/ng_ayiya.4 Mon Jun 29 18:56:53 2015 (r287734)
+++ soc2015/roam/ng_ayiya/ng_ayiya.4 Mon Jun 29 19:03:13 2015 (r287735)
@@ -130,6 +130,23 @@
.Dv NGM_AYIYA_CONFIGURE
control message; when the message has been processed, the tunnel
should be up and running.
+.It *
+Start an
+.Tn AYIYA
+responder program that will connect to the
+.Nm ayiya
+node's
+.Va control
+hook, listen for any incoming heartbeat, echo, "message of the day",
+or query packets, and process them as necessary.
+A sample
+.Tn AYIYA
+responder using the
+.Nm ayiya
+Netgraph node is available in the
+.Nm
+source directory as
+.Xr ayiya_resp 8 .
.El
.Sh HOOKS
The
Modified: soc2015/roam/ng_ayiya/ng_ayiya.c
==============================================================================
--- soc2015/roam/ng_ayiya/ng_ayiya.c Mon Jun 29 18:56:53 2015 (r287734)
+++ soc2015/roam/ng_ayiya/ng_ayiya.c Mon Jun 29 19:03:13 2015 (r287735)
@@ -567,20 +567,31 @@
return (AYIYA_HOOK_LAST);
}
+static int ayiya_sign(struct mbuf **mb, priv_p priv);
+
static int
-ayiya_build(struct mbuf **mb, const u_char opcode, const u_char nextheader,
+ayiya_build(struct mbuf ** const mb, const u_char opcode, const u_char nextheader,
const priv_p priv)
{
struct mbuf *m = *mb;
- if (m == NULL)
+ if (m == NULL) {
m = ayiya_m_getm(sizeof(struct ng_ayiya_packet), M_NOWAIT);
- else
+ *mb = m;
+ } else {
M_PREPEND(m, sizeof(struct ng_ayiya_packet), M_NOWAIT);
- if (m->m_next)
- m = m_defrag(m, M_NOWAIT);
- if (m == NULL)
- return (ENOMEM);
+ *mb = m;
+ }
+ if (m->m_next) {
+ struct mbuf * const m2 = m_defrag(m, M_NOWAIT);
+ if (m2 == NULL) {
+ m_freem(m);
+ *mb = NULL;
+ return (ENOMEM);
+ }
+ m = m2;
+ *mb = m;
+ }
struct ng_ayiya_header * const hdr =
(struct ng_ayiya_header *)m->m_data;
struct ng_ayiya_packet * const pkt =
@@ -595,6 +606,27 @@
hdr->nextheader = nextheader;
hdr->epochtime = htonl(time_second);
+ return (ayiya_sign(mb, priv));
+}
+
+static int
+ayiya_sign(struct mbuf ** const mb, const priv_p priv)
+{
+ struct mbuf *m = *mb;
+
+ if (m->m_next) {
+ struct mbuf * const m2 = m_defrag(m, M_NOWAIT);
+ if (m2 == NULL) {
+ m_freem(m);
+ *mb = NULL;
+ return (ENOMEM);
+ }
+ m = m2;
+ *mb = m;
+ }
+
+ struct ng_ayiya_packet * const pkt =
+ (struct ng_ayiya_packet *)m->m_data;
bcopy(priv->identity, pkt->identity, sizeof(pkt->identity));
/* Start with the secret hash... */
@@ -610,22 +642,25 @@
bcopy(hash, pkt->signature, sizeof(pkt->signature));
/* And I think we're done. */
- *mb = m;
return (0);
}
static int
ayiya_verify(struct mbuf **mb, u_char * const opcode, u_char * const nextheader,
- const priv_p priv)
+ int32_t * const ofs, const priv_p priv)
{
struct mbuf *m = *mb;
if (m->m_next) {
- m = m_defrag(m, M_NOWAIT);
+ struct mbuf * const m2 = m_defrag(m, M_NOWAIT);
+ if (m2 == NULL) {
+ m_freem(m);
+ *mb = NULL;
+ return (ENOMEM);
+ }
+ m = m2;
*mb = m;
}
- if (m == NULL)
- return (ENOMEM);
const int32_t len = m->m_len;
struct ng_ayiya_header * const hdr =
(struct ng_ayiya_header *)m->m_data;
@@ -704,8 +739,7 @@
return (EOPNOTSUPP);
}
- m_adj(m, ofs_data);
- *mb = m;
+ *ofs = ofs_data;
*opcode = hdr->opcode;
*nextheader = hdr->nextheader;
return (0);
@@ -746,7 +780,8 @@
}
/* Prepare a packet for forwarding */
- int error = ayiya_build(&m, 1, IPPROTO_IPV6, priv);
+ int error = ayiya_build(&m, AYIYA_OP_FORWARD,
+ IPPROTO_IPV6, priv);
if (error != 0)
return (error);
@@ -758,7 +793,8 @@
{
u_char opcode;
u_char nextheader;
- int error = ayiya_verify(&m, &opcode, &nextheader, priv);
+ int32_t ofs;
+ int error = ayiya_verify(&m, &opcode, &nextheader, &ofs, priv);
if (error != 0)
{
m_freem(m);
@@ -767,24 +803,63 @@
switch (opcode)
{
- case 1:
+ case AYIYA_OP_FORWARD:
+ case AYIYA_OP_ECHO_AND_FORWARD:
+ {
+ const int echo = opcode == AYIYA_OP_ECHO_AND_FORWARD;
+ struct mbuf *mf;
+ if (!echo) {
+ m_adj(m, ofs);
+ mf = m;
+ } else {
+ mf = ayiya_m_getm(m->m_len - ofs, M_NOWAIT);
+ bcopy(m->m_data + ofs, mf->m_data, mf->m_len);
+ }
+
/* Forward */
if (nextheader != IPPROTO_IPV6)
{
+ if (echo)
+ m_freem(mf);
m_freem(m);
return (0);
}
int error;
- NG_SEND_DATA_ONLY(error, priv->hooks[AYIYA_HOOK_INET6], m);
- /* Ignore the error, nothing to do, really. */
- break;
+ NG_SEND_DATA_ONLY(error, priv->hooks[AYIYA_HOOK_INET6], mf);
+ if (!echo)
+ return (0);
+ }
default:
- break;
+ {
+ if (priv->hooks[AYIYA_HOOK_CONTROL] == NULL) {
+ m_freem(m);
+ return (0);
+ }
+ int error;
+ NG_SEND_DATA_ONLY(error, priv->hooks[AYIYA_HOOK_CONTROL], m);
+ return (0);
+ }
+ }
+ /* NOTREACHED */
}
- m_freem(m);
- return (0);
+ case AYIYA_HOOK_CONTROL:
+ {
+ if (!priv->configured) {
+ m_freem(m);
+ return (ENOTCONN);
+ }
+
+ int error = ayiya_sign(&m, priv);
+ if (error != 0)
+ {
+ m_freem(m);
+ return (0);
+ }
+
+ NG_SEND_DATA_ONLY(error, priv->hooks[AYIYA_HOOK_AYIYA], m);
+ return (error);
}
default:
Modified: soc2015/roam/ng_ayiya/ng_ayiya.h
==============================================================================
--- soc2015/roam/ng_ayiya/ng_ayiya.h Mon Jun 29 18:56:53 2015 (r287734)
+++ soc2015/roam/ng_ayiya/ng_ayiya.h Mon Jun 29 19:03:13 2015 (r287735)
@@ -40,6 +40,17 @@
NGM_AYIYA_GET_MOTD,
};
+typedef enum {
+ AYIYA_OP_HEARTBEAT = 0,
+ AYIYA_OP_FORWARD = 1,
+ AYIYA_OP_ECHO = 2,
+ AYIYA_OP_ECHO_AND_FORWARD = 3,
+ AYIYA_OP_ECHO_RESP = 4,
+ AYIYA_OP_MOTD = 5,
+ AYIYA_OP_QUERY = 6,
+ AYIYA_OP_QUERY_RESP = 7,
+} ayiya_opcode;
+
struct ng_ayiya_header {
#if _BYTE_ORDER == _BIG_ENDIAN
unsigned idlen:4,
@@ -69,4 +80,24 @@
u_char signature[20];
} __packed;
+static inline size_t ayiya_offset_id(const struct ng_ayiya_header * const hdr) {
+ return (sizeof(*hdr));
+}
+
+static inline size_t ayiya_length_id(const struct ng_ayiya_header * const hdr) {
+ return (1 << hdr->idlen);
+}
+
+static inline size_t ayiya_offset_sig(const struct ng_ayiya_header * const hdr) {
+ return (ayiya_offset_id(hdr) + ayiya_length_id(hdr));
+}
+
+static inline size_t ayiya_length_sig(const struct ng_ayiya_header * const hdr) {
+ return (4 * hdr->siglen);
+}
+
+static inline size_t ayiya_offset_data(const struct ng_ayiya_header * const hdr) {
+ return (ayiya_offset_sig(hdr) + ayiya_length_sig(hdr));
+}
+
#endif
More information about the svn-soc-all
mailing list