linux/net/netfilter/nf_nat_proto_tcp.c
<<
>>
Prefs
   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
   9#include <linux/types.h>
  10#include <linux/init.h>
  11#include <linux/export.h>
  12#include <linux/tcp.h>
  13
  14#include <linux/netfilter.h>
  15#include <linux/netfilter/nfnetlink_conntrack.h>
  16#include <net/netfilter/nf_nat.h>
  17#include <net/netfilter/nf_nat_l3proto.h>
  18#include <net/netfilter/nf_nat_l4proto.h>
  19#include <net/netfilter/nf_nat_core.h>
  20
  21static u16 tcp_port_rover;
  22
  23static void
  24tcp_unique_tuple(const struct nf_nat_l3proto *l3proto,
  25                 struct nf_conntrack_tuple *tuple,
  26                 const struct nf_nat_range *range,
  27                 enum nf_nat_manip_type maniptype,
  28                 const struct nf_conn *ct)
  29{
  30        nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct,
  31                                    &tcp_port_rover);
  32}
  33
  34static bool
  35tcp_manip_pkt(struct sk_buff *skb,
  36              const struct nf_nat_l3proto *l3proto,
  37              unsigned int iphdroff, unsigned int hdroff,
  38              const struct nf_conntrack_tuple *tuple,
  39              enum nf_nat_manip_type maniptype)
  40{
  41        struct tcphdr *hdr;
  42        __be16 *portptr, newport, oldport;
  43        int hdrsize = 8; /* TCP connection tracking guarantees this much */
  44
  45        /* this could be a inner header returned in icmp packet; in such
  46           cases we cannot update the checksum field since it is outside of
  47           the 8 bytes of transport layer headers we are guaranteed */
  48        if (skb->len >= hdroff + sizeof(struct tcphdr))
  49                hdrsize = sizeof(struct tcphdr);
  50
  51        if (!skb_make_writable(skb, hdroff + hdrsize))
  52                return false;
  53
  54        hdr = (struct tcphdr *)(skb->data + hdroff);
  55
  56        if (maniptype == NF_NAT_MANIP_SRC) {
  57                /* Get rid of src port */
  58                newport = tuple->src.u.tcp.port;
  59                portptr = &hdr->source;
  60        } else {
  61                /* Get rid of dst port */
  62                newport = tuple->dst.u.tcp.port;
  63                portptr = &hdr->dest;
  64        }
  65
  66        oldport = *portptr;
  67        *portptr = newport;
  68
  69        if (hdrsize < sizeof(*hdr))
  70                return true;
  71
  72        l3proto->csum_update(skb, iphdroff, &hdr->check, tuple, maniptype);
  73        inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, false);
  74        return true;
  75}
  76
  77const struct nf_nat_l4proto nf_nat_l4proto_tcp = {
  78        .l4proto                = IPPROTO_TCP,
  79        .manip_pkt              = tcp_manip_pkt,
  80        .in_range               = nf_nat_l4proto_in_range,
  81        .unique_tuple           = tcp_unique_tuple,
  82#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  83        .nlattr_to_range        = nf_nat_l4proto_nlattr_to_range,
  84#endif
  85};
  86