nft_payload.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. /*
  2. * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  3. * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Development of this code funded by Astaro AG (http://www.astaro.com/)
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/if_vlan.h>
  13. #include <linux/init.h>
  14. #include <linux/module.h>
  15. #include <linux/netlink.h>
  16. #include <linux/netfilter.h>
  17. #include <linux/netfilter/nf_tables.h>
  18. #include <net/netfilter/nf_tables_core.h>
  19. #include <net/netfilter/nf_tables.h>
  20. /* For layer 4 checksum field offset. */
  21. #include <linux/tcp.h>
  22. #include <linux/udp.h>
  23. #include <linux/icmpv6.h>
  24. /* add vlan header into the user buffer for if tag was removed by offloads */
  25. static bool
  26. nft_payload_copy_vlan(u32 *d, const struct sk_buff *skb, u8 offset, u8 len)
  27. {
  28. int mac_off = skb_mac_header(skb) - skb->data;
  29. u8 vlan_len, *vlanh, *dst_u8 = (u8 *) d;
  30. struct vlan_ethhdr veth;
  31. vlanh = (u8 *) &veth;
  32. if (offset < ETH_HLEN) {
  33. u8 ethlen = min_t(u8, len, ETH_HLEN - offset);
  34. if (skb_copy_bits(skb, mac_off, &veth, ETH_HLEN))
  35. return false;
  36. veth.h_vlan_proto = skb->vlan_proto;
  37. memcpy(dst_u8, vlanh + offset, ethlen);
  38. len -= ethlen;
  39. if (len == 0)
  40. return true;
  41. dst_u8 += ethlen;
  42. offset = ETH_HLEN;
  43. } else if (offset >= VLAN_ETH_HLEN) {
  44. offset -= VLAN_HLEN;
  45. goto skip;
  46. }
  47. veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb));
  48. veth.h_vlan_encapsulated_proto = skb->protocol;
  49. vlanh += offset;
  50. vlan_len = min_t(u8, len, VLAN_ETH_HLEN - offset);
  51. memcpy(dst_u8, vlanh, vlan_len);
  52. len -= vlan_len;
  53. if (!len)
  54. return true;
  55. dst_u8 += vlan_len;
  56. skip:
  57. return skb_copy_bits(skb, offset + mac_off, dst_u8, len) == 0;
  58. }
  59. static void nft_payload_eval(const struct nft_expr *expr,
  60. struct nft_regs *regs,
  61. const struct nft_pktinfo *pkt)
  62. {
  63. const struct nft_payload *priv = nft_expr_priv(expr);
  64. const struct sk_buff *skb = pkt->skb;
  65. u32 *dest = &regs->data[priv->dreg];
  66. int offset;
  67. dest[priv->len / NFT_REG32_SIZE] = 0;
  68. switch (priv->base) {
  69. case NFT_PAYLOAD_LL_HEADER:
  70. if (!skb_mac_header_was_set(skb))
  71. goto err;
  72. if (skb_vlan_tag_present(skb)) {
  73. if (!nft_payload_copy_vlan(dest, skb,
  74. priv->offset, priv->len))
  75. goto err;
  76. return;
  77. }
  78. offset = skb_mac_header(skb) - skb->data;
  79. break;
  80. case NFT_PAYLOAD_NETWORK_HEADER:
  81. offset = skb_network_offset(skb);
  82. break;
  83. case NFT_PAYLOAD_TRANSPORT_HEADER:
  84. if (!pkt->tprot_set)
  85. goto err;
  86. offset = pkt->xt.thoff;
  87. break;
  88. default:
  89. BUG();
  90. }
  91. offset += priv->offset;
  92. if (skb_copy_bits(skb, offset, dest, priv->len) < 0)
  93. goto err;
  94. return;
  95. err:
  96. regs->verdict.code = NFT_BREAK;
  97. }
  98. static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
  99. [NFTA_PAYLOAD_SREG] = { .type = NLA_U32 },
  100. [NFTA_PAYLOAD_DREG] = { .type = NLA_U32 },
  101. [NFTA_PAYLOAD_BASE] = { .type = NLA_U32 },
  102. [NFTA_PAYLOAD_OFFSET] = { .type = NLA_U32 },
  103. [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 },
  104. [NFTA_PAYLOAD_CSUM_TYPE] = { .type = NLA_U32 },
  105. [NFTA_PAYLOAD_CSUM_OFFSET] = { .type = NLA_U32 },
  106. [NFTA_PAYLOAD_CSUM_FLAGS] = { .type = NLA_U32 },
  107. };
  108. static int nft_payload_init(const struct nft_ctx *ctx,
  109. const struct nft_expr *expr,
  110. const struct nlattr * const tb[])
  111. {
  112. struct nft_payload *priv = nft_expr_priv(expr);
  113. priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
  114. priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
  115. priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
  116. priv->dreg = nft_parse_register(tb[NFTA_PAYLOAD_DREG]);
  117. return nft_validate_register_store(ctx, priv->dreg, NULL,
  118. NFT_DATA_VALUE, priv->len);
  119. }
  120. static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
  121. {
  122. const struct nft_payload *priv = nft_expr_priv(expr);
  123. if (nft_dump_register(skb, NFTA_PAYLOAD_DREG, priv->dreg) ||
  124. nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
  125. nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
  126. nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
  127. goto nla_put_failure;
  128. return 0;
  129. nla_put_failure:
  130. return -1;
  131. }
  132. static const struct nft_expr_ops nft_payload_ops = {
  133. .type = &nft_payload_type,
  134. .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
  135. .eval = nft_payload_eval,
  136. .init = nft_payload_init,
  137. .dump = nft_payload_dump,
  138. };
  139. const struct nft_expr_ops nft_payload_fast_ops = {
  140. .type = &nft_payload_type,
  141. .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
  142. .eval = nft_payload_eval,
  143. .init = nft_payload_init,
  144. .dump = nft_payload_dump,
  145. };
  146. static inline void nft_csum_replace(__sum16 *sum, __wsum fsum, __wsum tsum)
  147. {
  148. *sum = csum_fold(csum_add(csum_sub(~csum_unfold(*sum), fsum), tsum));
  149. if (*sum == 0)
  150. *sum = CSUM_MANGLED_0;
  151. }
  152. static bool nft_payload_udp_checksum(struct sk_buff *skb, unsigned int thoff)
  153. {
  154. struct udphdr *uh, _uh;
  155. uh = skb_header_pointer(skb, thoff, sizeof(_uh), &_uh);
  156. if (!uh)
  157. return false;
  158. return (__force bool)uh->check;
  159. }
  160. static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
  161. struct sk_buff *skb,
  162. unsigned int *l4csum_offset)
  163. {
  164. switch (pkt->tprot) {
  165. case IPPROTO_TCP:
  166. *l4csum_offset = offsetof(struct tcphdr, check);
  167. break;
  168. case IPPROTO_UDP:
  169. if (!nft_payload_udp_checksum(skb, pkt->xt.thoff))
  170. return -1;
  171. /* Fall through. */
  172. case IPPROTO_UDPLITE:
  173. *l4csum_offset = offsetof(struct udphdr, check);
  174. break;
  175. case IPPROTO_ICMPV6:
  176. *l4csum_offset = offsetof(struct icmp6hdr, icmp6_cksum);
  177. break;
  178. default:
  179. return -1;
  180. }
  181. *l4csum_offset += pkt->xt.thoff;
  182. return 0;
  183. }
  184. static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
  185. struct sk_buff *skb,
  186. __wsum fsum, __wsum tsum)
  187. {
  188. int l4csum_offset;
  189. __sum16 sum;
  190. /* If we cannot determine layer 4 checksum offset or this packet doesn't
  191. * require layer 4 checksum recalculation, skip this packet.
  192. */
  193. if (nft_payload_l4csum_offset(pkt, skb, &l4csum_offset) < 0)
  194. return 0;
  195. if (skb_copy_bits(skb, l4csum_offset, &sum, sizeof(sum)) < 0)
  196. return -1;
  197. /* Checksum mangling for an arbitrary amount of bytes, based on
  198. * inet_proto_csum_replace*() functions.
  199. */
  200. if (skb->ip_summed != CHECKSUM_PARTIAL) {
  201. nft_csum_replace(&sum, fsum, tsum);
  202. if (skb->ip_summed == CHECKSUM_COMPLETE) {
  203. skb->csum = ~csum_add(csum_sub(~(skb->csum), fsum),
  204. tsum);
  205. }
  206. } else {
  207. sum = ~csum_fold(csum_add(csum_sub(csum_unfold(sum), fsum),
  208. tsum));
  209. }
  210. if (!skb_make_writable(skb, l4csum_offset + sizeof(sum)) ||
  211. skb_store_bits(skb, l4csum_offset, &sum, sizeof(sum)) < 0)
  212. return -1;
  213. return 0;
  214. }
  215. static int nft_payload_csum_inet(struct sk_buff *skb, const u32 *src,
  216. __wsum fsum, __wsum tsum, int csum_offset)
  217. {
  218. __sum16 sum;
  219. if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
  220. return -1;
  221. nft_csum_replace(&sum, fsum, tsum);
  222. if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
  223. skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
  224. return -1;
  225. return 0;
  226. }
  227. static void nft_payload_set_eval(const struct nft_expr *expr,
  228. struct nft_regs *regs,
  229. const struct nft_pktinfo *pkt)
  230. {
  231. const struct nft_payload_set *priv = nft_expr_priv(expr);
  232. struct sk_buff *skb = pkt->skb;
  233. const u32 *src = &regs->data[priv->sreg];
  234. int offset, csum_offset;
  235. __wsum fsum, tsum;
  236. switch (priv->base) {
  237. case NFT_PAYLOAD_LL_HEADER:
  238. if (!skb_mac_header_was_set(skb))
  239. goto err;
  240. offset = skb_mac_header(skb) - skb->data;
  241. break;
  242. case NFT_PAYLOAD_NETWORK_HEADER:
  243. offset = skb_network_offset(skb);
  244. break;
  245. case NFT_PAYLOAD_TRANSPORT_HEADER:
  246. if (!pkt->tprot_set)
  247. goto err;
  248. offset = pkt->xt.thoff;
  249. break;
  250. default:
  251. BUG();
  252. }
  253. csum_offset = offset + priv->csum_offset;
  254. offset += priv->offset;
  255. if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
  256. (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
  257. skb->ip_summed != CHECKSUM_PARTIAL)) {
  258. fsum = skb_checksum(skb, offset, priv->len, 0);
  259. tsum = csum_partial(src, priv->len, 0);
  260. if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
  261. nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
  262. goto err;
  263. if (priv->csum_flags &&
  264. nft_payload_l4csum_update(pkt, skb, fsum, tsum) < 0)
  265. goto err;
  266. }
  267. if (!skb_make_writable(skb, max(offset + priv->len, 0)) ||
  268. skb_store_bits(skb, offset, src, priv->len) < 0)
  269. goto err;
  270. return;
  271. err:
  272. regs->verdict.code = NFT_BREAK;
  273. }
  274. static int nft_payload_set_init(const struct nft_ctx *ctx,
  275. const struct nft_expr *expr,
  276. const struct nlattr * const tb[])
  277. {
  278. struct nft_payload_set *priv = nft_expr_priv(expr);
  279. priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
  280. priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
  281. priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
  282. priv->sreg = nft_parse_register(tb[NFTA_PAYLOAD_SREG]);
  283. if (tb[NFTA_PAYLOAD_CSUM_TYPE])
  284. priv->csum_type =
  285. ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_TYPE]));
  286. if (tb[NFTA_PAYLOAD_CSUM_OFFSET])
  287. priv->csum_offset =
  288. ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_OFFSET]));
  289. if (tb[NFTA_PAYLOAD_CSUM_FLAGS]) {
  290. u32 flags;
  291. flags = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_CSUM_FLAGS]));
  292. if (flags & ~NFT_PAYLOAD_L4CSUM_PSEUDOHDR)
  293. return -EINVAL;
  294. priv->csum_flags = flags;
  295. }
  296. switch (priv->csum_type) {
  297. case NFT_PAYLOAD_CSUM_NONE:
  298. case NFT_PAYLOAD_CSUM_INET:
  299. break;
  300. default:
  301. return -EOPNOTSUPP;
  302. }
  303. return nft_validate_register_load(priv->sreg, priv->len);
  304. }
  305. static int nft_payload_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
  306. {
  307. const struct nft_payload_set *priv = nft_expr_priv(expr);
  308. if (nft_dump_register(skb, NFTA_PAYLOAD_SREG, priv->sreg) ||
  309. nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
  310. nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
  311. nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)) ||
  312. nla_put_be32(skb, NFTA_PAYLOAD_CSUM_TYPE, htonl(priv->csum_type)) ||
  313. nla_put_be32(skb, NFTA_PAYLOAD_CSUM_OFFSET,
  314. htonl(priv->csum_offset)) ||
  315. nla_put_be32(skb, NFTA_PAYLOAD_CSUM_FLAGS, htonl(priv->csum_flags)))
  316. goto nla_put_failure;
  317. return 0;
  318. nla_put_failure:
  319. return -1;
  320. }
  321. static const struct nft_expr_ops nft_payload_set_ops = {
  322. .type = &nft_payload_type,
  323. .size = NFT_EXPR_SIZE(sizeof(struct nft_payload_set)),
  324. .eval = nft_payload_set_eval,
  325. .init = nft_payload_set_init,
  326. .dump = nft_payload_set_dump,
  327. };
  328. static const struct nft_expr_ops *
  329. nft_payload_select_ops(const struct nft_ctx *ctx,
  330. const struct nlattr * const tb[])
  331. {
  332. enum nft_payload_bases base;
  333. unsigned int offset, len;
  334. if (tb[NFTA_PAYLOAD_BASE] == NULL ||
  335. tb[NFTA_PAYLOAD_OFFSET] == NULL ||
  336. tb[NFTA_PAYLOAD_LEN] == NULL)
  337. return ERR_PTR(-EINVAL);
  338. base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
  339. switch (base) {
  340. case NFT_PAYLOAD_LL_HEADER:
  341. case NFT_PAYLOAD_NETWORK_HEADER:
  342. case NFT_PAYLOAD_TRANSPORT_HEADER:
  343. break;
  344. default:
  345. return ERR_PTR(-EOPNOTSUPP);
  346. }
  347. if (tb[NFTA_PAYLOAD_SREG] != NULL) {
  348. if (tb[NFTA_PAYLOAD_DREG] != NULL)
  349. return ERR_PTR(-EINVAL);
  350. return &nft_payload_set_ops;
  351. }
  352. if (tb[NFTA_PAYLOAD_DREG] == NULL)
  353. return ERR_PTR(-EINVAL);
  354. offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
  355. len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
  356. if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
  357. base != NFT_PAYLOAD_LL_HEADER)
  358. return &nft_payload_fast_ops;
  359. else
  360. return &nft_payload_ops;
  361. }
  362. struct nft_expr_type nft_payload_type __read_mostly = {
  363. .name = "payload",
  364. .select_ops = nft_payload_select_ops,
  365. .policy = nft_payload_policy,
  366. .maxattr = NFTA_PAYLOAD_MAX,
  367. .owner = THIS_MODULE,
  368. };