Annotation of embedaddon/dnsmasq/src/ipset.c, revision 1.1.1.4
1.1 misho 1: /* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
2:
3: This program is free software; you can redistribute it and/or modify
4: it under the terms of the GNU General Public License as published by
5: the Free Software Foundation; version 2 dated June, 1991, or
6: (at your option) version 3 dated 29 June, 2007.
7:
8: This program is distributed in the hope that it will be useful,
9: but WITHOUT ANY WARRANTY; without even the implied warranty of
10: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11: GNU General Public License for more details.
12:
13: You should have received a copy of the GNU General Public License
14: along with this program. If not, see <http://www.gnu.org/licenses/>.
15: */
16:
17: #include "dnsmasq.h"
18:
1.1.1.3 misho 19: #if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
1.1 misho 20:
21: #include <string.h>
22: #include <errno.h>
23: #include <sys/types.h>
24: #include <sys/socket.h>
25: #include <arpa/inet.h>
26: #include <linux/netlink.h>
1.1.1.2 misho 27:
28: /* We want to be able to compile against old header files
29: Kernel version is handled at run-time. */
30:
1.1 misho 31: #define NFNL_SUBSYS_IPSET 6
1.1.1.2 misho 32:
1.1 misho 33: #define IPSET_ATTR_DATA 7
34: #define IPSET_ATTR_IP 1
35: #define IPSET_ATTR_IPADDR_IPV4 1
36: #define IPSET_ATTR_IPADDR_IPV6 2
37: #define IPSET_ATTR_PROTOCOL 1
38: #define IPSET_ATTR_SETNAME 2
39: #define IPSET_CMD_ADD 9
40: #define IPSET_CMD_DEL 10
41: #define IPSET_MAXNAMELEN 32
42: #define IPSET_PROTOCOL 6
1.1.1.2 misho 43:
44: #ifndef NFNETLINK_V0
45: #define NFNETLINK_V0 0
46: #endif
47:
48: #ifndef NLA_F_NESTED
49: #define NLA_F_NESTED (1 << 15)
50: #endif
51:
52: #ifndef NLA_F_NET_BYTEORDER
53: #define NLA_F_NET_BYTEORDER (1 << 14)
1.1 misho 54: #endif
55:
1.1.1.2 misho 56: struct my_nlattr {
57: __u16 nla_len;
58: __u16 nla_type;
59: };
60:
61: struct my_nfgenmsg {
62: __u8 nfgen_family; /* AF_xxx */
63: __u8 version; /* nfnetlink version */
64: __be16 res_id; /* resource id */
65: };
66:
67:
1.1 misho 68: /* data structure size in here is fixed */
69: #define BUFF_SZ 256
70:
71: #define NL_ALIGN(len) (((len)+3) & ~(3))
72: static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
73: static int ipset_sock, old_kernel;
74: static char *buffer;
75:
76: static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
77: {
1.1.1.2 misho 78: struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
79: uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
1.1 misho 80: attr->nla_type = type;
81: attr->nla_len = payload_len;
1.1.1.2 misho 82: memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
1.1 misho 83: nlh->nlmsg_len += NL_ALIGN(payload_len);
84: }
85:
86: void ipset_init(void)
87: {
1.1.1.4 ! misho 88: old_kernel = (daemon->kernel_version < KERNEL_VERSION(2,6,32));
1.1 misho 89:
90: if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
91: return;
92:
93: if (!old_kernel &&
94: (buffer = safe_malloc(BUFF_SZ)) &&
95: (ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
96: (bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
97: return;
98:
99: die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
100: }
101:
1.1.1.4 ! misho 102: static int new_add_to_ipset(const char *setname, const union all_addr *ipaddr, int af, int remove)
1.1 misho 103: {
104: struct nlmsghdr *nlh;
1.1.1.2 misho 105: struct my_nfgenmsg *nfg;
106: struct my_nlattr *nested[2];
1.1 misho 107: uint8_t proto;
1.1.1.4 ! misho 108: int addrsz = (af == AF_INET6) ? IN6ADDRSZ : INADDRSZ;
1.1 misho 109:
110: if (strlen(setname) >= IPSET_MAXNAMELEN)
111: {
112: errno = ENAMETOOLONG;
113: return -1;
114: }
115:
1.1.1.2 misho 116: memset(buffer, 0, BUFF_SZ);
1.1 misho 117:
118: nlh = (struct nlmsghdr *)buffer;
119: nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
120: nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
121: nlh->nlmsg_flags = NLM_F_REQUEST;
122:
1.1.1.2 misho 123: nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
124: nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
1.1 misho 125: nfg->nfgen_family = af;
126: nfg->version = NFNETLINK_V0;
127: nfg->res_id = htons(0);
128:
129: proto = IPSET_PROTOCOL;
130: add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
131: add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
1.1.1.2 misho 132: nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
133: nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
1.1 misho 134: nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
1.1.1.2 misho 135: nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
136: nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
1.1 misho 137: nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
138: add_attr(nlh,
139: (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
1.1.1.4 ! misho 140: addrsz, ipaddr);
1.1 misho 141: nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
142: nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
143:
1.1.1.3 misho 144: while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
145: (struct sockaddr *)&snl, sizeof(snl))));
146:
147: return errno == 0 ? 0 : -1;
1.1 misho 148: }
149:
150:
1.1.1.4 ! misho 151: static int old_add_to_ipset(const char *setname, const union all_addr *ipaddr, int remove)
1.1 misho 152: {
153: socklen_t size;
154: struct ip_set_req_adt_get {
155: unsigned op;
156: unsigned version;
157: union {
158: char name[IPSET_MAXNAMELEN];
159: uint16_t index;
160: } set;
161: char typename[IPSET_MAXNAMELEN];
162: } req_adt_get;
163: struct ip_set_req_adt {
164: unsigned op;
165: uint16_t index;
166: uint32_t ip;
167: } req_adt;
168:
169: if (strlen(setname) >= sizeof(req_adt_get.set.name))
170: {
171: errno = ENAMETOOLONG;
172: return -1;
173: }
174:
175: req_adt_get.op = 0x10;
176: req_adt_get.version = 3;
177: strcpy(req_adt_get.set.name, setname);
178: size = sizeof(req_adt_get);
179: if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
180: return -1;
181: req_adt.op = remove ? 0x102 : 0x101;
182: req_adt.index = req_adt_get.set.index;
1.1.1.4 ! misho 183: req_adt.ip = ntohl(ipaddr->addr4.s_addr);
1.1 misho 184: if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
185: return -1;
186:
187: return 0;
188: }
189:
190:
191:
1.1.1.4 ! misho 192: int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove)
1.1 misho 193: {
1.1.1.4 ! misho 194: int ret = 0, af = AF_INET;
1.1 misho 195:
196: if (flags & F_IPV6)
197: {
198: af = AF_INET6;
199: /* old method only supports IPv4 */
200: if (old_kernel)
1.1.1.4 ! misho 201: {
! 202: errno = EAFNOSUPPORT ;
! 203: ret = -1;
! 204: }
1.1 misho 205: }
206:
1.1.1.4 ! misho 207: if (ret != -1)
! 208: ret = old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
! 209:
! 210: if (ret == -1)
! 211: my_syslog(LOG_ERR, _("failed to update ipset %s: %s"), setname, strerror(errno));
! 212:
! 213: return ret;
1.1 misho 214: }
215:
216: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>