/* tables.c is Copyright (c) 2014 Sven Falempin All Rights Reserved. Author's email: sfalempin@citypassenger.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 dated June, 1991, or (at your option) version 3 dated 29 June, 2007. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "dnsmasq.h" #if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK) #ifndef __FreeBSD__ #include #endif #include #include #include #include #include #include #include #include #define UNUSED(x) (void)(x) static char *pf_device = "/dev/pf"; static int dev = -1; static char *pfr_strerror(int errnum) { switch (errnum) { case ESRCH: return "Table does not exist"; case ENOENT: return "Anchor or Ruleset does not exist"; default: return strerror(errnum); } } static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) { struct pfioc_table io; if (size < 0 || (size && tbl == NULL)) { errno = EINVAL; return (-1); } bzero(&io, sizeof io); io.pfrio_flags = flags; io.pfrio_buffer = tbl; io.pfrio_esize = sizeof(*tbl); io.pfrio_size = size; if (ioctl(dev, DIOCRADDTABLES, &io)) return (-1); if (nadd != NULL) *nadd = io.pfrio_nadd; return (0); } static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) { if ( !addr || !ipaddr) { my_syslog(LOG_ERR, _("error: fill_addr missused")); return -1; } bzero(addr, sizeof(*addr)); #ifdef HAVE_IPV6 if (flags & F_IPV6) { addr->pfra_af = AF_INET6; addr->pfra_net = 0x80; memcpy(&(addr->pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr)); } else #endif { addr->pfra_af = AF_INET; addr->pfra_net = 0x20; addr->pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr; } return 1; } /*****************************************************************************/ void ipset_init(void) { dev = open( pf_device, O_RDWR); if (dev == -1) { err(1, "%s", pf_device); die (_("failed to access pf devices: %s"), NULL, EC_MISC); } } int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove) { struct pfr_addr addr; struct pfioc_table io; struct pfr_table table; int n = 0, rc = 0; if ( dev == -1 ) { my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device); return -1; } bzero(&table, sizeof(struct pfr_table)); table.pfrt_flags |= PFR_TFLAG_PERSIST; if ( strlen(setname) >= PF_TABLE_NAME_SIZE ) { my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname); errno = ENAMETOOLONG; return -1; } if ( strlcpy(table.pfrt_name, setname, sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) { my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname); return -1; } if ((rc = pfr_add_tables(&table, 1, &n, 0))) { my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"), pfr_strerror(errno),rc); return -1; } table.pfrt_flags &= ~PFR_TFLAG_PERSIST; if (n) my_syslog(LOG_INFO, _("info: table created")); fill_addr(ipaddr,flags,&addr); bzero(&io, sizeof(io)); io.pfrio_flags = 0; io.pfrio_table = table; io.pfrio_buffer = &addr; io.pfrio_esize = sizeof(addr); io.pfrio_size = 1; if (ioctl(dev, ( remove ? DIOCRDELADDRS : DIOCRADDADDRS ), &io)) { my_syslog(LOG_WARNING, _("warning: DIOCR%sADDRS: %s"), ( remove ? "DEL" : "ADD" ), pfr_strerror(errno)); return -1; } my_syslog(LOG_INFO, _("%d addresses %s"), io.pfrio_nadd, ( remove ? "removed" : "added" )); return io.pfrio_nadd; } #endif