pfild.c revision ed98f1ae92c0bb2fe51326c2720e493efd56e9bc
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Copyright (C) 2003 by Darren Reed.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * See the IPFILTER.LICENCE file for details on licencing.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Use is subject to license terms.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#pragma ident "%Z%%M% %I% %E% SMI"
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsextern int vas(const struct pfil_ifaddrs *, int);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * pfild.c: interface data and packet transmission daemon for pfil
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 * 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/* 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 * flag indicates that some interface or routing data have changed since
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * last update.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * debuglevel indicates to what level debugging messages should be emitted.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic int debuglevel = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews/* Wait for this many ms of quiet time after changes before doing an update. */
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 (void) fprintf(stderr, "pfil_msg(%x,%p,%d)\n", cmd, buf, len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:pfil_msg():putmsg(%d,%p,%p,0) = %d\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:pfil_msg():pfil_fd < 0\n");
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 * p points to, and size indicates the size of, the message.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (size < sizeof (*p) ||
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "Not a valid version %u RTM message - "
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "%u bytes version %u\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild:handle_msg(): msg rcvd %d flag %d\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrewsstatic const char *
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (inet_ntop(sin->sin_family, &sin->sin_addr, buf,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (inet_ntop(sin6->sin6_family, &sin6->sin6_addr, buf,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return ("<none>");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews#define LIFN_MARGIN 5 /* a few extra in case things are changing */
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 const int lifc_flags = 0;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(ip_fd, SIOCGLIFNUM, (char *)&lifn) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFNUM: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews bufsize = (lifn.lifn_count + LIFN_MARGIN) * sizeof (struct lifreq);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "malloc: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(ip_fd, SIOCGLIFCONF, (char *)&lifc) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFCONF: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews numifs = lifc.lifc_len / sizeof (struct lifreq);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Allocate memory for the number of interfaces retrieved. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist = calloc(numifs, sizeof (struct pfil_ifaddrs));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) snprintf(errbuf, ERRBUFSIZE, "calloc: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
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 (void) strncpy(ifaddrlist[i].name, lifrbuf[i].lifr_name,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].localaddr, &lifrbuf[i].lifr_addr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFNETMASK, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFNETMASK %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews LIFNAMSIZ, ifaddrlist[i].name, strerror(errno));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) memcpy(&ifaddrlist[i].netmask, &lifrbuf[i].lifr_addr,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFBRDADDR, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFBRDADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (ioctl(fd, SIOCGLIFDSTADDR, &lifrbuf[i]) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFDSTADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "SIOCGLIFDSTADDR %.*s: %s",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Now send this table of interfaces and addresses down into
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * the pfil kernel module.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ifaddrlist, i * sizeof (struct pfil_ifaddrs)) < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews * Next, compute and send the table of valid addresses.
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
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 unsigned char ancdatabuf[sizeof (*cmsgp) + sizeof (*pktinfop) + 100];
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews pktinfop = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews cmsgp->cmsg_len = ((char *)(pktinfop + 1) - (char *)cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ancdatalen = ((char *)(pktinfop + 1) - (char *)cmsgp);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews memcpy(&sin6.sin6_addr, &iph->ip6_dst, sizeof (sin6.sin6_addr));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews sin6.sin6_flowinfo = iph->ip6_flow & IPV6_FLOWINFO_TCLASS;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews return (-1);
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 fprintf(stderr, "pfild sendpkt %u bytes:\n", len);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews n = sendto(ip_fd, buf, len, 0, (void *)&sin, sizeof (sin));
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews union { char bytes[1024]; ifa_msghdr_t msg; } buffer;
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews switch (c) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ip_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
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 icmp6_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
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 if (setsockopt(icmp6_ip6_fd, IPPROTO_ICMPV6, ICMP6_FILTER,
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews perror("pfild: inet6 ICMP6 socket type filtering option");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews tcp_ip6_fd = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP);
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Background */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews (void) fprintf(stderr, "%s: fork() failed %s\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* NOTREACHED */
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 /* Wait for a moment of quiet, then do the update. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 1 || !(pollfds[0].revents & POLLRDNORM)) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Check for route_fd message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 1) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild: read(PF_ROUTE) EOF\n");
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* Check for pfil_fd message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews ctl.maxlen = 0; /* We don't want any control message. */
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n < 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews if (n > 0) {
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "pfild: invalid packet from kernel "
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews "n=%d ctl.len=%u data.len=%u\n",
35f36a82bf56925fc6ae4b69ff95aa27258cfc4fMark Andrews /* NOTREACHED */