• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "../iptables/xshared.h"
10 
11 static int
get_version(unsigned * version)12 get_version(unsigned *version)
13 {
14 	int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
15 	struct ip_set_req_version req_version;
16 	socklen_t size = sizeof(req_version);
17 
18 	if (sockfd < 0)
19 		xtables_error(OTHER_PROBLEM,
20 			      "Can't open socket to ipset.\n");
21 
22 	if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) {
23 		xtables_error(OTHER_PROBLEM,
24 			      "Could not set close on exec: %s\n",
25 			      strerror(errno));
26 	}
27 
28 	req_version.op = IP_SET_OP_VERSION;
29 	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size);
30 	if (res != 0)
31 		xtables_error(OTHER_PROBLEM,
32 			      "Kernel module xt_set is not loaded in.\n");
33 
34 	*version = req_version.version;
35 
36 	return sockfd;
37 }
38 
39 static void
get_set_byid(char * setname,ip_set_id_t idx)40 get_set_byid(char *setname, ip_set_id_t idx)
41 {
42 	struct ip_set_req_get_set req;
43 	socklen_t size = sizeof(struct ip_set_req_get_set);
44 	int res, sockfd;
45 
46 	sockfd = get_version(&req.version);
47 	req.op = IP_SET_OP_GET_BYINDEX;
48 	req.set.index = idx;
49 	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
50 	close(sockfd);
51 
52 	if (res != 0)
53 		xtables_error(OTHER_PROBLEM,
54 			"Problem when communicating with ipset, errno=%d.\n",
55 			errno);
56 	if (size != sizeof(struct ip_set_req_get_set))
57 		xtables_error(OTHER_PROBLEM,
58 			"Incorrect return size from kernel during ipset lookup, "
59 			"(want %zu, got %zu)\n",
60 			sizeof(struct ip_set_req_get_set), (size_t)size);
61 	if (req.set.name[0] == '\0')
62 		xtables_error(PARAMETER_PROBLEM,
63 			"Set with index %i in kernel doesn't exist.\n", idx);
64 
65 	strncpy(setname, req.set.name, IPSET_MAXNAMELEN);
66 }
67 
68 static void
get_set_byname_only(const char * setname,struct xt_set_info * info,int sockfd,unsigned int version)69 get_set_byname_only(const char *setname, struct xt_set_info *info,
70 		    int sockfd, unsigned int version)
71 {
72 	struct ip_set_req_get_set req = { .version = version };
73 	socklen_t size = sizeof(struct ip_set_req_get_set);
74 	int res;
75 
76 	req.op = IP_SET_OP_GET_BYNAME;
77 	strncpy(req.set.name, setname, IPSET_MAXNAMELEN);
78 	req.set.name[IPSET_MAXNAMELEN - 1] = '\0';
79 	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
80 	close(sockfd);
81 
82 	if (res != 0)
83 		xtables_error(OTHER_PROBLEM,
84 			"Problem when communicating with ipset, errno=%d.\n",
85 			errno);
86 	if (size != sizeof(struct ip_set_req_get_set))
87 		xtables_error(OTHER_PROBLEM,
88 			"Incorrect return size from kernel during ipset lookup, "
89 			"(want %zu, got %zu)\n",
90 			sizeof(struct ip_set_req_get_set), (size_t)size);
91 	if (req.set.index == IPSET_INVALID_ID)
92 		xtables_error(PARAMETER_PROBLEM,
93 			      "Set %s doesn't exist.\n", setname);
94 
95 	info->index = req.set.index;
96 }
97 
98 static void
get_set_byname(const char * setname,struct xt_set_info * info)99 get_set_byname(const char *setname, struct xt_set_info *info)
100 {
101 	struct ip_set_req_get_set_family req;
102 	socklen_t size = sizeof(struct ip_set_req_get_set_family);
103 	int res, sockfd, version;
104 
105 	sockfd = get_version(&req.version);
106 	version = req.version;
107 	req.op = IP_SET_OP_GET_FNAME;
108 	strncpy(req.set.name, setname, IPSET_MAXNAMELEN);
109 	req.set.name[IPSET_MAXNAMELEN - 1] = '\0';
110 	res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size);
111 
112 	if (res != 0 && errno == EBADMSG)
113 		/* Backward compatibility */
114 		return get_set_byname_only(setname, info, sockfd, version);
115 
116 	close(sockfd);
117 	if (res != 0)
118 		xtables_error(OTHER_PROBLEM,
119 			"Problem when communicating with ipset, errno=%d.\n",
120 			errno);
121 	if (size != sizeof(struct ip_set_req_get_set_family))
122 		xtables_error(OTHER_PROBLEM,
123 			"Incorrect return size from kernel during ipset lookup, "
124 			"(want %zu, got %zu)\n",
125 			sizeof(struct ip_set_req_get_set_family),
126 			(size_t)size);
127 	if (req.set.index == IPSET_INVALID_ID)
128 		xtables_error(PARAMETER_PROBLEM,
129 			      "Set %s doesn't exist.\n", setname);
130 	if (!(req.family == afinfo->family ||
131 	      req.family == NFPROTO_UNSPEC))
132 		xtables_error(PARAMETER_PROBLEM,
133 			      "The protocol family of set %s is %s, "
134 			      "which is not applicable.\n",
135 			      setname,
136 			      req.family == NFPROTO_IPV4 ? "IPv4" : "IPv6");
137 
138 	info->index = req.set.index;
139 }
140 
141 static void
parse_dirs_v0(const char * opt_arg,struct xt_set_info_v0 * info)142 parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info)
143 {
144 	char *saved = strdup(opt_arg);
145 	char *ptr, *tmp = saved;
146 	int i = 0;
147 
148 	while (i < (IPSET_DIM_MAX - 1) && tmp != NULL) {
149 		ptr = strsep(&tmp, ",");
150 		if (strncmp(ptr, "src", 3) == 0)
151 			info->u.flags[i++] |= IPSET_SRC;
152 		else if (strncmp(ptr, "dst", 3) == 0)
153 			info->u.flags[i++] |= IPSET_DST;
154 		else
155 			xtables_error(PARAMETER_PROBLEM,
156 				"You must spefify (the comma separated list of) 'src' or 'dst'.");
157 	}
158 
159 	if (tmp)
160 		xtables_error(PARAMETER_PROBLEM,
161 			      "Can't be more src/dst options than %i.",
162 			      IPSET_DIM_MAX);
163 
164 	free(saved);
165 }
166 
167 static void
parse_dirs(const char * opt_arg,struct xt_set_info * info)168 parse_dirs(const char *opt_arg, struct xt_set_info *info)
169 {
170 	char *saved = strdup(opt_arg);
171 	char *ptr, *tmp = saved;
172 
173 	while (info->dim < IPSET_DIM_MAX && tmp != NULL) {
174 		info->dim++;
175 		ptr = strsep(&tmp, ",");
176 		if (strncmp(ptr, "src", 3) == 0)
177 			info->flags |= (1 << info->dim);
178 		else if (strncmp(ptr, "dst", 3) != 0)
179 			xtables_error(PARAMETER_PROBLEM,
180 				"You must spefify (the comma separated list of) 'src' or 'dst'.");
181 	}
182 
183 	if (tmp)
184 		xtables_error(PARAMETER_PROBLEM,
185 			      "Can't be more src/dst options than %i.",
186 			      IPSET_DIM_MAX);
187 
188 	free(saved);
189 }
190 
191 #endif /*_LIBXT_SET_H*/
192