nf_nat_proto_tcp.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /* (C) 1999-2001 Paul `Rusty' Russell
  2. * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. */
  8. #include <linux/types.h>
  9. #include <linux/init.h>
  10. #include <linux/export.h>
  11. #include <linux/tcp.h>
  12. #include <linux/netfilter.h>
  13. #include <linux/netfilter/nfnetlink_conntrack.h>
  14. #include <net/netfilter/nf_nat.h>
  15. #include <net/netfilter/nf_nat_l3proto.h>
  16. #include <net/netfilter/nf_nat_l4proto.h>
  17. #include <net/netfilter/nf_nat_core.h>
  18. static u16 tcp_port_rover;
  19. static void
  20. tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
  21. struct nf_conntrack_tuple *tuple,
  22. const struct nf_nat_range *range,
  23. enum nf_nat_manip_type maniptype,
  24. const struct nf_conn *ct)
  25. {
  26. nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
  27. &tcp_port_rover);
  28. }
  29. static bool
  30. tcp_manip_pkt(struct sk_buff *skb,
  31. const struct nf_nat_l3proto *l3proto,
  32. unsigned int iphdroff, unsigned int hdroff,
  33. const struct nf_conntrack_tuple *tuple,
  34. enum nf_nat_manip_type maniptype)
  35. {
  36. struct tcphdr *hdr;
  37. __be16 *portptr, newport, oldport;
  38. int hdrsize = 8; /* TCP connection tracking guarantees this much */
  39. /* this could be a inner header returned in icmp packet; in such
  40. cases we cannot update the checksum field since it is outside of
  41. the 8 bytes of transport layer headers we are guaranteed */
  42. if (skb->len >= hdroff + sizeof(struct tcphdr))
  43. hdrsize = sizeof(struct tcphdr);
  44. if (!skb_make_writable(skb, hdroff + hdrsize))
  45. return false;
  46. hdr = (struct tcphdr *)(skb->data + hdroff);
  47. if (maniptype == NF_NAT_MANIP_SRC) {
  48. /* Get rid of src port */
  49. newport = tuple->src.u.tcp.port;
  50. portptr = &hdr->source;
  51. } else {
  52. /* Get rid of dst port */
  53. newport = tuple->dst.u.tcp.port;
  54. portptr = &hdr->dest;
  55. }
  56. oldport = *portptr;
  57. *portptr = newport;
  58. if (hdrsize < sizeof(*hdr))
  59. return true;
  60. l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
  61. inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, false);
  62. return true;
  63. }
  64. const struct nf_nat_l4proto nf_nat_l4proto_tcp = {
  65. .l4proto = IPPROTO_TCP,
  66. .manip_pkt = tcp_manip_pkt,
  67. .in_range = nf_nat_l4proto_in_range,
  68. .unique_tuple = tcp_unique_tuple,
  69. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  70. .nlattr_to_range = nf_nat_l4proto_nlattr_to_range,
  71. #endif
  72. };