1/* tables.c is Copyright (c) 2014 Sven Falempin All Rights Reserved. 2 3 Author's email: sfalempin@citypassenger.com 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; version 2 dated June, 1991, or 8 (at your option) version 3 dated 29 June, 2007. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17*/ 18 19#include "dnsmasq.h" 20 21#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK) 22 23#ifndef __FreeBSD__ 24#include <string.h> 25#endif 26 27#include <sys/types.h> 28#include <sys/ioctl.h> 29 30#include <net/if.h> 31#include <netinet/in.h> 32#include <net/pfvar.h> 33 34#include <err.h> 35#include <errno.h> 36#include <fcntl.h> 37 38#define UNUSED(x) (void)(x) 39 40static char *pf_device = "/dev/pf"; 41static int dev = -1; 42 43static char *pfr_strerror(int errnum) 44{ 45 switch (errnum) 46 { 47 case ESRCH: 48 return "Table does not exist"; 49 case ENOENT: 50 return "Anchor or Ruleset does not exist"; 51 default: 52 return strerror(errnum); 53 } 54} 55 56static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) 57{ 58 struct pfioc_table io; 59 60 if (size < 0 || (size && tbl == NULL)) 61 { 62 errno = EINVAL; 63 return (-1); 64 } 65 bzero(&io, sizeof io); 66 io.pfrio_flags = flags; 67 io.pfrio_buffer = tbl; 68 io.pfrio_esize = sizeof(*tbl); 69 io.pfrio_size = size; 70 if (ioctl(dev, DIOCRADDTABLES, &io)) 71 return (-1); 72 if (nadd != NULL) 73 *nadd = io.pfrio_nadd; 74 return (0); 75} 76 77static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) { 78 if ( !addr || !ipaddr) 79 { 80 my_syslog(LOG_ERR, _("error: fill_addr missused")); 81 return -1; 82 } 83 bzero(addr, sizeof(*addr)); 84#ifdef HAVE_IPV6 85 if (flags & F_IPV6) 86 { 87 addr->pfra_af = AF_INET6; 88 addr->pfra_net = 0x80; 89 memcpy(&(addr->pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr)); 90 } 91 else 92#endif 93 { 94 addr->pfra_af = AF_INET; 95 addr->pfra_net = 0x20; 96 addr->pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr; 97 } 98 return 1; 99} 100 101/*****************************************************************************/ 102 103void ipset_init(void) 104{ 105 dev = open( pf_device, O_RDWR); 106 if (dev == -1) 107 { 108 err(1, "%s", pf_device); 109 die (_("failed to access pf devices: %s"), NULL, EC_MISC); 110 } 111} 112 113int add_to_ipset(const char *setname, const struct all_addr *ipaddr, 114 int flags, int remove) 115{ 116 struct pfr_addr addr; 117 struct pfioc_table io; 118 struct pfr_table table; 119 int n = 0, rc = 0; 120 121 if ( dev == -1 ) 122 { 123 my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device); 124 return -1; 125 } 126 127 bzero(&table, sizeof(struct pfr_table)); 128 table.pfrt_flags |= PFR_TFLAG_PERSIST; 129 if ( strlen(setname) >= PF_TABLE_NAME_SIZE ) 130 { 131 my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname); 132 errno = ENAMETOOLONG; 133 return -1; 134 } 135 136 if ( strlcpy(table.pfrt_name, setname, 137 sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) 138 { 139 my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname); 140 return -1; 141 } 142 143 if ((rc = pfr_add_tables(&table, 1, &n, 0))) 144 { 145 my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"), 146 pfr_strerror(errno),rc); 147 return -1; 148 } 149 table.pfrt_flags &= ~PFR_TFLAG_PERSIST; 150 if (n) 151 my_syslog(LOG_INFO, _("info: table created")); 152 153 fill_addr(ipaddr,flags,&addr); 154 bzero(&io, sizeof(io)); 155 io.pfrio_flags = 0; 156 io.pfrio_table = table; 157 io.pfrio_buffer = &addr; 158 io.pfrio_esize = sizeof(addr); 159 io.pfrio_size = 1; 160 if (ioctl(dev, ( remove ? DIOCRDELADDRS : DIOCRADDADDRS ), &io)) 161 { 162 my_syslog(LOG_WARNING, _("warning: DIOCR%sADDRS: %s"), ( remove ? "DEL" : "ADD" ), pfr_strerror(errno)); 163 return -1; 164 } 165 166 my_syslog(LOG_INFO, _("%d addresses %s"), 167 io.pfrio_nadd, ( remove ? "removed" : "added" )); 168 169 return io.pfrio_nadd; 170} 171 172 173#endif 174