linux/net/ipv6/netfilter/nf_nat_proto_icmpv6.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 Patrick Mchardy <kaber@trash.net>
   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 * Based on Rusty Russell's IPv4 ICMP NAT code. Development of IPv6
   9 * NAT funded by Astaro.
  10 */
  11
  12#include <linux/types.h>
  13#include <linux/init.h>
  14#include <linux/icmpv6.h>
  15
  16#include <linux/netfilter.h>
  17#include <net/netfilter/nf_nat.h>
  18#include <net/netfilter/nf_nat_core.h>
  19#include <net/netfilter/nf_nat_l3proto.h>
  20#include <net/netfilter/nf_nat_l4proto.h>
  21
  22static bool
  23icmpv6_in_range(const struct nf_conntrack_tuple *tuple,
  24                enum nf_nat_manip_type maniptype,
  25                const union nf_conntrack_man_proto *min,
  26                const union nf_conntrack_man_proto *max)
  27{
  28        return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
  29               ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
  30}
  31
  32static void
  33icmpv6_unique_tuple(const struct nf_nat_l3proto *l3proto,
  34                    struct nf_conntrack_tuple *tuple,
  35                    const struct nf_nat_range *range,
  36                    enum nf_nat_manip_type maniptype,
  37                    const struct nf_conn *ct)
  38{
  39        static u16 id;
  40        unsigned int range_size;
  41        unsigned int i;
  42
  43        range_size = ntohs(range->max_proto.icmp.id) -
  44                     ntohs(range->min_proto.icmp.id) + 1;
  45
  46        if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED))
  47                range_size = 0xffff;
  48
  49        for (i = 0; ; ++id) {
  50                tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) +
  51                                             (id % range_size));
  52                if (++i == range_size || !nf_nat_used_tuple(tuple, ct))
  53                        return;
  54        }
  55}
  56
  57static bool
  58icmpv6_manip_pkt(struct sk_buff *skb,
  59                 const struct nf_nat_l3proto *l3proto,
  60                 unsigned int iphdroff, unsigned int hdroff,
  61                 const struct nf_conntrack_tuple *tuple,
  62                 enum nf_nat_manip_type maniptype)
  63{
  64        struct icmp6hdr *hdr;
  65
  66        if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
  67                return false;
  68
  69        hdr = (struct icmp6hdr *)(skb->data + hdroff);
  70        l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum,
  71                             tuple, maniptype);
  72        if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
  73            hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
  74                inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
  75                                         hdr->icmp6_identifier,
  76                                         tuple->src.u.icmp.id, 0);
  77                hdr->icmp6_identifier = tuple->src.u.icmp.id;
  78        }
  79        return true;
  80}
  81
  82const struct nf_nat_l4proto nf_nat_l4proto_icmpv6 = {
  83        .l4proto                = IPPROTO_ICMPV6,
  84        .manip_pkt              = icmpv6_manip_pkt,
  85        .in_range               = icmpv6_in_range,
  86        .unique_tuple           = icmpv6_unique_tuple,
  87#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  88        .nlattr_to_range        = nf_nat_l4proto_nlattr_to_range,
  89#endif
  90};
  91