Date: Mon, 29 Jun 2015 19:03:13 GMT From: roam@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r287735 - in soc2015/roam: . ayiya_resp ng_ayiya Message-ID: <201506291903.t5TJ3DMa067409@socsvn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506291903.t5TJ3DMa067409>