pfild.c revision ed98f1ae92c0bb2fe51326c2720e493efd56e9bc
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Copyright (C) 2003 by Darren Reed.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * See the IPFILTER.LICENCE file for details on licencing.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Use is subject to license terms.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#pragma ident "%Z%%M% %I% %E% SMI"
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <sys/types.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <sys/socket.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <sys/sockio.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <net/if.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <net/route.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <unistd.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <errno.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <string.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <fcntl.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <poll.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <stdio.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <malloc.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <stropts.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <stdlib.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <netinet/ip.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <netinet/ip6.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <netinet/icmp6.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include "pfild.h"
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsextern int vas(const struct pfil_ifaddrs *, int);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * pfild.c: interface data and packet transmission daemon for pfil
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * pfild provides the pfil kernel module with certain data that are not
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * directly available to kernel code using supported OS interfaces. pfild
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * accesses the routing tables and network interface parameters using
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * interfaces readily available to a user space daemon, copies the data into
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * the kernel via /dev/pfil, and waits for any changes to the data.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * pfild also provides a way for the kernel module to originate IP packets
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * without resorting to unsupported kernel interfaces. If the kernel
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * sends up an M_DATA message, pfild sends it on a raw IP socket so that it
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * gets routed and transmitted as a normal packet.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/* file descriptors for talking to pfil, ifnet, routing kernel modules */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int pfil_fd, ip_fd, icmp6_ip6_fd, tcp_ip6_fd, route_fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * flag indicates that some interface or routing data have changed since
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * last update.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int flag = 1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * debuglevel indicates to what level debugging messages should be emitted.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int debuglevel = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/* Wait for this many ms of quiet time after changes before doing an update. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#define QUIETTIME 200
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Send a message to the pfil kernel module.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Returns zero for success, otherwise non-zero with errror in errno.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsint
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewspfil_msg(uint32_t cmd, void *buf, size_t len)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int error;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, "pfil_msg(%x,%p,%d)\n", cmd, buf, len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pfil_fd >= 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct strbuf ctl, data;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ctl.buf = (void *)&cmd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ctl.len = sizeof (cmd);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews data.buf = buf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews data.len = len;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews error = putmsg(pfil_fd, &ctl, &data, 0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:pfil_msg():putmsg(%d,%p,%p,0) = %d\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pfil_fd, &ctl, &data, 0, error);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews error = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:pfil_msg():pfil_fd < 0\n");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (error);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Handle a PF_ROUTE message. If an address has been added or deleted, treat
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * this as an indication that some interface data has been udpated. If a route
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * has been added or deleted, treat this as an indication that the routing
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * table has been updated. The current implementation completely updates both
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * sets of data when either kind of change is indicated.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * p points to, and size indicates the size of, the message.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic void
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewshandle_msg(const ifa_msghdr_t *p, size_t size)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (size < sizeof (*p) ||
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews size < p->ifam_msglen ||
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews p->ifam_version != RTM_VERSION) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "Not a valid version %u RTM message - "
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "%u bytes version %u\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews RTM_VERSION, size, p->ifam_version);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews switch (p->ifam_type) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case RTM_NEWADDR:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case RTM_DELADDR:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case RTM_ADD:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case RTM_DELETE:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews flag = 1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews break;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews default:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews break;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:handle_msg(): msg rcvd %d flag %d\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews p->ifam_type, flag);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#include <arpa/inet.h>
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic const char *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsdumpaddr(void *p)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews static char buf[INET6_ADDRSTRLEN];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct sockaddr_in *sin = p;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct sockaddr_in6 *sin6 = p;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews switch (sin->sin_family) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case AF_INET:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (inet_ntop(sin->sin_family, &sin->sin_addr, buf,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (buf)));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case AF_INET6:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (inet_ntop(sin6->sin6_family, &sin6->sin6_addr, buf,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (buf)));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews default:
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return ("<none>");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#define ERRBUFSIZE 100
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic char errbuf[ERRBUFSIZE];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#define LIFN_MARGIN 5 /* a few extra in case things are changing */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Fetch the address configuration data for all interfaces and push it into
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * the pfil kernel module. Fetch the routing table, compute the valid address
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * set data for all interfaces and push it into the pfil kernel module.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsdo_update(void)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int numifs, i;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct lifreq *lifrbuf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct lifconf lifc;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct pfil_ifaddrs *ifaddrlist;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct lifnum lifn;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews const int lifc_flags = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews void *buf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews size_t bufsize;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews flag = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifn.lifn_family = AF_UNSPEC;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifn.lifn_flags = lifc_flags;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(ip_fd, SIOCGLIFNUM, (char *)&lifn) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFNUM: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews bufsize = (lifn.lifn_count + LIFN_MARGIN) * sizeof (struct lifreq);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews buf = malloc(bufsize);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (buf == NULL) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "malloc: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifrbuf = buf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifc.lifc_family = AF_UNSPEC;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifc.lifc_flags = lifc_flags;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifc.lifc_buf = buf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews lifc.lifc_len = bufsize;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(ip_fd, SIOCGLIFCONF, (char *)&lifc) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFCONF: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews numifs = lifc.lifc_len / sizeof (struct lifreq);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Allocate memory for the number of interfaces retrieved. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist = calloc(numifs, sizeof (struct pfil_ifaddrs));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ifaddrlist == NULL) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "calloc: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Populate the interface entries in the ifaddrlist. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews for (i = 0; i < numifs; i++) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int isv6 = (lifrbuf[i].lifr_addr.ss_family == AF_INET6);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int fd = (isv6 ? icmp6_ip6_fd : ip_fd);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) strncpy(ifaddrlist[i].name, lifrbuf[i].lifr_name,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].localaddr, &lifrbuf[i].lifr_addr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (ifaddrlist[i].localaddr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFNETMASK, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFNETMASK %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name, strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].netmask, &lifrbuf[i].lifr_addr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (ifaddrlist[i].netmask));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFBRDADDR, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (errno != EADDRNOTAVAIL) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFBRDADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].broadaddr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews &lifrbuf[i].lifr_broadaddr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (ifaddrlist[i].broadaddr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFDSTADDR, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (errno != EADDRNOTAVAIL) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFDSTADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].dstaddr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews &lifrbuf[i].lifr_dstaddr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (ifaddrlist[i].dstaddr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFMTU, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFDSTADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].mtu = lifrbuf[i].lifr_mtu;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, "%.*s:\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, " localaddr %s (%d)\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews dumpaddr(&ifaddrlist[i].localaddr),
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].localaddr.in.sin_family);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, " netmask %s (%d)\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews dumpaddr(&ifaddrlist[i].netmask),
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].netmask.in.sin_family);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, " broadaddr %s (%d)\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews dumpaddr(&ifaddrlist[i].broadaddr),
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].broadaddr.in.sin_family);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, " dstaddr %s (%d)\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews dumpaddr(&ifaddrlist[i].dstaddr),
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].dstaddr.in.sin_family);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, " mtu %u\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist[i].mtu);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(buf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Now send this table of interfaces and addresses down into
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * the pfil kernel module.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pfil_msg(PFILCMD_IFADDRS,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist, i * sizeof (struct pfil_ifaddrs)) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "PFILCMD_IFADDRS: %s", strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Next, compute and send the table of valid addresses.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (vas(ifaddrlist, numifs) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "PFILCMD_IFADDRSET: %s", strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews free(ifaddrlist);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Send an IPv6 packet out from the system using sendmsg on the raw IP socket
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * through the ancillary data.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewssend_ip6_pkt(const void *pkt, size_t len)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews const struct ip6_hdr *iph = pkt;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct sockaddr_in6 sin6;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct iovec iovec;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct msghdr msghdr;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct cmsghdr *cmsgp;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct in6_pktinfo *pktinfop;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews unsigned char ancdatabuf[sizeof (*cmsgp) + sizeof (*pktinfop) + 100];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews size_t ancdatalen;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews cmsgp = (struct cmsghdr *)ancdatabuf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews cmsgp->cmsg_len = ((char *)(pktinfop + 1) - (char *)cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews cmsgp->cmsg_level = IPPROTO_IPV6;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews cmsgp->cmsg_type = IPV6_PKTINFO;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews memcpy(&pktinfop->ipi6_addr, &iph->ip6_src,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sizeof (pktinfop->ipi6_addr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pktinfop->ipi6_ifindex = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ancdatalen = ((char *)(pktinfop + 1) - (char *)cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin6.sin6_family = AF_INET6;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews memcpy(&sin6.sin6_addr, &iph->ip6_dst, sizeof (sin6.sin6_addr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin6.sin6_port = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin6.sin6_scope_id = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin6.sin6_flowinfo = iph->ip6_flow & IPV6_FLOWINFO_TCLASS;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews iovec.iov_base = (char *)(iph + 1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews iovec.iov_len = len - sizeof (*iph);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_name = &sin6;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_namelen = sizeof (sin6);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_iov = &iovec;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_iovlen = 1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_control = ancdatabuf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_controllen = ancdatalen;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews msghdr.msg_flags = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (iph->ip6_nxt == IPPROTO_ICMPV6)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fd = icmp6_ip6_fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews else if (iph->ip6_nxt == IPPROTO_TCP)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fd = tcp_ip6_fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews errno = EPROTONOSUPPORT;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (sendmsg(fd, &msghdr, 0));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Send an arbitrary IP packet out from the system using sendto/sendmsg on the
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * raw IP socket. Due to the awkwardness of the IPv6 socket API, IPv6 packets
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * are limited to ICMP and TCP; other protocols are dropped.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic void
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewssendpkt(const void *buf, int len)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews const struct ip *iph = buf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int n;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (debuglevel > 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr, "pfild sendpkt %u bytes:\n", len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr, " %08X %08X %08X %08X\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[0],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[1],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[2],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[3]);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr, " %08X %08X %08X %08X\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[4],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[5],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[6],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[7]);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr, " %08X %08X %08X %08X\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[8],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[9],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[10],
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ((uint32_t *)buf)[11]);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (iph->ip_v == 4 && len >= 20) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct sockaddr_in sin;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin.sin_family = AF_INET;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin.sin_port = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin.sin_addr = iph->ip_dst;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = sendto(ip_fd, buf, len, 0, (void *)&sin, sizeof (sin));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else if (iph->ip_v == 6 && len > 40) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = send_ip6_pkt(buf, len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews } else {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = -1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews errno = EINVAL;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: raw socket send");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic void usage(const char *prog)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr, "%s: [-d]\n", prog);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews exit(1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsint
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsmain(int argc, char *argv[])
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews{
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int c, n;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews const int on = 1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int make_daemon = 1;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct pollfd pollfds[2];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews union { char bytes[1024]; ifa_msghdr_t msg; } buffer;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int pid;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct icmp6_filter filter;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews while ((c = getopt(argc, argv, "d")) != -1) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews switch (c) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case '?' :
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews usage(argv[0]);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews break;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews case 'd' :
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews make_daemon = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews debuglevel++;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews break;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pfil_fd = open("/dev/pfil", O_RDWR);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pfil_fd < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: open(/dev/pfil)");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ip_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ip_fd < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet socket");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (setsockopt(ip_fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet socket IP_HDRINCL option");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews icmp6_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (icmp6_ip6_fd < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet6 ICMP6 socket");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * ICMPv6 raw socket by default passes all ICMPv6 message received
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * to the application. We don't care about them, so simply block them
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * all.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ICMP6_FILTER_SETBLOCKALL(&filter);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (setsockopt(icmp6_ip6_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews &filter, sizeof (filter)) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet6 ICMP6 socket type filtering option");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews tcp_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (tcp_ip6_fd < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet6 TCP socket");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews route_fd = socket(PF_ROUTE, SOCK_RAW, 0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (route_fd < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: socket(PF_ROUTE)");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (make_daemon) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Background */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if ((pid = fork()) > 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pid < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, "%s: fork() failed %s\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews argv[0], strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* NOTREACHED */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) setsid();
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) close(0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) close(1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) close(2);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) open("/dev/null", O_RDWR);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) dup(0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) dup(0);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) chdir("/");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /*
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Main loop: Poll for messages from PF_ROUTE socket or pfil stream.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * PF_ROUTE messages may indicate a need to update the kernel module's
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * interface data. pfil messages contain packets to be transmitted.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Errors in processing don't terminate the program, but errors in
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * polling will terminate the program to avoid busy looping.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pollfds[0].fd = route_fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pollfds[0].events = POLLRDNORM;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pollfds[1].fd = pfil_fd;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pollfds[1].events = POLLRDNORM;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews while (1) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (flag) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Wait for a moment of quiet, then do the update. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = poll(pollfds, 1, QUIETTIME);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 1 || !(pollfds[0].revents & POLLRDNORM)) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (do_update() != 0 && make_daemon == 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, "pfild: %s\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews errbuf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (poll(pollfds, 2, -1) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: poll()");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Check for route_fd message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pollfds[0].revents & POLLRDNORM) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = read(route_fd, &buffer, sizeof (buffer));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 1) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 0)
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: read(PF_ROUTE)");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews else
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild: read(PF_ROUTE) EOF\n");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews handle_msg(&buffer.msg, n);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Check for pfil_fd message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (pollfds[1].revents & POLLRDNORM) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews char pktbuf[IP_MAXPACKET];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews struct strbuf ctl, data;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews int flags;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ctl.maxlen = 0; /* We don't want any control message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ctl.buf = pktbuf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews data.maxlen = sizeof (pktbuf);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews data.buf = pktbuf;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews flags = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = getmsg(pfil_fd, &ctl, &data, &flags);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: getmsg(pfil)");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n > 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews fprintf(stderr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild: invalid packet from kernel "
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "n=%d ctl.len=%u data.len=%u\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n, ctl.len, data.len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sendpkt(data.buf, data.len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews }
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* NOTREACHED */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews}
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews