ip_set_hash_netport.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /* Copyright (C) 2003-2013 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:net,port 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 <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_getport.h>
  21. #include <linux/netfilter/ipset/ip_set_hash.h>
  22. #define IPSET_TYPE_REV_MIN 0
  23. /* 1 SCTP and UDPLITE support added */
  24. /* 2 Range as input support for IPv4 added */
  25. /* 3 nomatch flag support added */
  26. /* 4 Counters support added */
  27. /* 5 Comments support added */
  28. /* 6 Forceadd support added */
  29. #define IPSET_TYPE_REV_MAX 7 /* skbinfo support added */
  30. MODULE_LICENSE("GPL");
  31. MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  32. IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  33. MODULE_ALIAS("ip_set_hash:net,port");
  34. /* Type specific function prefix */
  35. #define HTYPE hash_netport
  36. #define IP_SET_HASH_WITH_PROTO
  37. #define IP_SET_HASH_WITH_NETS
  38. /* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
  39. * However this way we have to store internally cidr - 1,
  40. * dancing back and forth.
  41. */
  42. #define IP_SET_HASH_WITH_NETS_PACKED
  43. /* IPv4 variant */
  44. /* Member elements */
  45. struct hash_netport4_elem {
  46. __be32 ip;
  47. __be16 port;
  48. u8 proto;
  49. u8 cidr:7;
  50. u8 nomatch:1;
  51. };
  52. /* Common functions */
  53. static inline bool
  54. hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
  55. const struct hash_netport4_elem *ip2,
  56. u32 *multi)
  57. {
  58. return ip1->ip == ip2->ip &&
  59. ip1->port == ip2->port &&
  60. ip1->proto == ip2->proto &&
  61. ip1->cidr == ip2->cidr;
  62. }
  63. static inline int
  64. hash_netport4_do_data_match(const struct hash_netport4_elem *elem)
  65. {
  66. return elem->nomatch ? -ENOTEMPTY : 1;
  67. }
  68. static inline void
  69. hash_netport4_data_set_flags(struct hash_netport4_elem *elem, u32 flags)
  70. {
  71. elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
  72. }
  73. static inline void
  74. hash_netport4_data_reset_flags(struct hash_netport4_elem *elem, u8 *flags)
  75. {
  76. swap(*flags, elem->nomatch);
  77. }
  78. static inline void
  79. hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
  80. {
  81. elem->ip &= ip_set_netmask(cidr);
  82. elem->cidr = cidr - 1;
  83. }
  84. static bool
  85. hash_netport4_data_list(struct sk_buff *skb,
  86. const struct hash_netport4_elem *data)
  87. {
  88. u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
  89. if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
  90. nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
  91. nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
  92. nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
  93. (flags &&
  94. nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
  95. goto nla_put_failure;
  96. return false;
  97. nla_put_failure:
  98. return true;
  99. }
  100. static inline void
  101. hash_netport4_data_next(struct hash_netport4_elem *next,
  102. const struct hash_netport4_elem *d)
  103. {
  104. next->ip = d->ip;
  105. next->port = d->port;
  106. }
  107. #define MTYPE hash_netport4
  108. #define HOST_MASK 32
  109. #include "ip_set_hash_gen.h"
  110. static int
  111. hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
  112. const struct xt_action_param *par,
  113. enum ipset_adt adt, struct ip_set_adt_opt *opt)
  114. {
  115. const struct hash_netport *h = set->data;
  116. ipset_adtfn adtfn = set->variant->adt[adt];
  117. struct hash_netport4_elem e = {
  118. .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
  119. };
  120. struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
  121. if (adt == IPSET_TEST)
  122. e.cidr = HOST_MASK - 1;
  123. if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
  124. &e.port, &e.proto))
  125. return -EINVAL;
  126. ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
  127. e.ip &= ip_set_netmask(e.cidr + 1);
  128. return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
  129. }
  130. static int
  131. hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
  132. enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
  133. {
  134. const struct hash_netport *h = set->data;
  135. ipset_adtfn adtfn = set->variant->adt[adt];
  136. struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
  137. struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
  138. u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
  139. bool with_ports = false;
  140. u8 cidr;
  141. int ret;
  142. if (tb[IPSET_ATTR_LINENO])
  143. *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
  144. if (unlikely(!tb[IPSET_ATTR_IP] ||
  145. !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
  146. !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
  147. !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
  148. return -IPSET_ERR_PROTOCOL;
  149. ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
  150. if (ret)
  151. return ret;
  152. ret = ip_set_get_extensions(set, tb, &ext);
  153. if (ret)
  154. return ret;
  155. if (tb[IPSET_ATTR_CIDR]) {
  156. cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
  157. if (!cidr || cidr > HOST_MASK)
  158. return -IPSET_ERR_INVALID_CIDR;
  159. e.cidr = cidr - 1;
  160. }
  161. e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
  162. if (tb[IPSET_ATTR_PROTO]) {
  163. e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
  164. with_ports = ip_set_proto_with_ports(e.proto);
  165. if (e.proto == 0)
  166. return -IPSET_ERR_INVALID_PROTO;
  167. } else {
  168. return -IPSET_ERR_MISSING_PROTO;
  169. }
  170. if (!(with_ports || e.proto == IPPROTO_ICMP))
  171. e.port = 0;
  172. with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
  173. if (tb[IPSET_ATTR_CADT_FLAGS]) {
  174. u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
  175. if (cadt_flags & IPSET_FLAG_NOMATCH)
  176. flags |= (IPSET_FLAG_NOMATCH << 16);
  177. }
  178. if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
  179. e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
  180. ret = adtfn(set, &e, &ext, &ext, flags);
  181. return ip_set_enomatch(ret, flags, adt, set) ? -ret :
  182. ip_set_eexist(ret, flags) ? 0 : ret;
  183. }
  184. port = port_to = ntohs(e.port);
  185. if (tb[IPSET_ATTR_PORT_TO]) {
  186. port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
  187. if (port_to < port)
  188. swap(port, port_to);
  189. }
  190. if (tb[IPSET_ATTR_IP_TO]) {
  191. ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
  192. if (ret)
  193. return ret;
  194. if (ip_to < ip)
  195. swap(ip, ip_to);
  196. if (ip + UINT_MAX == ip_to)
  197. return -IPSET_ERR_HASH_RANGE;
  198. } else {
  199. ip_set_mask_from_to(ip, ip_to, e.cidr + 1);
  200. }
  201. if (retried)
  202. ip = ntohl(h->next.ip);
  203. while (!after(ip, ip_to)) {
  204. e.ip = htonl(ip);
  205. last = ip_set_range_to_cidr(ip, ip_to, &cidr);
  206. e.cidr = cidr - 1;
  207. p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
  208. : port;
  209. for (; p <= port_to; p++) {
  210. e.port = htons(p);
  211. ret = adtfn(set, &e, &ext, &ext, flags);
  212. if (ret && !ip_set_eexist(ret, flags))
  213. return ret;
  214. ret = 0;
  215. }
  216. ip = last + 1;
  217. }
  218. return ret;
  219. }
  220. /* IPv6 variant */
  221. struct hash_netport6_elem {
  222. union nf_inet_addr ip;
  223. __be16 port;
  224. u8 proto;
  225. u8 cidr:7;
  226. u8 nomatch:1;
  227. };
  228. /* Common functions */
  229. static inline bool
  230. hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
  231. const struct hash_netport6_elem *ip2,
  232. u32 *multi)
  233. {
  234. return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
  235. ip1->port == ip2->port &&
  236. ip1->proto == ip2->proto &&
  237. ip1->cidr == ip2->cidr;
  238. }
  239. static inline int
  240. hash_netport6_do_data_match(const struct hash_netport6_elem *elem)
  241. {
  242. return elem->nomatch ? -ENOTEMPTY : 1;
  243. }
  244. static inline void
  245. hash_netport6_data_set_flags(struct hash_netport6_elem *elem, u32 flags)
  246. {
  247. elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
  248. }
  249. static inline void
  250. hash_netport6_data_reset_flags(struct hash_netport6_elem *elem, u8 *flags)
  251. {
  252. swap(*flags, elem->nomatch);
  253. }
  254. static inline void
  255. hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
  256. {
  257. ip6_netmask(&elem->ip, cidr);
  258. elem->cidr = cidr - 1;
  259. }
  260. static bool
  261. hash_netport6_data_list(struct sk_buff *skb,
  262. const struct hash_netport6_elem *data)
  263. {
  264. u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
  265. if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
  266. nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
  267. nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr + 1) ||
  268. nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
  269. (flags &&
  270. nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
  271. goto nla_put_failure;
  272. return false;
  273. nla_put_failure:
  274. return true;
  275. }
  276. static inline void
  277. hash_netport6_data_next(struct hash_netport4_elem *next,
  278. const struct hash_netport6_elem *d)
  279. {
  280. next->port = d->port;
  281. }
  282. #undef MTYPE
  283. #undef HOST_MASK
  284. #define MTYPE hash_netport6
  285. #define HOST_MASK 128
  286. #define IP_SET_EMIT_CREATE
  287. #include "ip_set_hash_gen.h"
  288. static int
  289. hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
  290. const struct xt_action_param *par,
  291. enum ipset_adt adt, struct ip_set_adt_opt *opt)
  292. {
  293. const struct hash_netport *h = set->data;
  294. ipset_adtfn adtfn = set->variant->adt[adt];
  295. struct hash_netport6_elem e = {
  296. .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
  297. };
  298. struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
  299. if (adt == IPSET_TEST)
  300. e.cidr = HOST_MASK - 1;
  301. if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
  302. &e.port, &e.proto))
  303. return -EINVAL;
  304. ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
  305. ip6_netmask(&e.ip, e.cidr + 1);
  306. return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
  307. }
  308. static int
  309. hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
  310. enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
  311. {
  312. const struct hash_netport *h = set->data;
  313. ipset_adtfn adtfn = set->variant->adt[adt];
  314. struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 };
  315. struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
  316. u32 port, port_to;
  317. bool with_ports = false;
  318. u8 cidr;
  319. int ret;
  320. if (tb[IPSET_ATTR_LINENO])
  321. *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
  322. if (unlikely(!tb[IPSET_ATTR_IP] ||
  323. !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
  324. !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
  325. !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
  326. return -IPSET_ERR_PROTOCOL;
  327. if (unlikely(tb[IPSET_ATTR_IP_TO]))
  328. return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
  329. ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
  330. if (ret)
  331. return ret;
  332. ret = ip_set_get_extensions(set, tb, &ext);
  333. if (ret)
  334. return ret;
  335. if (tb[IPSET_ATTR_CIDR]) {
  336. cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
  337. if (!cidr || cidr > HOST_MASK)
  338. return -IPSET_ERR_INVALID_CIDR;
  339. e.cidr = cidr - 1;
  340. }
  341. ip6_netmask(&e.ip, e.cidr + 1);
  342. e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
  343. if (tb[IPSET_ATTR_PROTO]) {
  344. e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
  345. with_ports = ip_set_proto_with_ports(e.proto);
  346. if (e.proto == 0)
  347. return -IPSET_ERR_INVALID_PROTO;
  348. } else {
  349. return -IPSET_ERR_MISSING_PROTO;
  350. }
  351. if (!(with_ports || e.proto == IPPROTO_ICMPV6))
  352. e.port = 0;
  353. if (tb[IPSET_ATTR_CADT_FLAGS]) {
  354. u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
  355. if (cadt_flags & IPSET_FLAG_NOMATCH)
  356. flags |= (IPSET_FLAG_NOMATCH << 16);
  357. }
  358. if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
  359. ret = adtfn(set, &e, &ext, &ext, flags);
  360. return ip_set_enomatch(ret, flags, adt, set) ? -ret :
  361. ip_set_eexist(ret, flags) ? 0 : ret;
  362. }
  363. port = ntohs(e.port);
  364. port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
  365. if (port > port_to)
  366. swap(port, port_to);
  367. if (retried)
  368. port = ntohs(h->next.port);
  369. for (; port <= port_to; port++) {
  370. e.port = htons(port);
  371. ret = adtfn(set, &e, &ext, &ext, flags);
  372. if (ret && !ip_set_eexist(ret, flags))
  373. return ret;
  374. ret = 0;
  375. }
  376. return ret;
  377. }
  378. static struct ip_set_type hash_netport_type __read_mostly = {
  379. .name = "hash:net,port",
  380. .protocol = IPSET_PROTOCOL,
  381. .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,
  382. .dimension = IPSET_DIM_TWO,
  383. .family = NFPROTO_UNSPEC,
  384. .revision_min = IPSET_TYPE_REV_MIN,
  385. .revision_max = IPSET_TYPE_REV_MAX,
  386. .create = hash_netport_create,
  387. .create_policy = {
  388. [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
  389. [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
  390. [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
  391. [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
  392. [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
  393. [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  394. [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
  395. },
  396. .adt_policy = {
  397. [IPSET_ATTR_IP] = { .type = NLA_NESTED },
  398. [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
  399. [IPSET_ATTR_PORT] = { .type = NLA_U16 },
  400. [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
  401. [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
  402. [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
  403. [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
  404. [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
  405. [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
  406. [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
  407. [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
  408. [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
  409. .len = IPSET_MAX_COMMENT_SIZE },
  410. [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
  411. [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
  412. [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
  413. },
  414. .me = THIS_MODULE,
  415. };
  416. static int __init
  417. hash_netport_init(void)
  418. {
  419. return ip_set_type_register(&hash_netport_type);
  420. }
  421. static void __exit
  422. hash_netport_fini(void)
  423. {
  424. rcu_barrier();
  425. ip_set_type_unregister(&hash_netport_type);
  426. }
  427. module_init(hash_netport_init);
  428. module_exit(hash_netport_fini);