Index: olldpd/Makefile =================================================================== RCS file: olldpd/Makefile diff -N olldpd/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ olldpd/Makefile 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,12 @@ +PROG= olldpd +SRCS= lldpd.c +SRCS+= log.c +MAN= + +CFLAGS+= -Wall -Werror +DEBUG= -g + +LDADD+= -levent +DPADD+= ${LIBEVENT} + +.include Index: olldpd/lldpd.c =================================================================== RCS file: olldpd/lldpd.c diff -N olldpd/lldpd.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ olldpd/lldpd.c 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,696 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2024 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "log.h" + +int rdaemon(int); + +#define OLLDPD_USER "_olldpd" +#define OLLDPD_CTL_PATH "/var/run/olldpd.sock" + +#define CMSG_FOREACH(_cmsg, _msgp) \ + for ((_cmsg) = CMSG_FIRSTHDR((_msgp)); \ + (_cmsg) != NULL; \ + (_cmsg) = CMSG_NXTHDR((_msgp), (_cmsg))) + +static const uint8_t maddr[ETHER_ADDR_LEN] = + { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }; + +static inline int +cmsg_match(const struct cmsghdr *cmsg, size_t len, int level, int type) +{ + return (cmsg->cmsg_len == CMSG_LEN(len) && + cmsg->cmsg_level == level && cmsg->cmsg_type == type); +} + +#define CMSG_MATCH(_cmsg, _len, _level, _type) \ + cmsg_match((_cmsg), (_len), (_level), (_type)) + +struct iface; + +struct lldp_nei { + struct iface *nei_iface; + struct ether_addr nei_faddr; + struct ether_addr nei_laddr; + + TAILQ_ENTRY(lldp_nei) nei_entry; /* iface list */ + TAILQ_ENTRY(lldp_nei) nei_aentry; /* daemon list */ + unsigned int nei_refs; + + void * *nei_msg; + size_t nei_msglen; + +}; + +TAILQ_HEAD(lldp_neighbors, lldp_nei); + +struct iface_key { + unsigned int if_index; + char if_name[IFNAMSIZ]; +}; + +struct iface { + struct iface_key if_key; /* must be first */ + RBT_ENTRY(iface) if_entry; + + struct lldp_neighbors if_neighbors; +}; + +RBT_HEAD(ifaces, iface); + +static inline int + +iface_cmp(const struct iface *a, const struct iface *b) +{ + const struct iface_key *ka = &a->if_key; + const struct iface_key *kb = &b->if_key; + + if (ka->if_index > kb->if_index) + return (1); + if (ka->if_index < kb->if_index) + return (-1); + return (0); +} + +RBT_PROTOTYPE(ifaces, iface, if_entry, iface_cmp); + +struct olldpd_ctl { + struct olldpd *ctl_olldpd; + + struct event ctl_rd_ev; + struct event ctl_wr_ev; + + struct lldp_nei *ctl_nei; /* cursor */ +}; + +struct olldpd { + const char *ctl_path; + + struct event rt_ev; + struct event en_ev; + struct event ctl_ev; + + struct ifaces ifaces; + + struct lldp_neighbors neighbors; +}; + +static void rtsock_open(struct olldpd *); +static void rtsock_recv(int, short, void *); +static void ensock_open(struct olldpd *); +static void ensock_recv(int, short, void *); +static void ctlsock_open(struct olldpd *); +static void ctlsock_accept(int, short, void *); + +static int getall(struct olldpd *); + +extern char *__progname; + +__dead static void +usage(void) +{ + fprintf(stderr, "usage: %s [-d] [-s /path/to/ctl.sock]\n", __progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + struct olldpd _olldpd = { + .ctl_path = OLLDPD_CTL_PATH, + .ifaces = RBT_INITIALIZER(_olldpd.ifaces), + .neighbors = TAILQ_HEAD_INITIALIZER(_olldpd.neighbors), + }; + struct olldpd *olldpd = &_olldpd; /* let me use -> consistently */ + struct passwd *pw; + int debug = 0; + int devnull = -1; + + int ch; + + while ((ch = getopt(argc, argv, "ds:")) != -1) { + switch (ch) { + case 'd': + debug = 1; + break; + case 's': + olldpd->ctl_path = optarg; + break; + default: + usage(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage(); + + if (geteuid() != 0) + errx(1, "need root privileges"); + + pw = getpwnam(OLLDPD_USER); + if (pw == NULL) + errx(1, "no %s user", OLLDPD_USER); + + if (!debug) { + logger_syslog(__progname, LOG_DAEMON); + devnull = open(_PATH_DEVNULL, O_RDWR); + if (devnull == -1) + err(1, "%s", _PATH_DEVNULL); + } + + rtsock_open(olldpd); + ensock_open(olldpd); + ctlsock_open(olldpd); + + printf("debug = %d\n", debug); + + if (chroot(pw->pw_dir) == -1) + err(1, "chroot %s", pw->pw_dir); + if (chdir("/") == -1) + err(1, "chdir %s", pw->pw_dir); + + /* drop privs */ + if (setgroups(1, &pw->pw_gid) || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) + errx(1, "can't drop privileges"); + + pw = NULL; + endpwent(); + + if (getall(olldpd) == -1) + warn("getall"); + + if (!debug && rdaemon(devnull) == -1) + err(1, "unable to daemonize"); + + event_init(); + + event_set(&olldpd->rt_ev, EVENT_FD(&olldpd->rt_ev), + EV_READ|EV_PERSIST, rtsock_recv, olldpd); + event_set(&olldpd->en_ev, EVENT_FD(&olldpd->en_ev), + EV_READ|EV_PERSIST, ensock_recv, olldpd); + event_set(&olldpd->ctl_ev, EVENT_FD(&olldpd->ctl_ev), + EV_READ|EV_PERSIST, ctlsock_accept, olldpd); + + event_add(&olldpd->rt_ev, NULL); + event_add(&olldpd->en_ev, NULL); + event_add(&olldpd->ctl_ev, NULL); + + event_dispatch(); + + return (0); +} + +static void +rtsock_open(struct olldpd *olldpd) +{ + unsigned int rtfilter; + int s; + + s = socket(AF_ROUTE, SOCK_RAW | SOCK_NONBLOCK, AF_UNSPEC); + if (s == -1) + err(1, "route socket"); + + rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_IFANNOUNCE); + if (setsockopt(s, AF_ROUTE, ROUTE_MSGFILTER, + &rtfilter, sizeof(rtfilter)) == -1) + err(1, "route socket setsockopt msgfilter"); + + event_set(&olldpd->rt_ev, s, 0, NULL, NULL); +} + +static void +rtsock_recv(int s, short events, void *arg) +{ + char buf[1024]; + ssize_t rv; + + rv = recv(s, buf, sizeof(buf), 0); + if (rv == -1) { + lwarn("route message"); + return; + } + + linfo("route message: %zd bytes", rv); +} + +static void +ensock_open(struct olldpd *olldpd) +{ + struct sockaddr_frame sfrm = { + .sfrm_family = AF_FRAME, + .sfrm_proto = htons(ETHERTYPE_LLDP), + }; + int opt; + int s; + + s = socket(AF_FRAME, SOCK_DGRAM | SOCK_NONBLOCK, IFT_ETHER); + if (s == -1) + err(1, "Ethernet socket"); + + opt = 1; + if (setsockopt(s, IFT_ETHER, FRAME_RECVDSTADDR, + &opt, sizeof(opt)) == -1) + err(1, "Ethernet setsockopt recv dstaddr"); + + if (bind(s, (struct sockaddr *)&sfrm, sizeof(sfrm)) == -1) + err(1, "Ethernet bind lldp"); + + event_set(&olldpd->en_ev, s, 0, NULL, NULL); +} + +static void +ensock_recv(int s, short events, void *arg) +{ + struct olldpd *olldpd = arg; + struct sockaddr_frame sfrm; + uint8_t buf[1500]; + + struct ether_addr *ea = NULL; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + uint8_t buf[CMSG_SPACE(sizeof(*ea))]; + } cmsgbuf; + struct iovec iov[1] = { + { .iov_base = buf, .iov_len = sizeof(buf) }, + }; + struct msghdr msg = { + .msg_name = &sfrm, + .msg_namelen = sizeof(sfrm), + .msg_control = &cmsgbuf.buf, + .msg_controllen = sizeof(cmsgbuf.buf), + .msg_iov = iov, + .msg_iovlen = 1, + }; + ssize_t rv; + size_t len; + + struct iface *ifp; + struct iface_key key; + struct lldp_nei *nei; + + rv = recvmsg(s, &msg, 0); + if (rv == -1) { + lwarn("Ethernet recv"); + return; + } + + CMSG_FOREACH(cmsg, &msg) { + if (CMSG_MATCH(cmsg, + sizeof(*ea), IFT_ETHER, FRAME_RECVDSTADDR)) { + ea = (struct ether_addr *)CMSG_DATA(cmsg); + } + } + + printf("%zd bytes from %s", rv, + ether_ntoa((struct ether_addr *)sfrm.sfrm_addr)); + if (ea != NULL) + printf(" to %s", ether_ntoa(ea)); + printf(" on %s\n", sfrm.sfrm_ifname); + + key.if_index = sfrm.sfrm_ifindex; + ifp = RBT_FIND(ifaces, &olldpd->ifaces, (struct iface *)&key); + if (ifp == NULL) { + /* count */ + return; + } + + TAILQ_FOREACH(nei, &ifp->if_neighbors, nei_entry) { + if (memcmp(&nei->nei_faddr, sfrm.sfrm_addr, + sizeof(nei->nei_faddr)) == 0) + break; + } + + if (nei == NULL) { + nei = malloc(sizeof(*nei)); + if (nei == NULL) { + lwarn("interface %s: neighbor alloc", + ifp->if_key.if_name); + /* count drop */ + return; + } + nei->nei_iface = ifp; + memcpy(&nei->nei_faddr, sfrm.sfrm_addr, + sizeof(nei->nei_faddr)); + nei->nei_msg = NULL; + nei->nei_msglen = 0; + + nei->nei_refs = 1; + TAILQ_INSERT_TAIL(&ifp->if_neighbors, nei, nei_entry); + TAILQ_INSERT_TAIL(&olldpd->neighbors, nei, nei_aentry); + } + + len = rv; + if (len > nei->nei_msglen) { + void *msg = realloc(nei->nei_msg, len); + if (msg == NULL) { + lwarn("interface %s; pdu alloc", + ifp->if_key.if_name); + if (nei->nei_msg == NULL) { + TAILQ_REMOVE(&olldpd->neighbors, nei, + nei_aentry); + TAILQ_REMOVE(&ifp->if_neighbors, nei, + nei_entry); + free(nei); + } + /* count drop */ + return; + } + nei->nei_msg = msg; + } + + nei->nei_msglen = len; + memcpy(nei->nei_msg, buf, len); +} + +static void +ctlsock_open(struct olldpd *olldpd) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + }; + const char *path = olldpd->ctl_path; + mode_t oumask; + int s; + + if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= + sizeof(sun.sun_path)) + errc(ENAMETOOLONG, 1, "control socket %s", path); + + s = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); + if (s == -1) + err(1, "control socket"); + + /* try connect first? */ + + if (unlink(path) == -1) { + if (errno != ENOENT) + err(1, "control socket %s unlink", path); + } + + oumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + if (oumask == -1) + err(1, "umask"); + if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(1, "control socket %s bind", path); + if (umask(oumask) == -1) + err(1, "umask restore"); + + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) + err(1, "control socket %s chmod", path); + + if (listen(s, 5) == -1) + err(1, "control socket %s listen", path); + + event_set(&olldpd->ctl_ev, s, 0, NULL, NULL); +} + +static struct lldp_nei * +lldp_nei_take(struct olldpd *olldpd, struct lldp_nei *nei) +{ + nei->nei_refs++; + return (nei); +} + +static void +lldp_nei_rele(struct olldpd *olldpd, struct lldp_nei *nei) +{ + if (--nei->nei_refs == 0) { + TAILQ_REMOVE(&olldpd->neighbors, nei, nei_aentry); + free(nei); + } +} + +static void +ctl_close(struct olldpd *olldpd, struct olldpd_ctl *ctl) +{ + int fd = EVENT_FD(&ctl->ctl_rd_ev); + struct lldp_nei *nei = ctl->ctl_nei; + + if (nei != NULL) + lldp_nei_rele(olldpd, nei); + event_del(&ctl->ctl_rd_ev); + event_del(&ctl->ctl_wr_ev); + free(ctl); + close(fd); +} + +static void +ctl_recv(int fd, short events, void *arg) +{ + struct olldpd_ctl *ctl = arg; + struct olldpd *olldpd = ctl->ctl_olldpd; + uint8_t buf[1024]; + ssize_t rv; + + rv = recv(fd, buf, sizeof(buf), 0); + if (rv == -1) { + lwarn("ctl recv"); + return; + } + if (rv == 0) { + ctl_close(olldpd, ctl); + return; + } + + linfo("%s: %zd bytes", __func__, rv); +} + +static void +ctl_send(int fd, short events, void *arg) +{ + struct olldpd_ctl *ctl = arg; + struct olldpd *olldpd = ctl->ctl_olldpd; + struct lldp_nei *nei = ctl->ctl_nei; + struct iface *ifp; + struct lldp_nei *nnei; + ssize_t rv; + + struct sockaddr_frame sfrm = { + .sfrm_family = AF_FRAME, + .sfrm_proto = htons(ETHERTYPE_LLDP), + }; + struct iovec iov[2] = { { &sfrm, sizeof(sfrm) } }; + struct msghdr msg = { + .msg_iov = iov, + .msg_iovlen = 2, + }; + + ifp = nei->nei_iface; + if (ifp != NULL) { + sfrm.sfrm_ifindex = ifp->if_key.if_index; + strlcpy(sfrm.sfrm_ifname, ifp->if_key.if_name, + sizeof(sfrm.sfrm_ifname)); + } + memcpy(sfrm.sfrm_addr, &nei->nei_faddr, sizeof(nei->nei_faddr)); + + iov[1].iov_base = nei->nei_msg; + iov[1].iov_len = nei->nei_msglen; + + rv = sendmsg(fd, &msg, 0); + if (rv == -1) { + lwarn("ctl send"); + return; + } + + nnei = TAILQ_NEXT(nei, nei_aentry); + if (nnei == NULL) { + ctl_close(olldpd, ctl); + return; + } + ctl->ctl_nei = lldp_nei_take(olldpd, nnei); + lldp_nei_rele(olldpd, nei); + + event_add(&ctl->ctl_wr_ev, NULL); +} + +static void +ctlsock_accept(int s, short events, void *arg) +{ + struct olldpd *olldpd = arg; + struct olldpd_ctl *ctl; + struct lldp_nei *nei; + int fd; + + fd = accept4(s, NULL, NULL, SOCK_NONBLOCK); + if (fd == -1) { + lwarn("control socket %s accept", olldpd->ctl_path); + return; + } + + linfo("%s: hi", __func__); + + nei = TAILQ_FIRST(&olldpd->neighbors); + if (nei == NULL) { + close(fd); + return; + } + linfo("%s: hihi", __func__); + + ctl = malloc(sizeof(*ctl)); + if (ctl == NULL) { + lwarn("ctl alloc"); + close(fd); + return; + } + ctl->ctl_olldpd = olldpd; + linfo("%s: hihihi", __func__); + + event_set(&ctl->ctl_rd_ev, fd, EV_READ|EV_PERSIST, + ctl_recv, ctl); + event_set(&ctl->ctl_wr_ev, fd, EV_WRITE, + ctl_send, ctl); + + ctl->ctl_nei = lldp_nei_take(olldpd, nei); + ctl_send(fd, EV_WRITE, ctl); +} + +static int +getall(struct olldpd *olldpd) +{ + struct ifaddrs *ifa0, *ifa; + struct sockaddr_dl *sdl; + struct if_data *ifi; + struct iface *ifp; + struct frame_mreq fmr; + + if (getifaddrs(&ifa0) == -1) + return (-1); + + for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + ifi = ifa->ifa_data; + if (ifi->ifi_type != IFT_ETHER) + continue; + + sdl = (struct sockaddr_dl *)ifa->ifa_addr; + if (sdl->sdl_index == 0) { + warnx("interface %s has index 0, skipping", + ifa->ifa_name); + continue; + } + + printf("%s index %u\n", ifa->ifa_name, sdl->sdl_index); + + ifp = malloc(sizeof(*ifp)); + if (ifp == NULL) { + warn("interface %s allocation", ifa->ifa_name); + continue; + } + + ifp->if_key.if_index = sdl->sdl_index; + strlcpy(ifp->if_key.if_name, ifa->ifa_name, + sizeof(ifp->if_key.if_name)); + + TAILQ_INIT(&ifp->if_neighbors); + + if (RBT_INSERT(ifaces, &olldpd->ifaces, ifp) != NULL) { + warnx("interface %s: index %u already exists", + ifa->ifa_name, ifp->if_key.if_index); + free(ifp); + } + + memset(&fmr, 0, sizeof(fmr)); + fmr.fmr_ifindex = ifp->if_key.if_index; + memcpy(fmr.fmr_addr, maddr, ETHER_ADDR_LEN); + + if (setsockopt(EVENT_FD(&olldpd->en_ev), + IFT_ETHER, FRAME_ADD_MEMBERSHIP, + &fmr, sizeof(fmr)) == -1) + warn("interface %s: add membership", ifa->ifa_name); + } + + freeifaddrs(ifa0); + + return (0); +} + +RBT_GENERATE(ifaces, iface, if_entry, iface_cmp); + +/* daemon(3) clone, intended to be used in a "r"estricted environment */ +int +rdaemon(int devnull) +{ + if (devnull == -1) { + errno = EBADF; + return (-1); + } + if (fcntl(devnull, F_GETFL) == -1) + return (-1); + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return (-1); + + (void)dup2(devnull, STDIN_FILENO); + (void)dup2(devnull, STDOUT_FILENO); + (void)dup2(devnull, STDERR_FILENO); + if (devnull > 2) + (void)close(devnull); + + return (0); +} Index: olldpd/log.c =================================================================== RCS file: olldpd/log.c diff -N olldpd/log.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ olldpd/log.c 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,150 @@ + +/* + * Copyright (c) 2008 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +static const struct __logger conslogger = { + err, + errx, + warn, + warnx, + warnx, /* info */ + warnx /* debug */ +}; + +__dead static void syslog_err(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +__dead static void syslog_errx(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +static void syslog_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +static void syslog_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +static void syslog_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +static void syslog_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +static void syslog_vstrerror(int, int, const char *, va_list) + __attribute__((__format__ (printf, 3, 0))); + +static const struct __logger syslogger = { + syslog_err, + syslog_errx, + syslog_warn, + syslog_warnx, + syslog_info, + syslog_debug +}; + +const struct __logger *__logger = &conslogger; + +void +logger_syslog(const char *progname, int facility) +{ + openlog(progname, LOG_PID | LOG_NDELAY, facility); + tzset(); + + __logger = &syslogger; +} + +static void +syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) +{ + char *s; + + if (vasprintf(&s, fmt, ap) == -1) { + syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror"); + exit(1); + } + + syslog(priority, "%s: %s", s, strerror(e)); + + free(s); +} + +static void +syslog_err(int ecode, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + syslog_vstrerror(errno, LOG_CRIT, fmt, ap); + va_end(ap); + + exit(ecode); +} + +static void +syslog_errx(int ecode, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_CRIT, fmt, ap); + va_end(ap); + + exit(ecode); +} + +static void +syslog_warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + syslog_vstrerror(errno, LOG_ERR, fmt, ap); + va_end(ap); +} + +static void +syslog_warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); +} + +static void +syslog_info(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_INFO, fmt, ap); + va_end(ap); +} + +static void +syslog_debug(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(LOG_DEBUG, fmt, ap); + va_end(ap); +} Index: olldpd/log.h =================================================================== RCS file: olldpd/log.h diff -N olldpd/log.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ olldpd/log.h 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,47 @@ + +/* + * Copyright (c) 2008 David Gwynne + * + * 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 _LOG_H_ +#define _LOG_H_ + +struct __logger { + __dead void (*err)(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); + __dead void (*errx)(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); + void (*warn)(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); + void (*warnx)(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); + void (*info)(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); + void (*debug)(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +}; + +extern const struct __logger *__logger; + +#define lerr(_e, _f...) __logger->err((_e), _f) +#define lerrx(_e, _f...) __logger->errx((_e), _f) +#define lwarn(_f...) __logger->warn(_f) +#define lwarnx(_f...) __logger->warnx(_f) +#define linfo(_f...) __logger->info(_f) +#define ldebug(_f...) __logger->debug(_f) + +void logger_syslog(const char *, int); + +#endif /* _LOG_H_ */ Index: lldp/Makefile =================================================================== RCS file: lldp/Makefile diff -N lldp/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lldp/Makefile 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,8 @@ +PROG= lldp +SRCS= lldp.c +MAN= + +CFLAGS+= -Wall -Werror +DEBUG= -g + +.include Index: lldp/lldp.c =================================================================== RCS file: lldp/lldp.c diff -N lldp/lldp.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lldp/lldp.c 18 Dec 2024 02:41:22 -0000 @@ -0,0 +1,116 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2024 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include /* IFNAMSIZ */ +#include + +#include +#include /* ether_ntoa */ + +#include +#include +#include + +static void hexdump(const void *, size_t); + +int +main(int argc, char *argv[]) +{ + struct sockaddr_un sun = { + .sun_family = AF_UNIX, + .sun_path = "/var/run/olldpd.sock", + }; + int s; + + s = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (s == -1) + err(1, "socket"); + + if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(1, "%s connect", sun.sun_path); + + for (;;) { + struct sockaddr_frame sfrm; + char buf[2048]; + struct iovec iov[2] = { + { &sfrm, sizeof(sfrm) }, + { buf, sizeof(buf) }, + }; + struct msghdr msg = { + .msg_iov = iov, + .msg_iovlen = 2, + }; + ssize_t rv; + + rv = recvmsg(s, &msg, 0); + if (rv == -1) + err(1, "recv"); + if (rv == 0) + break; + + if (rv < sizeof(sfrm)) { + warnx("too short for sockaddr_frame\n"); + continue; + } + if (sfrm.sfrm_family != AF_FRAME) { + warnx("unexpected address family"); + continue; + } + + rv -= sizeof(sfrm); + printf("%s nei %s\n", sfrm.sfrm_ifname, + ether_ntoa((struct ether_addr *)sfrm.sfrm_addr)); + hexdump(buf, rv); + } + + return (0); +} + +static int +printable(int ch) +{ + if (ch == '\0') + return ('_'); + if (!isprint(ch)) + return ('~'); + + return (ch); +} + +static void +hexdump(const void *d, size_t datalen) +{ + const uint8_t *data = d; + size_t i, j = 0; + + for (i = 0; i < datalen; i += j) { + printf("%4zu: ", i); + for (j = 0; j < 16 && i+j < datalen; j++) + printf("%02x ", data[i + j]); + while (j++ < 16) + printf(" "); + printf("|"); + for (j = 0; j < 16 && i+j < datalen; j++) + putchar(printable(data[i + j])); + printf("|\n"); + } +}