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