PageRenderTime 29ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/net/netfilter/ipset/ip_set_hash_ip.c

https://github.com/iksaif/platform-drivers-x86
C | 492 lines | 388 code | 89 blank | 15 comment | 68 complexity | 1cb9d99627c205ae0934d5a5fb282f1a MD5 | raw file
  1. /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 as
  5. * published by the Free Software Foundation.
  6. */
  7. /* Kernel module implementing an IP set type: the hash:ip type */
  8. #include <linux/jhash.h>
  9. #include <linux/module.h>
  10. #include <linux/ip.h>
  11. #include <linux/skbuff.h>
  12. #include <linux/errno.h>
  13. #include <linux/random.h>
  14. #include <net/ip.h>
  15. #include <net/ipv6.h>
  16. #include <net/netlink.h>
  17. #include <net/tcp.h>
  18. #include <linux/netfilter.h>
  19. #include <linux/netfilter/ipset/pfxlen.h>
  20. #include <linux/netfilter/ipset/ip_set.h>
  21. #include <linux/netfilter/ipset/ip_set_timeout.h>
  22. #include <linux/netfilter/ipset/ip_set_hash.h>
  23. #define REVISION_MIN 0
  24. #define REVISION_MAX 0
  25. MODULE_LICENSE("GPL");
  26. MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  27. IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
  28. MODULE_ALIAS("ip_set_hash:ip");
  29. /* Type specific function prefix */
  30. #define TYPE hash_ip
  31. static bool
  32. hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
  33. #define hash_ip4_same_set hash_ip_same_set
  34. #define hash_ip6_same_set hash_ip_same_set
  35. /* The type variant functions: IPv4 */
  36. /* Member elements without timeout */
  37. struct hash_ip4_elem {
  38. __be32 ip;
  39. };
  40. /* Member elements with timeout support */
  41. struct hash_ip4_telem {
  42. __be32 ip;
  43. unsigned long timeout;
  44. };
  45. static inline bool
  46. hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
  47. const struct hash_ip4_elem *ip2,
  48. u32 *multi)
  49. {
  50. return ip1->ip == ip2->ip;
  51. }
  52. static inline bool
  53. hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
  54. {
  55. return elem->ip == 0;
  56. }
  57. static inline void
  58. hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
  59. {
  60. dst->ip = src->ip;
  61. }
  62. /* Zero valued IP addresses cannot be stored */
  63. static inline void
  64. hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
  65. {
  66. elem->ip = 0;
  67. }
  68. static inline bool
  69. hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
  70. {
  71. if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip))
  72. goto nla_put_failure;
  73. return 0;
  74. nla_put_failure:
  75. return 1;
  76. }
  77. static bool
  78. hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
  79. {
  80. const struct hash_ip4_telem *tdata =
  81. (const struct hash_ip4_telem *)data;
  82. if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
  83. nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
  84. htonl(ip_set_timeout_get(tdata->timeout))))
  85. goto nla_put_failure;
  86. return 0;
  87. nla_put_failure:
  88. return 1;
  89. }
  90. #define IP_SET_HASH_WITH_NETMASK
  91. #define PF 4
  92. #define HOST_MASK 32
  93. #include <linux/netfilter/ipset/ip_set_ahash.h>
  94. static inline void
  95. hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
  96. {
  97. h->next.ip = d->ip;
  98. }
  99. static int
  100. hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
  101. const struct xt_action_param *par,
  102. enum ipset_adt adt, const struct ip_set_adt_opt *opt)
  103. {
  104. const struct ip_set_hash *h = set->data;
  105. ipset_adtfn adtfn = set->variant->adt[adt];
  106. __be32 ip;
  107. ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
  108. ip &= ip_set_netmask(h->netmask);
  109. if (ip == 0)
  110. return -EINVAL;
  111. return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
  112. }
  113. static int
  114. hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
  115. enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
  116. {
  117. const struct ip_set_hash *h = set->data;
  118. ipset_adtfn adtfn = set->variant->adt[adt];
  119. u32 ip, ip_to, hosts, timeout = h->timeout;
  120. __be32 nip;
  121. int ret = 0;
  122. if (unlikely(!tb[IPSET_ATTR_IP] ||
  123. !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
  124. return -IPSET_ERR_PROTOCOL;
  125. if (tb[IPSET_ATTR_LINENO])
  126. *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
  127. ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
  128. if (ret)
  129. return ret;
  130. ip &= ip_set_hostmask(h->netmask);
  131. if (tb[IPSET_ATTR_TIMEOUT]) {
  132. if (!with_timeout(h->timeout))
  133. return -IPSET_ERR_TIMEOUT;
  134. timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
  135. }
  136. if (adt == IPSET_TEST) {
  137. nip = htonl(ip);
  138. if (nip == 0)
  139. return -IPSET_ERR_HASH_ELEM;
  140. return adtfn(set, &nip, timeout, flags);
  141. }
  142. ip_to = ip;
  143. if (tb[IPSET_ATTR_IP_TO]) {
  144. ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
  145. if (ret)
  146. return ret;
  147. if (ip > ip_to)
  148. swap(ip, ip_to);
  149. } else if (tb[IPSET_ATTR_CIDR]) {
  150. u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
  151. if (!cidr || cidr > 32)
  152. return -IPSET_ERR_INVALID_CIDR;
  153. ip_set_mask_from_to(ip, ip_to, cidr);
  154. }
  155. hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
  156. if (retried)
  157. ip = ntohl(h->next.ip);
  158. for (; !before(ip_to, ip); ip += hosts) {
  159. nip = htonl(ip);
  160. if (nip == 0)
  161. return -IPSET_ERR_HASH_ELEM;
  162. ret = adtfn(set, &nip, timeout, flags);
  163. if (ret && !ip_set_eexist(ret, flags))
  164. return ret;
  165. else
  166. ret = 0;
  167. }
  168. return ret;
  169. }
  170. static bool
  171. hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
  172. {
  173. const struct ip_set_hash *x = a->data;
  174. const struct ip_set_hash *y = b->data;
  175. /* Resizing changes htable_bits, so we ignore it */
  176. return x->maxelem == y->maxelem &&
  177. x->timeout == y->timeout &&
  178. x->netmask == y->netmask;
  179. }
  180. /* The type variant functions: IPv6 */
  181. struct hash_ip6_elem {
  182. union nf_inet_addr ip;
  183. };
  184. struct hash_ip6_telem {
  185. union nf_inet_addr ip;
  186. unsigned long timeout;
  187. };
  188. static inline bool
  189. hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
  190. const struct hash_ip6_elem *ip2,
  191. u32 *multi)
  192. {
  193. return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6);
  194. }
  195. static inline bool
  196. hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
  197. {
  198. return ipv6_addr_any(&elem->ip.in6);
  199. }
  200. static inline void
  201. hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
  202. {
  203. dst->ip.in6 = src->ip.in6;
  204. }
  205. static inline void
  206. hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
  207. {
  208. ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
  209. }
  210. static inline void
  211. ip6_netmask(union nf_inet_addr *ip, u8 prefix)
  212. {
  213. ip->ip6[0] &= ip_set_netmask6(prefix)[0];
  214. ip->ip6[1] &= ip_set_netmask6(prefix)[1];
  215. ip->ip6[2] &= ip_set_netmask6(prefix)[2];
  216. ip->ip6[3] &= ip_set_netmask6(prefix)[3];
  217. }
  218. static bool
  219. hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
  220. {
  221. if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6))
  222. goto nla_put_failure;
  223. return 0;
  224. nla_put_failure:
  225. return 1;
  226. }
  227. static bool
  228. hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
  229. {
  230. const struct hash_ip6_telem *e =
  231. (const struct hash_ip6_telem *)data;
  232. if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
  233. nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
  234. htonl(ip_set_timeout_get(e->timeout))))
  235. goto nla_put_failure;
  236. return 0;
  237. nla_put_failure:
  238. return 1;
  239. }
  240. #undef PF
  241. #undef HOST_MASK
  242. #define PF 6
  243. #define HOST_MASK 128
  244. #include <linux/netfilter/ipset/ip_set_ahash.h>
  245. static inline void
  246. hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
  247. {
  248. }
  249. static int
  250. hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
  251. const struct xt_action_param *par,
  252. enum ipset_adt adt, const struct ip_set_adt_opt *opt)
  253. {
  254. const struct ip_set_hash *h = set->data;
  255. ipset_adtfn adtfn = set->variant->adt[adt];
  256. union nf_inet_addr ip;
  257. ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
  258. ip6_netmask(&ip, h->netmask);
  259. if (ipv6_addr_any(&ip.in6))
  260. return -EINVAL;
  261. return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
  262. }
  263. static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
  264. [IPSET_ATTR_IP] = { .type = NLA_NESTED },
  265. [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  266. [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
  267. };
  268. static int
  269. hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
  270. enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
  271. {
  272. const struct ip_set_hash *h = set->data;
  273. ipset_adtfn adtfn = set->variant->adt[adt];
  274. union nf_inet_addr ip;
  275. u32 timeout = h->timeout;
  276. int ret;
  277. if (unlikely(!tb[IPSET_ATTR_IP] ||
  278. !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
  279. tb[IPSET_ATTR_IP_TO] ||
  280. tb[IPSET_ATTR_CIDR]))
  281. return -IPSET_ERR_PROTOCOL;
  282. if (tb[IPSET_ATTR_LINENO])
  283. *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
  284. ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
  285. if (ret)
  286. return ret;
  287. ip6_netmask(&ip, h->netmask);
  288. if (ipv6_addr_any(&ip.in6))
  289. return -IPSET_ERR_HASH_ELEM;
  290. if (tb[IPSET_ATTR_TIMEOUT]) {
  291. if (!with_timeout(h->timeout))
  292. return -IPSET_ERR_TIMEOUT;
  293. timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
  294. }
  295. ret = adtfn(set, &ip, timeout, flags);
  296. return ip_set_eexist(ret, flags) ? 0 : ret;
  297. }
  298. /* Create hash:ip type of sets */
  299. static int
  300. hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
  301. {
  302. u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
  303. u8 netmask, hbits;
  304. size_t hsize;
  305. struct ip_set_hash *h;
  306. if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
  307. return -IPSET_ERR_INVALID_FAMILY;
  308. netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
  309. pr_debug("Create set %s with family %s\n",
  310. set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
  311. if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
  312. !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
  313. !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
  314. return -IPSET_ERR_PROTOCOL;
  315. if (tb[IPSET_ATTR_HASHSIZE]) {
  316. hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
  317. if (hashsize < IPSET_MIMINAL_HASHSIZE)
  318. hashsize = IPSET_MIMINAL_HASHSIZE;
  319. }
  320. if (tb[IPSET_ATTR_MAXELEM])
  321. maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
  322. if (tb[IPSET_ATTR_NETMASK]) {
  323. netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
  324. if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
  325. (set->family == NFPROTO_IPV6 && netmask > 128) ||
  326. netmask == 0)
  327. return -IPSET_ERR_INVALID_NETMASK;
  328. }
  329. h = kzalloc(sizeof(*h), GFP_KERNEL);
  330. if (!h)
  331. return -ENOMEM;
  332. h->maxelem = maxelem;
  333. h->netmask = netmask;
  334. get_random_bytes(&h->initval, sizeof(h->initval));
  335. h->timeout = IPSET_NO_TIMEOUT;
  336. hbits = htable_bits(hashsize);
  337. hsize = htable_size(hbits);
  338. if (hsize == 0) {
  339. kfree(h);
  340. return -ENOMEM;
  341. }
  342. h->table = ip_set_alloc(hsize);
  343. if (!h->table) {
  344. kfree(h);
  345. return -ENOMEM;
  346. }
  347. h->table->htable_bits = hbits;
  348. set->data = h;
  349. if (tb[IPSET_ATTR_TIMEOUT]) {
  350. h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
  351. set->variant = set->family == NFPROTO_IPV4
  352. ? &hash_ip4_tvariant : &hash_ip6_tvariant;
  353. if (set->family == NFPROTO_IPV4)
  354. hash_ip4_gc_init(set);
  355. else
  356. hash_ip6_gc_init(set);
  357. } else {
  358. set->variant = set->family == NFPROTO_IPV4
  359. ? &hash_ip4_variant : &hash_ip6_variant;
  360. }
  361. pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
  362. set->name, jhash_size(h->table->htable_bits),
  363. h->table->htable_bits, h->maxelem, set->data, h->table);
  364. return 0;
  365. }
  366. static struct ip_set_type hash_ip_type __read_mostly = {
  367. .name = "hash:ip",
  368. .protocol = IPSET_PROTOCOL,
  369. .features = IPSET_TYPE_IP,
  370. .dimension = IPSET_DIM_ONE,
  371. .family = NFPROTO_UNSPEC,
  372. .revision_min = REVISION_MIN,
  373. .revision_max = REVISION_MAX,
  374. .create = hash_ip_create,
  375. .create_policy = {
  376. [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
  377. [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
  378. [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
  379. [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
  380. [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  381. [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
  382. },
  383. .adt_policy = {
  384. [IPSET_ATTR_IP] = { .type = NLA_NESTED },
  385. [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
  386. [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
  387. [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  388. [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
  389. },
  390. .me = THIS_MODULE,
  391. };
  392. static int __init
  393. hash_ip_init(void)
  394. {
  395. return ip_set_type_register(&hash_ip_type);
  396. }
  397. static void __exit
  398. hash_ip_fini(void)
  399. {
  400. ip_set_type_unregister(&hash_ip_type);
  401. }
  402. module_init(hash_ip_init);
  403. module_exit(hash_ip_fini);