1#ifndef _LIBXT_SET_H
2#define _LIBXT_SET_H
3
4#include <unistd.h>
5#include <fcntl.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <errno.h>
9
10#ifdef DEBUG
11#define DEBUGP(x, args...) fprintf(stderr, x , ## args)
12#else
13#define DEBUGP(x, args...)
14#endif
15
16static int
17get_version(unsigned *version)
18{
19	int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
20	struct ip_set_req_version req_version;
21	socklen_t size = sizeof(req_version);
22
23	if (sockfd < 0)
24		xtables_error(OTHER_PROBLEM,
25			      "Can't open socket to ipset.\n");
26
27	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
28		xtables_error(OTHER_PROBLEM,
29			      "Could not set close on exec: %s\n",
30			      strerror(errno));
31	}
32
33	req_version.op = IP_SET_OP_VERSION;
34	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size);
35	if (res != 0)
36		xtables_error(OTHER_PROBLEM,
37			      "Kernel module xt_set is not loaded in.\n");
38
39	*version = req_version.version;
40
41	return sockfd;
42}
43
44static void
45get_set_byid(char *setname, ip_set_id_t idx)
46{
47	struct ip_set_req_get_set req;
48	socklen_t size = sizeof(struct ip_set_req_get_set);
49	int res, sockfd;
50
51	sockfd = get_version(&req.version);
52	req.op = IP_SET_OP_GET_BYINDEX;
53	req.set.index = idx;
54	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
55	close(sockfd);
56
57	if (res != 0)
58		xtables_error(OTHER_PROBLEM,
59			"Problem when communicating with ipset, errno=%d.\n",
60			errno);
61	if (size != sizeof(struct ip_set_req_get_set))
62		xtables_error(OTHER_PROBLEM,
63			"Incorrect return size from kernel during ipset lookup, "
64			"(want %zu, got %zu)\n",
65			sizeof(struct ip_set_req_get_set), (size_t)size);
66	if (req.set.name[0] == '\0')
67		xtables_error(PARAMETER_PROBLEM,
68			"Set with index %i in kernel doesn't exist.\n", idx);
69
70	strncpy(setname, req.set.name, IPSET_MAXNAMELEN);
71}
72
73static void
74get_set_byname(const char *setname, struct xt_set_info *info)
75{
76	struct ip_set_req_get_set req;
77	socklen_t size = sizeof(struct ip_set_req_get_set);
78	int res, sockfd;
79
80	sockfd = get_version(&req.version);
81	req.op = IP_SET_OP_GET_BYNAME;
82	strncpy(req.set.name, setname, IPSET_MAXNAMELEN);
83	req.set.name[IPSET_MAXNAMELEN - 1] = '\0';
84	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
85	close(sockfd);
86
87	if (res != 0)
88		xtables_error(OTHER_PROBLEM,
89			"Problem when communicating with ipset, errno=%d.\n",
90			errno);
91	if (size != sizeof(struct ip_set_req_get_set))
92		xtables_error(OTHER_PROBLEM,
93			"Incorrect return size from kernel during ipset lookup, "
94			"(want %zu, got %zu)\n",
95			sizeof(struct ip_set_req_get_set), (size_t)size);
96	if (req.set.index == IPSET_INVALID_ID)
97		xtables_error(PARAMETER_PROBLEM,
98			      "Set %s doesn't exist.\n", setname);
99
100	info->index = req.set.index;
101}
102
103static void
104parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
105{
106	char *saved = strdup(opt_arg);
107	char *ptr, *tmp = saved;
108	int i = 0;
109
110	while (i < (IPSET_DIM_MAX - 1) && tmp != NULL) {
111		ptr = strsep(&tmp, ",");
112		if (strncmp(ptr, "src", 3) == 0)
113			info->u.flags[i++] |= IPSET_SRC;
114		else if (strncmp(ptr, "dst", 3) == 0)
115			info->u.flags[i++] |= IPSET_DST;
116		else
117			xtables_error(PARAMETER_PROBLEM,
118				"You must spefify (the comma separated list of) 'src' or 'dst'.");
119	}
120
121	if (tmp)
122		xtables_error(PARAMETER_PROBLEM,
123			      "Can't be more src/dst options than %i.",
124			      IPSET_DIM_MAX);
125
126	free(saved);
127}
128
129static void
130parse_dirs(const char *opt_arg, struct xt_set_info *info)
131{
132	char *saved = strdup(opt_arg);
133	char *ptr, *tmp = saved;
134
135	while (info->dim < IPSET_DIM_MAX && tmp != NULL) {
136		info->dim++;
137		ptr = strsep(&tmp, ",");
138		if (strncmp(ptr, "src", 3) == 0)
139			info->flags |= (1 << info->dim);
140		else if (strncmp(ptr, "dst", 3) != 0)
141			xtables_error(PARAMETER_PROBLEM,
142				"You must spefify (the comma separated list of) 'src' or 'dst'.");
143	}
144
145	if (tmp)
146		xtables_error(PARAMETER_PROBLEM,
147			      "Can't be more src/dst options than %i.",
148			      IPSET_DIM_MAX);
149
150	free(saved);
151}
152
153#endif /*_LIBXT_SET_H*/
154