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