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