1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */ 3 4 /* Kernel module implementing an IP set type: the hash:ip,mark type */ 5 6 #include <linux/jhash.h> 7 #include <linux/module.h> 8 #include <linux/ip.h> 9 #include <linux/skbuff.h> 10 #include <linux/errno.h> 11 #include <linux/random.h> 12 #include <net/ip.h> 13 #include <net/ipv6.h> 14 #include <net/netlink.h> 15 #include <net/tcp.h> 16 17 #include <linux/netfilter.h> 18 #include <linux/netfilter/ipset/pfxlen.h> 19 #include <linux/netfilter/ipset/ip_set.h> 20 #include <linux/netfilter/ipset/ip_set_hash.h> 21 22 #define IPSET_TYPE_REV_MIN 0 23 /* 1 Forceadd support */ 24 #define IPSET_TYPE_REV_MAX 2 /* skbinfo support */ 25 26 MODULE_LICENSE("GPL"); 27 MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>"); 28 IP_SET_MODULE_DESC("hash:ip,mark", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 29 MODULE_ALIAS("ip_set_hash:ip,mark"); 30 31 /* Type specific function prefix */ 32 #define HTYPE hash_ipmark 33 #define IP_SET_HASH_WITH_MARKMASK 34 35 /* IPv4 variant */ 36 37 /* Member elements */ 38 struct hash_ipmark4_elem { 39 __be32 ip; 40 __u32 mark; 41 }; 42 43 /* Common functions */ 44 45 static bool 46 hash_ipmark4_data_equal(const struct hash_ipmark4_elem *ip1, 47 const struct hash_ipmark4_elem *ip2, 48 u32 *multi) 49 { 50 return ip1->ip == ip2->ip && 51 ip1->mark == ip2->mark; 52 } 53 54 static bool 55 hash_ipmark4_data_list(struct sk_buff *skb, 56 const struct hash_ipmark4_elem *data) 57 { 58 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 59 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) 60 goto nla_put_failure; 61 return false; 62 63 nla_put_failure: 64 return true; 65 } 66 67 static void 68 hash_ipmark4_data_next(struct hash_ipmark4_elem *next, 69 const struct hash_ipmark4_elem *d) 70 { 71 next->ip = d->ip; 72 } 73 74 #define MTYPE hash_ipmark4 75 #define HOST_MASK 32 76 #include "ip_set_hash_gen.h" 77 78 static int 79 hash_ipmark4_kadt(struct ip_set *set, const struct sk_buff *skb, 80 const struct xt_action_param *par, 81 enum ipset_adt adt, struct ip_set_adt_opt *opt) 82 { 83 const struct hash_ipmark4 *h = set->data; 84 ipset_adtfn adtfn = set->variant->adt[adt]; 85 struct hash_ipmark4_elem e = { }; 86 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 87 88 e.mark = skb->mark; 89 e.mark &= h->markmask; 90 91 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 92 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 93 } 94 95 static int 96 hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], 97 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 98 { 99 const struct hash_ipmark4 *h = set->data; 100 ipset_adtfn adtfn = set->variant->adt[adt]; 101 struct hash_ipmark4_elem e = { }; 102 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 103 u32 ip, ip_to = 0; 104 int ret; 105 106 if (tb[IPSET_ATTR_LINENO]) 107 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 108 109 if (unlikely(!tb[IPSET_ATTR_IP] || 110 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK))) 111 return -IPSET_ERR_PROTOCOL; 112 113 ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip); 114 if (ret) 115 return ret; 116 117 ret = ip_set_get_extensions(set, tb, &ext); 118 if (ret) 119 return ret; 120 121 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); 122 e.mark &= h->markmask; 123 124 if (adt == IPSET_TEST || 125 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { 126 ret = adtfn(set, &e, &ext, &ext, flags); 127 return ip_set_eexist(ret, flags) ? 0 : ret; 128 } 129 130 ip_to = ip = ntohl(e.ip); 131 if (tb[IPSET_ATTR_IP_TO]) { 132 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 133 if (ret) 134 return ret; 135 if (ip > ip_to) 136 swap(ip, ip_to); 137 } else if (tb[IPSET_ATTR_CIDR]) { 138 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 139 140 if (!cidr || cidr > HOST_MASK) 141 return -IPSET_ERR_INVALID_CIDR; 142 ip_set_mask_from_to(ip, ip_to, cidr); 143 } 144 145 if (retried) 146 ip = ntohl(h->next.ip); 147 for (; ip <= ip_to; ip++) { 148 e.ip = htonl(ip); 149 ret = adtfn(set, &e, &ext, &ext, flags); 150 151 if (ret && !ip_set_eexist(ret, flags)) 152 return ret; 153 154 ret = 0; 155 } 156 return ret; 157 } 158 159 /* IPv6 variant */ 160 161 struct hash_ipmark6_elem { 162 union nf_inet_addr ip; 163 __u32 mark; 164 }; 165 166 /* Common functions */ 167 168 static bool 169 hash_ipmark6_data_equal(const struct hash_ipmark6_elem *ip1, 170 const struct hash_ipmark6_elem *ip2, 171 u32 *multi) 172 { 173 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 174 ip1->mark == ip2->mark; 175 } 176 177 static bool 178 hash_ipmark6_data_list(struct sk_buff *skb, 179 const struct hash_ipmark6_elem *data) 180 { 181 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 182 nla_put_net32(skb, IPSET_ATTR_MARK, htonl(data->mark))) 183 goto nla_put_failure; 184 return false; 185 186 nla_put_failure: 187 return true; 188 } 189 190 static void 191 hash_ipmark6_data_next(struct hash_ipmark6_elem *next, 192 const struct hash_ipmark6_elem *d) 193 { 194 } 195 196 #undef MTYPE 197 #undef HOST_MASK 198 199 #define MTYPE hash_ipmark6 200 #define HOST_MASK 128 201 #define IP_SET_EMIT_CREATE 202 #include "ip_set_hash_gen.h" 203 204 static int 205 hash_ipmark6_kadt(struct ip_set *set, const struct sk_buff *skb, 206 const struct xt_action_param *par, 207 enum ipset_adt adt, struct ip_set_adt_opt *opt) 208 { 209 const struct hash_ipmark6 *h = set->data; 210 ipset_adtfn adtfn = set->variant->adt[adt]; 211 struct hash_ipmark6_elem e = { }; 212 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 213 214 e.mark = skb->mark; 215 e.mark &= h->markmask; 216 217 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 218 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 219 } 220 221 static int 222 hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], 223 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 224 { 225 const struct hash_ipmark6 *h = set->data; 226 ipset_adtfn adtfn = set->variant->adt[adt]; 227 struct hash_ipmark6_elem e = { }; 228 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 229 int ret; 230 231 if (tb[IPSET_ATTR_LINENO]) 232 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 233 234 if (unlikely(!tb[IPSET_ATTR_IP] || 235 !ip_set_attr_netorder(tb, IPSET_ATTR_MARK))) 236 return -IPSET_ERR_PROTOCOL; 237 if (unlikely(tb[IPSET_ATTR_IP_TO])) 238 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; 239 if (unlikely(tb[IPSET_ATTR_CIDR])) { 240 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 241 242 if (cidr != HOST_MASK) 243 return -IPSET_ERR_INVALID_CIDR; 244 } 245 246 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip); 247 if (ret) 248 return ret; 249 250 ret = ip_set_get_extensions(set, tb, &ext); 251 if (ret) 252 return ret; 253 254 e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); 255 e.mark &= h->markmask; 256 257 if (adt == IPSET_TEST) { 258 ret = adtfn(set, &e, &ext, &ext, flags); 259 return ip_set_eexist(ret, flags) ? 0 : ret; 260 } 261 262 ret = adtfn(set, &e, &ext, &ext, flags); 263 if (ret && !ip_set_eexist(ret, flags)) 264 return ret; 265 266 return 0; 267 } 268 269 static struct ip_set_type hash_ipmark_type __read_mostly = { 270 .name = "hash:ip,mark", 271 .protocol = IPSET_PROTOCOL, 272 .features = IPSET_TYPE_IP | IPSET_TYPE_MARK, 273 .dimension = IPSET_DIM_TWO, 274 .family = NFPROTO_UNSPEC, 275 .revision_min = IPSET_TYPE_REV_MIN, 276 .revision_max = IPSET_TYPE_REV_MAX, 277 .create = hash_ipmark_create, 278 .create_policy = { 279 [IPSET_ATTR_MARKMASK] = { .type = NLA_U32 }, 280 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 281 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 282 [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, 283 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 284 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 285 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 286 }, 287 .adt_policy = { 288 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 289 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 290 [IPSET_ATTR_MARK] = { .type = NLA_U32 }, 291 [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 292 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 293 [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 294 [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 295 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 296 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING, 297 .len = IPSET_MAX_COMMENT_SIZE }, 298 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, 299 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, 300 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, 301 }, 302 .me = THIS_MODULE, 303 }; 304 305 static int __init 306 hash_ipmark_init(void) 307 { 308 return ip_set_type_register(&hash_ipmark_type); 309 } 310 311 static void __exit 312 hash_ipmark_fini(void) 313 { 314 rcu_barrier(); 315 ip_set_type_unregister(&hash_ipmark_type); 316 } 317 318 module_init(hash_ipmark_init); 319 module_exit(hash_ipmark_fini); 320