+lldpd (0.7.2)
+ * Features
+ + Lock BPF interfaces before handing them to chrooted process on
+ BSD.
+
lldpd (0.7.1)
* Features
+ Mac OS X support, sponsored by Xcloud, Mac cloud server hosting
ifbsd_phys_init(struct lldpd *cfg,
struct lldpd_hardware *hardware)
{
- struct bpf_insn filter[] = { LLDPD_FILTER_F };
- struct ifreq ifr = {};
- struct bpf_program fprog = {
- .bf_insns = filter,
- .bf_len = sizeof(filter)/sizeof(struct bpf_insn)
- };
struct bpf_buffer *buffer = NULL;
- int fd = -1, enable, required;
+ int fd = -1;
log_debug("interfaces", "initialize ethernet device %s",
hardware->h_ifname);
- if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1)
return -1;
- /* We got a file descriptor to /dev/bpfXXX */
- /* Set buffer size */
- required = ETHER_MAX_LEN;
- if (ioctl(fd, BIOCSBLEN, (caddr_t)&required) < 0) {
- log_warn("interfaces",
- "unable to set receive buffer size for BPF on %s",
- hardware->h_ifname);
- goto end;
- }
+ /* Allocate receive buffer */
hardware->h_data = buffer =
- malloc(required + sizeof(struct bpf_buffer));
+ malloc(ETHER_MAX_LEN + sizeof(struct bpf_buffer));
if (buffer == NULL) {
log_warn("interfaces",
"unable to allocate buffer space for BPF on %s",
hardware->h_ifname);
goto end;
}
- buffer->len = required;
-
- /* Bind the interface to BPF device */
- strlcpy(ifr.ifr_name, hardware->h_ifname, IFNAMSIZ);
- if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
- log_warn("interfaces", "failed to bind interface %s to BPF",
- hardware->h_ifname);
- goto end;
- }
-
- /* Disable buffering */
- enable = 1;
- if (ioctl(fd, BIOCIMMEDIATE, (caddr_t)&enable) < 0) {
- log_warn("interfaces", "unable to disable buffering for %s",
- hardware->h_ifname);
- goto end;
- }
-
- /* Let us write the MAC address (raw packet mode) */
- enable = 1;
- if (ioctl(fd, BIOCSHDRCMPLT, (caddr_t)&enable) < 0) {
- log_warn("interfaces",
- "unable to set the `header complete` flag for %s",
- hardware->h_ifname);
- goto end;
- }
-
- /* Don't see sent packets */
-#ifdef HOST_OS_OPENBSD
- enable = BPF_DIRECTION_IN;
- if (ioctl(fd, BIOCSDIRFILT, (caddr_t)&enable) < 0) {
-#else
- enable = 0;
- if (ioctl(fd, BIOCSSEESENT, (caddr_t)&enable) < 0) {
-#endif
- log_warn("interfaces",
- "unable to set packet direction for BPF filter on %s",
- hardware->h_ifname);
- goto end;
- }
-
- /* Install read filter */
- if (ioctl(fd, BIOCSETF, (caddr_t)&fprog) < 0) {
- log_warn("interfaces", "unable to setup BPF filter for %s",
- hardware->h_ifname);
- goto end;
- }
-#ifdef BIOCSETWF
- /* Install write filter (optional) */
- if (ioctl(fd, BIOCSETWF, (caddr_t)&fprog) < 0) {
- log_info("interfaces", "unable to setup write BPF filter for %s",
- hardware->h_ifname);
- }
-#endif
+ buffer->len = ETHER_MAX_LEN;
/* Setup multicast */
interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
#include <linux/if_bridge.h>
#include <linux/wireless.h>
#include <linux/sockios.h>
-#include <linux/filter.h>
#include <linux/if_packet.h>
#include <linux/ethtool.h>
#define MAX_PORTS 1024
#define MAX_BRIDGES 1024
-static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
-static int
-iflinux_set_filter(const char *name, int fd)
-{
- struct sock_fprog prog;
- log_debug("interfaces", "set BPF filter for %s", name);
-
- memset(&prog, 0, sizeof(struct sock_fprog));
- prog.filter = lldpd_filter_f;
- prog.len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter);
-
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
- &prog, sizeof(prog)) < 0) {
- log_info("interfaces", "unable to change filter for %s", name);
- return ENETDOWN;
- }
- return 0;
-}
-
static int
iflinux_eth_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
- int fd, status;
+ int fd;
log_debug("interfaces", "initialize ethernet device %s",
hardware->h_ifname);
- if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex, hardware->h_ifname)) == -1)
return -1;
hardware->h_sendfd = fd; /* Send */
- /* Set filter */
- if ((status = iflinux_set_filter(hardware->h_ifname, fd)) != 0) {
- close(fd);
- return status;
- }
-
interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
levent_hardware_add_fd(hardware, fd); /* Receive */
iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
struct bond_master *master = hardware->h_data;
- int fd, status;
+ int fd;
int un = 1;
if (!master) return -1;
hardware->h_ifname);
/* First, we get a socket to the raw physical interface */
- if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex,
+ hardware->h_ifname)) == -1)
return -1;
hardware->h_sendfd = fd;
- if ((status = iflinux_set_filter(hardware->h_ifname, fd)) != 0) {
- close(fd);
- return status;
- }
interfaces_setup_multicast(cfg, hardware->h_ifname, 0);
/* Then, we open a raw interface for the master */
- if ((fd = priv_iface_init(master->index)) == -1) {
+ if ((fd = priv_iface_init(master->index, master->name)) == -1) {
close(hardware->h_sendfd);
return -1;
}
- if ((status = iflinux_set_filter(master->name, fd)) != 0) {
- close(hardware->h_sendfd);
- close(fd);
- return status;
- }
/* With bonding and older kernels (< 2.6.27) we need to listen
* to bond device. We use setsockopt() PACKET_ORIGDEV to get
* physical device instead of bond device (works with >=
continue;
}
if (init(cfg, hardware) != 0) {
- log_warn("interfaces",
+ log_warnx("interfaces",
"unable to initialize %s",
hardware->h_ifname);
lldpd_hardware_cleanup(cfg, hardware);
int priv_open(char*);
int priv_ethtool(char*, void*, size_t);
#endif
-int priv_iface_init(int);
+int priv_iface_init(int, char *);
int priv_iface_multicast(const char *, u_int8_t *, int);
int priv_snmp_socket(struct sockaddr_un *);
#include <netdb.h>
#ifdef HOST_OS_LINUX
# include <netpacket/packet.h> /* For sockaddr_ll */
+# include <linux/filter.h> /* For BPF filtering */
+#endif
+#if defined HOST_OS_FREEBSD || \
+ HOST_OS_NETBSD || \
+ HOST_OS_OPENBSD || \
+ HOST_OS_OSX
+# include <net/bpf.h>
#endif
#if defined HOST_OS_FREEBSD || HOST_OS_OSX
# include <net/if_dl.h>
#endif
int
-priv_iface_init(int index)
+priv_iface_init(int index, char *iface)
{
int cmd, rc;
+ char dev[IFNAMSIZ];
cmd = PRIV_IFACE_INIT;
must_write(remote, &cmd, sizeof(int));
must_write(remote, &index, sizeof(int));
+ strlcpy(dev, iface, IFNAMSIZ);
+ must_write(remote, dev, IFNAMSIZ);
must_read(remote, &rc, sizeof(int));
if (rc != 0) return -1;
return receive_fd(remote);
static void
asroot_iface_init()
{
-#if defined HOST_OS_LINUX
- struct sockaddr_ll sa;
- int s, rc = 0;
+ int rc = -1, fd = -1;
int ifindex;
-
+ char name[IFNAMSIZ];
must_read(remote, &ifindex, sizeof(ifindex));
+ must_read(remote, &name, sizeof(name));
+ name[sizeof(name) - 1] = '\0';
+#if defined HOST_OS_LINUX
/* Open listening socket to receive/send frames */
- if ((s = socket(PF_PACKET, SOCK_RAW,
+ if ((fd = socket(PF_PACKET, SOCK_RAW,
htons(ETH_P_ALL))) < 0) {
rc = errno;
must_write(remote, &rc, sizeof(rc));
return;
}
- memset(&sa, 0, sizeof(sa));
- sa.sll_family = AF_PACKET;
- sa.sll_protocol = 0;
- sa.sll_ifindex = ifindex;
- if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
+
+ struct sockaddr_ll sa = {
+ .sll_family = AF_PACKET,
+ .sll_ifindex = ifindex
+ };
+ if (bind(fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
rc = errno;
- must_write(remote, &rc, sizeof(rc));
- close(s);
- return;
+ log_warn("privsep",
+ "unable to bind to raw socket for interface %s",
+ name);
+ goto end;
}
- must_write(remote, &rc, sizeof(rc));
- send_fd(remote, s);
- close(s);
+
+ /* Set filter */
+ log_debug("privsep", "set BPF filter for %s", name);
+ static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
+ struct sock_fprog prog = {
+ .filter = lldpd_filter_f,
+ .len = sizeof(lldpd_filter_f) / sizeof(struct sock_filter)
+ };
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER,
+ &prog, sizeof(prog)) < 0) {
+ rc = errno;
+ log_info("privsep", "unable to change filter for %s", name);
+ goto end;
+ }
+
+ rc = 0;
+
#elif defined HOST_OS_FREEBSD || \
defined HOST_OS_OPENBSD || \
defined HOST_OS_NETBSD || \
defined HOST_OS_OSX
- int fd = -1, rc = 0, n = 0;
+ int n = 0;
+ int enable, required;
char dev[20];
- int ifindex;
-
- must_read(remote, &ifindex, sizeof(ifindex));
- /* Don't use ifindex */
+ struct bpf_insn filter[] = { LLDPD_FILTER_F };
+ struct ifreq ifr = {};
+ struct bpf_program fprog = {
+ .bf_insns = filter,
+ .bf_len = sizeof(filter)/sizeof(struct bpf_insn)
+ };
do {
snprintf(dev, sizeof(dev), "/dev/bpf%d", n++);
if (fd < 0) {
rc = errno;
log_warn("privsep", "unable to find a free BPF");
- must_write(remote, &rc, sizeof(rc));
- return;
+ goto end;
}
+ /* Set buffer size */
+ required = ETHER_MAX_LEN;
+ if (ioctl(fd, BIOCSBLEN, (caddr_t)&required) < 0) {
+ rc = errno;
+ log_warn("privsep",
+ "unable to set receive buffer size for BPF on %s",
+ name);
+ goto end;
+ }
+
+ /* Bind the interface to BPF device */
+ strlcpy(ifr.ifr_name, name, IFNAMSIZ);
+ if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ rc = errno;
+ log_warn("privsep", "failed to bind interface %s to BPF",
+ name);
+ goto end;
+ }
+
+ /* Disable buffering */
+ enable = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, (caddr_t)&enable) < 0) {
+ rc = errno;
+ log_warn("privsep", "unable to disable buffering for %s",
+ name);
+ goto end;
+ }
+
+ /* Let us write the MAC address (raw packet mode) */
+ enable = 1;
+ if (ioctl(fd, BIOCSHDRCMPLT, (caddr_t)&enable) < 0) {
+ rc = errno;
+ log_warn("privsep",
+ "unable to set the `header complete` flag for %s",
+ name);
+ goto end;
+ }
+
+ /* Don't see sent packets */
+#ifdef HOST_OS_OPENBSD
+ enable = BPF_DIRECTION_IN;
+ if (ioctl(fd, BIOCSDIRFILT, (caddr_t)&enable) < 0)
+#else
+ enable = 0;
+ if (ioctl(fd, BIOCSSEESENT, (caddr_t)&enable) < 0)
+#endif
+ {
+ rc = errno;
+ log_warn("privsep",
+ "unable to set packet direction for BPF filter on %s",
+ name);
+ goto end;
+ }
+
+ /* Install read filter */
+ if (ioctl(fd, BIOCSETF, (caddr_t)&fprog) < 0) {
+ rc = errno;
+ log_warn("privsep", "unable to setup BPF filter for %s",
+ name);
+ goto end;
+ }
+#ifdef BIOCSETWF
+ /* Install write filter (optional) */
+ if (ioctl(fd, BIOCSETWF, (caddr_t)&fprog) < 0) {
+ log_info("privsep", "unable to setup write BPF filter for %s",
+ name);
+ }
+#endif
+
+#ifdef BIOCLOCK
+ /* Lock interface */
+ if (ioctl(fd, BIOCLOCK, (caddr_t)&enable) < 0) {
+ rc = errno;
+ log_info("privsep", "unable to lock BPF interface %s",
+ name);
+ goto end;
+ }
+#endif
+
rc = 0;
- must_write(remote, &rc, sizeof(rc));
- send_fd(remote, fd);
- close(fd);
+
#else
#error Unsupported OS
#endif
+
+end:
+ must_write(remote, &rc, sizeof(rc));
+ if (rc == 0 && fd >=0) send_fd(remote, fd);
+ if (fd >= 0) close(fd);
}
static void