| /* 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 <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "dnsmasq.h" |
| |
| #if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK) |
| |
| #ifndef __FreeBSD__ |
| #include <bsd/string.h> |
| #endif |
| |
| #include <sys/types.h> |
| #include <sys/ioctl.h> |
| |
| #include <net/if.h> |
| #include <netinet/in.h> |
| #include <net/pfvar.h> |
| |
| #include <err.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| |
| #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 |