/*
 * suid wrapper for the pfctl table command
 *
 * this will add an address (or a range) to a given table, hardcoded
 * in the above define
 *
 * This should be compiled and installed as:
 *
 * -rwsr-x---  1 root www    5380 Jan 26 02:17 /usr/local/sbin/suidpftable
 *
 * then it can be ran by the webserver to add entries to the table,
 * which then gets whitelisted and not redirected to the captive
 * portal.
 *
 * A low-tech alternative is to run this command from inetd:
 *
 * http    stream  tcp     nowait  root    /usr/local/sbin/pftable pftable
 * http    stream  tcp6    nowait  root    /usr/local/sbin/pftable pftable
 *
 * Then it doesn't need to be setuid. This can then be added in an
 * iframe or similar.
 */

#include <err.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>

#define TABLE "cleared"

int main(int argc, char *argv[]) {
  struct sockaddr_storage from;
  int fromlen = sizeof(struct sockaddr_storage);
  char addr[INET6_ADDRSTRLEN+1];

  if (argc < 2) {
    if (getpeername(0, (struct sockaddr*) &from, &fromlen))
      err(1, "getpeername");
    if (getnameinfo((struct sockaddr *)&from, from.ss_len,
                    addr, sizeof(addr), NULL, 0, NI_NUMERICHOST))
      err(1, "getnameinfo");
  }
  else {
    strncpy(addr, argv[1], INET6_ADDRSTRLEN);
  }
  addr[INET6_ADDRSTRLEN] = '\0'; // make sure string is terminated,
                                 // as strncpy is dumb
  fprintf(stderr, "your IP is %s\n", addr);

  execl("/sbin/pfctl", "/sbin/pfctl", "-t", TABLE, "-T", "add", addr, NULL);
  /* NOT REACHED */
  err(1, "exec");
}
