/* * Write a packet to a data socket. The packet will be sent * out the corresponding node on the specified hook. * Returns -1 if error and sets errno. */ int NgSendData(int ds, const char *hook, const u_char * buf, size_t len) { u_char sgbuf[NG_HOOKSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; int errnosv; /* Set up destination hook */ sg->sg_family = AF_NETGRAPH; strlcpy(sg->sg_data, hook, NG_HOOKSIZ); sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("WRITE PACKET to hook \"%s\" (%d bytes)", hook, len); _NgDebugSockaddr(sg); if (_gNgDebugLevel >= 3) _NgDebugBytes(buf, len); } /* Send packet */ if (sendto(ds, buf, len, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("sendto(%s)", sg->sg_data); errno = errnosv; return (-1); } /* Done */ return (0); }
/* * Receive a control message. * * On error, this returns -1 and sets errno. * Otherwise, it returns the length of the received reply. */ int NgRecvMsg(int cs, struct ng_mesg *rep, size_t replen, char *path) { u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; socklen_t sglen = sizeof(sgbuf); int len, errnosv; /* Read reply */ len = recvfrom(cs, rep, replen, 0, (struct sockaddr *) sg, &sglen); if (len < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recvfrom"); goto errout; } if (path != NULL) strlcpy(path, sg->sg_data, NG_PATHSIZ); /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("RECEIVED %s:", (rep->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); _NgDebugSockaddr(sg); _NgDebugMsg(rep, sg->sg_data); } /* Done */ return (len); errout: errno = errnosv; return (-1); }
/* * Read a packet from a data socket * Returns -1 if error and sets errno. */ int NgRecvData(int ds, u_char * buf, size_t len, char *hook) { u_char frombuf[NG_HOOKSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const from = (struct sockaddr_ng *) frombuf; socklen_t fromlen = sizeof(frombuf); int rtn, errnosv; /* Read packet */ rtn = recvfrom(ds, buf, len, 0, (struct sockaddr *) from, &fromlen); if (rtn < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("recvfrom"); errno = errnosv; return (-1); } /* Copy hook name */ if (hook != NULL) strlcpy(hook, from->sg_data, NG_HOOKSIZ); /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("READ %s from hook \"%s\" (%d bytes)", rtn ? "PACKET" : "EOF", from->sg_data, rtn); if (_gNgDebugLevel >= 3) _NgDebugBytes(buf, rtn); } /* Done */ return (rtn); }
/* * Assign a globally unique name to a node * Returns -1 if error and sets errno. */ int NgNameNode(int cs, const char *path, const char *fmt, ...) { struct ngm_name ngn; va_list args; /* Build message arg */ va_start(args, fmt); vsnprintf(ngn.name, sizeof(ngn.name), fmt, args); va_end(args); /* Send message */ if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE, NGM_NAME, &ngn, sizeof(ngn)) < 0) { if (_gNgDebugLevel >= 1) NGLOGX("%s: failed", __func__); return (-1); } /* Done */ return (0); }
/* * Dump bytes in hex */ void _NgDebugBytes(const u_char *ptr, int len) { char buf[100]; int k, count; #define BYPERLINE 16 for (count = 0; count < len; ptr += BYPERLINE, count += BYPERLINE) { /* Do hex */ snprintf(buf, sizeof(buf), "%04x: ", count); for (k = 0; k < BYPERLINE; k++, count++) if (count < len) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%02x ", ptr[k]); else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " "); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " "); count -= BYPERLINE; /* Do ASCII */ for (k = 0; k < BYPERLINE; k++, count++) if (count < len) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c", isprint(ptr[k]) ? ptr[k] : '.'); else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " "); count -= BYPERLINE; /* Print it */ NGLOGX("%s", buf); } }
/* * Display a negraph message */ void _NgDebugMsg(const struct ng_mesg *msg, const char *path) { u_char buf[2 * sizeof(struct ng_mesg) + ARGS_BUFSIZE]; struct ng_mesg *const req = (struct ng_mesg *)buf; struct ng_mesg *const bin = (struct ng_mesg *)req->data; int arglen, csock = -1; /* Display header stuff */ NGLOGX("NG_MESG :"); NGLOGX(" vers %d", msg->header.version); NGLOGX(" arglen %d", msg->header.arglen); NGLOGX(" flags %u", msg->header.flags); NGLOGX(" token %u", msg->header.token); NGLOGX(" cookie %s (%d)", NgCookie(msg->header.typecookie), msg->header.typecookie); /* At lower debugging levels, skip ASCII translation */ if (_gNgDebugLevel <= 2) goto fail2; /* If path is not absolute, don't bother trying to use relative address on a different socket for the ASCII translation */ if (strchr(path, ':') == NULL) goto fail2; /* Get a temporary socket */ if (NgMkSockNode(NULL, &csock, NULL) < 0) goto fail; /* Copy binary message into request message payload */ arglen = msg->header.arglen; if (arglen > ARGS_BUFSIZE) arglen = ARGS_BUFSIZE; memcpy(bin, msg, sizeof(*msg) + arglen); bin->header.arglen = arglen; /* Lower debugging to avoid infinite recursion */ _gNgDebugLevel -= RECURSIVE_DEBUG_ADJUST; /* Ask the node to translate the binary message to ASCII for us */ if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_BINARY2ASCII, bin, sizeof(*bin) + bin->header.arglen) < 0) { _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; goto fail; } if (NgRecvMsg(csock, req, sizeof(buf), NULL) < 0) { _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; goto fail; } /* Restore debugging level */ _gNgDebugLevel += RECURSIVE_DEBUG_ADJUST; /* Display command string and arguments */ NGLOGX(" cmd %s (%d)", bin->header.cmdstr, bin->header.cmd); NGLOGX(" args %s", bin->data); goto done; fail: /* Just display binary version */ NGLOGX(" [error decoding message: %s]", strerror(errno)); fail2: NGLOGX(" cmd %d", msg->header.cmd); NGLOGX(" args (%d bytes)", msg->header.arglen); _NgDebugBytes(msg->data, msg->header.arglen); done: if (csock != -1) (void)close(csock); }
/* * Display a netgraph sockaddr */ void _NgDebugSockaddr(const struct sockaddr_ng *sg) { NGLOGX("SOCKADDR: { fam=%d len=%d addr=\"%s\" }", sg->sg_family, sg->sg_len, sg->sg_data); }
/* * Send a message to a node using control socket node "cs". * Returns -1 if error and sets errno appropriately, otherwise zero. */ static int NgDeliverMsg(int cs, const char *path, const struct ng_mesg *hdr, const void *args, size_t arglen) { u_char sgbuf[NG_PATHSIZ + NGSA_OVERHEAD]; struct sockaddr_ng *const sg = (struct sockaddr_ng *) sgbuf; u_char *buf = NULL; struct ng_mesg *msg; int errnosv = 0; int rtn = 0; /* Sanity check */ if (args == NULL) arglen = 0; /* Get buffer */ if ((buf = malloc(sizeof(*msg) + arglen)) == NULL) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("malloc"); rtn = -1; goto done; } msg = (struct ng_mesg *) buf; /* Finalize message */ *msg = *hdr; msg->header.arglen = arglen; memcpy(msg->data, args, arglen); /* Prepare socket address */ sg->sg_family = AF_NETGRAPH; /* XXX handle overflow */ strlcpy(sg->sg_data, path, NG_PATHSIZ); sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD; /* Debugging */ if (_gNgDebugLevel >= 2) { NGLOGX("SENDING %s:", (msg->header.flags & NGF_RESP) ? "RESPONSE" : "MESSAGE"); _NgDebugSockaddr(sg); _NgDebugMsg(msg, sg->sg_data); } /* Send it */ if (sendto(cs, msg, sizeof(*msg) + arglen, 0, (struct sockaddr *) sg, sg->sg_len) < 0) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("sendto(%s)", sg->sg_data); rtn = -1; goto done; } /* Wait for reply if there should be one. */ if (msg->header.cmd & NGM_HASREPLY && !(msg->header.flags & NGF_RESP)) { struct pollfd rfds; int n; rfds.fd = cs; rfds.events = POLLIN; rfds.revents = 0; n = poll(&rfds, 1, INFTIM); if (n == -1) { errnosv = errno; if (_gNgDebugLevel >= 1) NGLOG("poll"); rtn = -1; } } done: /* Done */ free(buf); /* OK if buf is NULL */ errno = errnosv; return (rtn); }