linux/net/netfilter/nf_nat_proto_dccp.c
<<
>>
Prefs
   1/*
   2 * DCCP NAT protocol helper
   3 *
   4 * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/skbuff.h>
  14#include <linux/dccp.h>
  15
  16#include <net/netfilter/nf_conntrack.h>
  17#include <net/netfilter/nf_nat.h>
  18#include <net/netfilter/nf_nat_l3proto.h>
  19#include <net/netfilter/nf_nat_l4proto.h>
  20
  21static u_int16_t dccp_port_rover;
  22
  23static void
  24dccp_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                                    &dccp_port_rover);
  32}
  33
  34static bool
  35dccp_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 dccp_hdr *hdr;
  42        __be16 *portptr, oldport, newport;
  43        int hdrsize = 8; /* DCCP connection tracking guarantees this much */
  44
  45        if (skb->len >= hdroff + sizeof(struct dccp_hdr))
  46                hdrsize = sizeof(struct dccp_hdr);
  47
  48        if (!skb_make_writable(skb, hdroff + hdrsize))
  49                return false;
  50
  51        hdr = (struct dccp_hdr *)(skb->data + hdroff);
  52
  53        if (maniptype == NF_NAT_MANIP_SRC) {
  54                newport = tuple->src.u.dccp.port;
  55                portptr = &hdr->dccph_sport;
  56        } else {
  57                newport = tuple->dst.u.dccp.port;
  58                portptr = &hdr->dccph_dport;
  59        }
  60
  61        oldport = *portptr;
  62        *portptr = newport;
  63
  64        if (hdrsize < sizeof(*hdr))
  65                return true;
  66
  67        l3proto->csum_update(skb, iphdroff, &hdr->dccph_checksum,
  68                             tuple, maniptype);
  69        inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport,
  70                                 false);
  71        return true;
  72}
  73
  74const struct nf_nat_l4proto nf_nat_l4proto_dccp = {
  75        .l4proto                = IPPROTO_DCCP,
  76        .manip_pkt              = dccp_manip_pkt,
  77        .in_range               = nf_nat_l4proto_in_range,
  78        .unique_tuple           = dccp_unique_tuple,
  79#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  80        .nlattr_to_range        = nf_nat_l4proto_nlattr_to_range,
  81#endif
  82};
  83