root/net/netfilter/nf_conntrack_proto_icmpv6.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. icmpv6_pkt_to_tuple
  2. nf_conntrack_invert_icmpv6_tuple
  3. icmpv6_get_timeouts
  4. nf_conntrack_icmpv6_packet
  5. icmpv6_error_log
  6. nf_conntrack_icmpv6_error
  7. icmpv6_tuple_to_nlattr
  8. icmpv6_nlattr_to_tuple
  9. icmpv6_nlattr_tuple_size
  10. icmpv6_timeout_nlattr_to_obj
  11. icmpv6_timeout_obj_to_nlattr
  12. nf_conntrack_icmpv6_init_net

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C)2003,2004 USAGI/WIDE Project
   4  *
   5  * Author:
   6  *      Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
   7  */
   8 
   9 #include <linux/types.h>
  10 #include <linux/timer.h>
  11 #include <linux/module.h>
  12 #include <linux/netfilter.h>
  13 #include <linux/in6.h>
  14 #include <linux/icmpv6.h>
  15 #include <linux/ipv6.h>
  16 #include <net/ipv6.h>
  17 #include <net/ip6_checksum.h>
  18 #include <linux/seq_file.h>
  19 #include <linux/netfilter_ipv6.h>
  20 #include <net/netfilter/nf_conntrack_tuple.h>
  21 #include <net/netfilter/nf_conntrack_l4proto.h>
  22 #include <net/netfilter/nf_conntrack_core.h>
  23 #include <net/netfilter/nf_conntrack_timeout.h>
  24 #include <net/netfilter/nf_conntrack_zones.h>
  25 #include <net/netfilter/nf_log.h>
  26 
  27 static const unsigned int nf_ct_icmpv6_timeout = 30*HZ;
  28 
  29 bool icmpv6_pkt_to_tuple(const struct sk_buff *skb,
  30                          unsigned int dataoff,
  31                          struct net *net,
  32                          struct nf_conntrack_tuple *tuple)
  33 {
  34         const struct icmp6hdr *hp;
  35         struct icmp6hdr _hdr;
  36 
  37         hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  38         if (hp == NULL)
  39                 return false;
  40         tuple->dst.u.icmp.type = hp->icmp6_type;
  41         tuple->src.u.icmp.id = hp->icmp6_identifier;
  42         tuple->dst.u.icmp.code = hp->icmp6_code;
  43 
  44         return true;
  45 }
  46 
  47 /* Add 1; spaces filled with 0. */
  48 static const u_int8_t invmap[] = {
  49         [ICMPV6_ECHO_REQUEST - 128]     = ICMPV6_ECHO_REPLY + 1,
  50         [ICMPV6_ECHO_REPLY - 128]       = ICMPV6_ECHO_REQUEST + 1,
  51         [ICMPV6_NI_QUERY - 128]         = ICMPV6_NI_REPLY + 1,
  52         [ICMPV6_NI_REPLY - 128]         = ICMPV6_NI_QUERY + 1
  53 };
  54 
  55 static const u_int8_t noct_valid_new[] = {
  56         [ICMPV6_MGM_QUERY - 130] = 1,
  57         [ICMPV6_MGM_REPORT - 130] = 1,
  58         [ICMPV6_MGM_REDUCTION - 130] = 1,
  59         [NDISC_ROUTER_SOLICITATION - 130] = 1,
  60         [NDISC_ROUTER_ADVERTISEMENT - 130] = 1,
  61         [NDISC_NEIGHBOUR_SOLICITATION - 130] = 1,
  62         [NDISC_NEIGHBOUR_ADVERTISEMENT - 130] = 1,
  63         [ICMPV6_MLD2_REPORT - 130] = 1
  64 };
  65 
  66 bool nf_conntrack_invert_icmpv6_tuple(struct nf_conntrack_tuple *tuple,
  67                                       const struct nf_conntrack_tuple *orig)
  68 {
  69         int type = orig->dst.u.icmp.type - 128;
  70         if (type < 0 || type >= sizeof(invmap) || !invmap[type])
  71                 return false;
  72 
  73         tuple->src.u.icmp.id   = orig->src.u.icmp.id;
  74         tuple->dst.u.icmp.type = invmap[type] - 1;
  75         tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
  76         return true;
  77 }
  78 
  79 static unsigned int *icmpv6_get_timeouts(struct net *net)
  80 {
  81         return &nf_icmpv6_pernet(net)->timeout;
  82 }
  83 
  84 /* Returns verdict for packet, or -1 for invalid. */
  85 int nf_conntrack_icmpv6_packet(struct nf_conn *ct,
  86                                struct sk_buff *skb,
  87                                enum ip_conntrack_info ctinfo,
  88                                const struct nf_hook_state *state)
  89 {
  90         unsigned int *timeout = nf_ct_timeout_lookup(ct);
  91         static const u8 valid_new[] = {
  92                 [ICMPV6_ECHO_REQUEST - 128] = 1,
  93                 [ICMPV6_NI_QUERY - 128] = 1
  94         };
  95 
  96         if (state->pf != NFPROTO_IPV6)
  97                 return -NF_ACCEPT;
  98 
  99         if (!nf_ct_is_confirmed(ct)) {
 100                 int type = ct->tuplehash[0].tuple.dst.u.icmp.type - 128;
 101 
 102                 if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
 103                         /* Can't create a new ICMPv6 `conn' with this. */
 104                         pr_debug("icmpv6: can't create new conn with type %u\n",
 105                                  type + 128);
 106                         nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple);
 107                         return -NF_ACCEPT;
 108                 }
 109         }
 110 
 111         if (!timeout)
 112                 timeout = icmpv6_get_timeouts(nf_ct_net(ct));
 113 
 114         /* Do not immediately delete the connection after the first
 115            successful reply to avoid excessive conntrackd traffic
 116            and also to handle correctly ICMP echo reply duplicates. */
 117         nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
 118 
 119         return NF_ACCEPT;
 120 }
 121 
 122 
 123 static void icmpv6_error_log(const struct sk_buff *skb,
 124                              const struct nf_hook_state *state,
 125                              const char *msg)
 126 {
 127         nf_l4proto_log_invalid(skb, state->net, state->pf,
 128                                IPPROTO_ICMPV6, "%s", msg);
 129 }
 130 
 131 int nf_conntrack_icmpv6_error(struct nf_conn *tmpl,
 132                               struct sk_buff *skb,
 133                               unsigned int dataoff,
 134                               const struct nf_hook_state *state)
 135 {
 136         union nf_inet_addr outer_daddr;
 137         const struct icmp6hdr *icmp6h;
 138         struct icmp6hdr _ih;
 139         int type;
 140 
 141         icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
 142         if (icmp6h == NULL) {
 143                 icmpv6_error_log(skb, state, "short packet");
 144                 return -NF_ACCEPT;
 145         }
 146 
 147         if (state->hook == NF_INET_PRE_ROUTING &&
 148             state->net->ct.sysctl_checksum &&
 149             nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) {
 150                 icmpv6_error_log(skb, state, "ICMPv6 checksum failed");
 151                 return -NF_ACCEPT;
 152         }
 153 
 154         type = icmp6h->icmp6_type - 130;
 155         if (type >= 0 && type < sizeof(noct_valid_new) &&
 156             noct_valid_new[type]) {
 157                 nf_ct_set(skb, NULL, IP_CT_UNTRACKED);
 158                 return NF_ACCEPT;
 159         }
 160 
 161         /* is not error message ? */
 162         if (icmp6h->icmp6_type >= 128)
 163                 return NF_ACCEPT;
 164 
 165         memcpy(&outer_daddr.ip6, &ipv6_hdr(skb)->daddr,
 166                sizeof(outer_daddr.ip6));
 167         dataoff += sizeof(*icmp6h);
 168         return nf_conntrack_inet_error(tmpl, skb, dataoff, state,
 169                                        IPPROTO_ICMPV6, &outer_daddr);
 170 }
 171 
 172 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 173 
 174 #include <linux/netfilter/nfnetlink.h>
 175 #include <linux/netfilter/nfnetlink_conntrack.h>
 176 static int icmpv6_tuple_to_nlattr(struct sk_buff *skb,
 177                                   const struct nf_conntrack_tuple *t)
 178 {
 179         if (nla_put_be16(skb, CTA_PROTO_ICMPV6_ID, t->src.u.icmp.id) ||
 180             nla_put_u8(skb, CTA_PROTO_ICMPV6_TYPE, t->dst.u.icmp.type) ||
 181             nla_put_u8(skb, CTA_PROTO_ICMPV6_CODE, t->dst.u.icmp.code))
 182                 goto nla_put_failure;
 183         return 0;
 184 
 185 nla_put_failure:
 186         return -1;
 187 }
 188 
 189 static const struct nla_policy icmpv6_nla_policy[CTA_PROTO_MAX+1] = {
 190         [CTA_PROTO_ICMPV6_TYPE] = { .type = NLA_U8 },
 191         [CTA_PROTO_ICMPV6_CODE] = { .type = NLA_U8 },
 192         [CTA_PROTO_ICMPV6_ID]   = { .type = NLA_U16 },
 193 };
 194 
 195 static int icmpv6_nlattr_to_tuple(struct nlattr *tb[],
 196                                 struct nf_conntrack_tuple *tuple)
 197 {
 198         if (!tb[CTA_PROTO_ICMPV6_TYPE] ||
 199             !tb[CTA_PROTO_ICMPV6_CODE] ||
 200             !tb[CTA_PROTO_ICMPV6_ID])
 201                 return -EINVAL;
 202 
 203         tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMPV6_TYPE]);
 204         tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMPV6_CODE]);
 205         tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMPV6_ID]);
 206 
 207         if (tuple->dst.u.icmp.type < 128 ||
 208             tuple->dst.u.icmp.type - 128 >= sizeof(invmap) ||
 209             !invmap[tuple->dst.u.icmp.type - 128])
 210                 return -EINVAL;
 211 
 212         return 0;
 213 }
 214 
 215 static unsigned int icmpv6_nlattr_tuple_size(void)
 216 {
 217         static unsigned int size __read_mostly;
 218 
 219         if (!size)
 220                 size = nla_policy_len(icmpv6_nla_policy, CTA_PROTO_MAX + 1);
 221 
 222         return size;
 223 }
 224 #endif
 225 
 226 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
 227 
 228 #include <linux/netfilter/nfnetlink.h>
 229 #include <linux/netfilter/nfnetlink_cttimeout.h>
 230 
 231 static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[],
 232                                         struct net *net, void *data)
 233 {
 234         unsigned int *timeout = data;
 235         struct nf_icmp_net *in = nf_icmpv6_pernet(net);
 236 
 237         if (!timeout)
 238                 timeout = icmpv6_get_timeouts(net);
 239         if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) {
 240                 *timeout =
 241                     ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ;
 242         } else {
 243                 /* Set default ICMPv6 timeout. */
 244                 *timeout = in->timeout;
 245         }
 246         return 0;
 247 }
 248 
 249 static int
 250 icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 251 {
 252         const unsigned int *timeout = data;
 253 
 254         if (nla_put_be32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ)))
 255                 goto nla_put_failure;
 256         return 0;
 257 
 258 nla_put_failure:
 259         return -ENOSPC;
 260 }
 261 
 262 static const struct nla_policy
 263 icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = {
 264         [CTA_TIMEOUT_ICMPV6_TIMEOUT]    = { .type = NLA_U32 },
 265 };
 266 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
 267 
 268 void nf_conntrack_icmpv6_init_net(struct net *net)
 269 {
 270         struct nf_icmp_net *in = nf_icmpv6_pernet(net);
 271 
 272         in->timeout = nf_ct_icmpv6_timeout;
 273 }
 274 
 275 const struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 =
 276 {
 277         .l4proto                = IPPROTO_ICMPV6,
 278 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 279         .tuple_to_nlattr        = icmpv6_tuple_to_nlattr,
 280         .nlattr_tuple_size      = icmpv6_nlattr_tuple_size,
 281         .nlattr_to_tuple        = icmpv6_nlattr_to_tuple,
 282         .nla_policy             = icmpv6_nla_policy,
 283 #endif
 284 #ifdef CONFIG_NF_CONNTRACK_TIMEOUT
 285         .ctnl_timeout           = {
 286                 .nlattr_to_obj  = icmpv6_timeout_nlattr_to_obj,
 287                 .obj_to_nlattr  = icmpv6_timeout_obj_to_nlattr,
 288                 .nlattr_max     = CTA_TIMEOUT_ICMP_MAX,
 289                 .obj_size       = sizeof(unsigned int),
 290                 .nla_policy     = icmpv6_timeout_nla_policy,
 291         },
 292 #endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
 293 };

/* [<][>][^][v][top][bottom][index][help] */