version 1.1, 2013/07/29 19:37:40
|
version 1.1.1.4, 2021/03/17 00:56:46
|
Line 16
|
Line 16
|
|
|
#include "dnsmasq.h" |
#include "dnsmasq.h" |
|
|
#ifdef HAVE_IPSET | #if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK) |
|
|
#include <string.h> |
#include <string.h> |
#include <errno.h> |
#include <errno.h> |
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <sys/utsname.h> |
|
#include <arpa/inet.h> |
#include <arpa/inet.h> |
#include <linux/version.h> |
|
#include <linux/netlink.h> |
#include <linux/netlink.h> |
#include <linux/netfilter/nfnetlink.h> | |
#ifndef NFNL_SUBSYS_IPSET | /* We want to be able to compile against old header files |
| Kernel version is handled at run-time. */ |
| |
#define NFNL_SUBSYS_IPSET 6 |
#define NFNL_SUBSYS_IPSET 6 |
|
|
#define IPSET_ATTR_DATA 7 |
#define IPSET_ATTR_DATA 7 |
#define IPSET_ATTR_IP 1 |
#define IPSET_ATTR_IP 1 |
#define IPSET_ATTR_IPADDR_IPV4 1 |
#define IPSET_ATTR_IPADDR_IPV4 1 |
Line 39
|
Line 40
|
#define IPSET_CMD_DEL 10 |
#define IPSET_CMD_DEL 10 |
#define IPSET_MAXNAMELEN 32 |
#define IPSET_MAXNAMELEN 32 |
#define IPSET_PROTOCOL 6 |
#define IPSET_PROTOCOL 6 |
#else | |
#include <linux/netfilter/ipset/ip_set.h> | #ifndef NFNETLINK_V0 |
| #define NFNETLINK_V0 0 |
#endif |
#endif |
|
|
|
#ifndef NLA_F_NESTED |
|
#define NLA_F_NESTED (1 << 15) |
|
#endif |
|
|
|
#ifndef NLA_F_NET_BYTEORDER |
|
#define NLA_F_NET_BYTEORDER (1 << 14) |
|
#endif |
|
|
|
struct my_nlattr { |
|
__u16 nla_len; |
|
__u16 nla_type; |
|
}; |
|
|
|
struct my_nfgenmsg { |
|
__u8 nfgen_family; /* AF_xxx */ |
|
__u8 version; /* nfnetlink version */ |
|
__be16 res_id; /* resource id */ |
|
}; |
|
|
|
|
/* data structure size in here is fixed */ |
/* data structure size in here is fixed */ |
#define BUFF_SZ 256 |
#define BUFF_SZ 256 |
|
|
Line 53 static char *buffer;
|
Line 75 static char *buffer;
|
|
|
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data) |
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data) |
{ |
{ |
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len); | struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len); |
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len; | uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len; |
attr->nla_type = type; |
attr->nla_type = type; |
attr->nla_len = payload_len; |
attr->nla_len = payload_len; |
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len); | memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len); |
nlh->nlmsg_len += NL_ALIGN(payload_len); |
nlh->nlmsg_len += NL_ALIGN(payload_len); |
} |
} |
|
|
void ipset_init(void) |
void ipset_init(void) |
{ |
{ |
struct utsname utsname; | old_kernel = (daemon->kernel_version < KERNEL_VERSION(2,6,32)); |
int version; | |
char *split; | |
|
|
if (uname(&utsname) < 0) |
|
die(_("failed to find kernel version: %s"), NULL, EC_MISC); |
|
|
|
split = strtok(utsname.release, "."); |
|
version = (split ? atoi(split) : 0); |
|
split = strtok(NULL, "."); |
|
version = version * 256 + (split ? atoi(split) : 0); |
|
split = strtok(NULL, "."); |
|
version = version * 256 + (split ? atoi(split) : 0); |
|
old_kernel = (version < KERNEL_VERSION(2,6,32)); |
|
|
|
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1) |
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1) |
return; |
return; |
|
|
Line 90 void ipset_init(void)
|
Line 99 void ipset_init(void)
|
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC); |
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC); |
} |
} |
|
|
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove) | static int new_add_to_ipset(const char *setname, const union all_addr *ipaddr, int af, int remove) |
{ |
{ |
struct nlmsghdr *nlh; |
struct nlmsghdr *nlh; |
struct nfgenmsg *nfg; | struct my_nfgenmsg *nfg; |
struct nlattr *nested[2]; | struct my_nlattr *nested[2]; |
uint8_t proto; |
uint8_t proto; |
int addrsz = INADDRSZ; | int addrsz = (af == AF_INET6) ? IN6ADDRSZ : INADDRSZ; |
ssize_t rc; | |
|
|
#ifdef HAVE_IPV6 |
|
if (af == AF_INET6) |
|
addrsz = IN6ADDRSZ; |
|
#endif |
|
|
|
if (strlen(setname) >= IPSET_MAXNAMELEN) |
if (strlen(setname) >= IPSET_MAXNAMELEN) |
{ |
{ |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
return -1; |
return -1; |
} |
} |
|
|
memset(buffer, 0, sizeof(buffer)); | memset(buffer, 0, BUFF_SZ); |
|
|
nlh = (struct nlmsghdr *)buffer; |
nlh = (struct nlmsghdr *)buffer; |
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr)); |
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr)); |
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8); |
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8); |
nlh->nlmsg_flags = NLM_F_REQUEST; |
nlh->nlmsg_flags = NLM_F_REQUEST; |
|
|
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len); | nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len); |
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg)); | nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg)); |
nfg->nfgen_family = af; |
nfg->nfgen_family = af; |
nfg->version = NFNETLINK_V0; |
nfg->version = NFNETLINK_V0; |
nfg->res_id = htons(0); |
nfg->res_id = htons(0); |
Line 126 static int new_add_to_ipset(const char *setname, const
|
Line 129 static int new_add_to_ipset(const char *setname, const
|
proto = IPSET_PROTOCOL; |
proto = IPSET_PROTOCOL; |
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto); |
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto); |
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname); |
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname); |
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len)); | nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len)); |
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr)); | nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr)); |
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA; |
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA; |
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len)); | nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len)); |
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr)); | nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr)); |
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP; |
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP; |
add_attr(nlh, |
add_attr(nlh, |
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, |
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, |
addrsz, &ipaddr->addr); | addrsz, ipaddr); |
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1]; |
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1]; |
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0]; |
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0]; |
|
|
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0, | while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0, |
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send()); | (struct sockaddr *)&snl, sizeof(snl)))); |
return rc; | |
| return errno == 0 ? 0 : -1; |
} |
} |
|
|
|
|
static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove) | static int old_add_to_ipset(const char *setname, const union all_addr *ipaddr, int remove) |
{ |
{ |
socklen_t size; |
socklen_t size; |
struct ip_set_req_adt_get { |
struct ip_set_req_adt_get { |
Line 176 static int old_add_to_ipset(const char *setname, const
|
Line 180 static int old_add_to_ipset(const char *setname, const
|
return -1; |
return -1; |
req_adt.op = remove ? 0x102 : 0x101; |
req_adt.op = remove ? 0x102 : 0x101; |
req_adt.index = req_adt_get.set.index; |
req_adt.index = req_adt_get.set.index; |
req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr); | req_adt.ip = ntohl(ipaddr->addr4.s_addr); |
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0) |
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0) |
return -1; |
return -1; |
|
|
Line 185 static int old_add_to_ipset(const char *setname, const
|
Line 189 static int old_add_to_ipset(const char *setname, const
|
|
|
|
|
|
|
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove) | int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove) |
{ |
{ |
int af = AF_INET; | int ret = 0, af = AF_INET; |
|
|
#ifdef HAVE_IPV6 |
|
if (flags & F_IPV6) |
if (flags & F_IPV6) |
{ |
{ |
af = AF_INET6; |
af = AF_INET6; |
/* old method only supports IPv4 */ |
/* old method only supports IPv4 */ |
if (old_kernel) |
if (old_kernel) |
return -1; | { |
| errno = EAFNOSUPPORT ; |
| ret = -1; |
| } |
} |
} |
#endif |
|
|
|
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove); | if (ret != -1) |
| ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove); |
| |
| if (ret == -1) |
| my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno)); |
| |
| return ret; |
} |
} |
|
|
#endif |
#endif |