diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h index 6617e1ca7d00..30482c6985cf 100644 --- a/sys/netinet/ip6.h +++ b/sys/netinet/ip6.h @@ -1,264 +1,264 @@ /* $FreeBSD$ */ /* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 */ #ifndef _NETINET_IP6_H_ #define _NETINET_IP6_H_ /* * Definition for internet protocol version 6. * RFC 2460 */ struct ip6_hdr { union { struct ip6_hdrctl { u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */ u_int16_t ip6_un1_plen; /* payload length */ u_int8_t ip6_un1_nxt; /* next header */ u_int8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ } __packed; #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim #define IPV6_VERSION 0x60 #define IPV6_VERSION_MASK 0xf0 #if BYTE_ORDER == BIG_ENDIAN #define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */ #define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */ #else #if BYTE_ORDER == LITTLE_ENDIAN #define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */ #define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */ #endif /* LITTLE_ENDIAN */ #endif #define IPV6_FLOWLABEL_LEN 20 #define IPV6_TRAFFIC_CLASS(ip6) ((ntohl((ip6)->ip6_flow) >> IPV6_FLOWLABEL_LEN) & 0xff) #define IPV6_DSCP(ip6) ((ntohl((ip6)->ip6_flow) >> IPV6_FLOWLABEL_LEN) & 0xfc) #define IPV6_ECN(ip6) ((ntohl((ip6)->ip6_flow) >> IPV6_FLOWLABEL_LEN) & 0x03) /* * Extension Headers */ struct ip6_ext { u_int8_t ip6e_nxt; u_int8_t ip6e_len; } __packed; /* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_hbh { u_int8_t ip6h_nxt; /* next header */ u_int8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ } __packed; /* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_dest { u_int8_t ip6d_nxt; /* next header */ u_int8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ } __packed; /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ #define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */ #define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */ #ifndef _KERNEL #define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */ #endif #define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 (RFC3542, recommended) */ #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 #define IP6OPT_EID 0x8a /* 10 0 01010 */ #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 #define IP6OPT_TYPE_DISCARD 0x40 #define IP6OPT_TYPE_FORCEICMP 0x80 #define IP6OPT_TYPE_ICMP 0xC0 #define IP6OPT_MUTABLE 0x20 /* IPv6 options: common part */ struct ip6_opt { u_int8_t ip6o_type; u_int8_t ip6o_len; } __packed; /* Jumbo Payload Option */ struct ip6_opt_jumbo { u_int8_t ip6oj_type; u_int8_t ip6oj_len; u_int8_t ip6oj_jumbo_len[4]; } __packed; #define IP6OPT_JUMBO_LEN 6 /* NSAP Address Option */ struct ip6_opt_nsap { u_int8_t ip6on_type; u_int8_t ip6on_len; u_int8_t ip6on_src_nsap_len; u_int8_t ip6on_dst_nsap_len; /* followed by source NSAP */ /* followed by destination NSAP */ } __packed; /* Tunnel Limit Option */ struct ip6_opt_tunnel { u_int8_t ip6ot_type; u_int8_t ip6ot_len; u_int8_t ip6ot_encap_limit; } __packed; /* Router Alert Option */ struct ip6_opt_router { u_int8_t ip6or_type; u_int8_t ip6or_len; u_int8_t ip6or_value[2]; } __packed; /* Router alert values (in network byte order) */ #if BYTE_ORDER == BIG_ENDIAN #define IP6_ALERT_MLD 0x0000 #define IP6_ALERT_RSVP 0x0001 #define IP6_ALERT_AN 0x0002 #else #if BYTE_ORDER == LITTLE_ENDIAN #define IP6_ALERT_MLD 0x0000 #define IP6_ALERT_RSVP 0x0100 #define IP6_ALERT_AN 0x0200 #endif /* LITTLE_ENDIAN */ #endif /* Routing header */ struct ip6_rthdr { u_int8_t ip6r_nxt; /* next header */ u_int8_t ip6r_len; /* length in units of 8 octets */ u_int8_t ip6r_type; /* routing type */ u_int8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ } __packed; /* Type 0 Routing header, deprecated by RFC 5095. */ struct ip6_rthdr0 { u_int8_t ip6r0_nxt; /* next header */ u_int8_t ip6r0_len; /* length in units of 8 octets */ u_int8_t ip6r0_type; /* always zero */ u_int8_t ip6r0_segleft; /* segments left */ u_int32_t ip6r0_reserved; /* reserved field */ /* followed by up to 127 struct in6_addr */ } __packed; /* Fragment header */ struct ip6_frag { u_int8_t ip6f_nxt; /* next header */ u_int8_t ip6f_reserved; /* reserved field */ u_int16_t ip6f_offlg; /* offset, reserved, and flag */ u_int32_t ip6f_ident; /* identification */ } __packed; #if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */ #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ /* * Internet implementation parameters. */ #define IPV6_MAXHLIM 255 /* maximum hoplimit */ #define IPV6_DEFHLIM 64 /* default hlim */ -#define IPV6_FRAGTTL 120 /* ttl for fragment packets, in slowtimo tick */ +#define IPV6_DEFFRAGTTL 60000 /* Default fragment packets lifetime, in milliseconds */ #define IPV6_HLIMDEC 1 /* subtracted when forwarding */ #define IPV6_MMTU 1280 /* minimal MTU and reassembly. 1024 + 256 */ #define IPV6_MAXPACKET 65535 /* ip6 max packet size without Jumbo payload*/ #define IPV6_MAXOPTHDR 2048 /* max option header size, 256 64-bit words */ #endif /* not _NETINET_IP6_H_ */ diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c index d634f869acd5..5acdc1b20981 100644 --- a/sys/netinet6/frag6.c +++ b/sys/netinet6/frag6.c @@ -1,1068 +1,1122 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * Copyright (c) 2019 Netflix, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $KAME: frag6.c,v 1.33 2002/01/07 11:34:48 kjc Exp $ */ #include __FBSDID("$FreeBSD$"); #include "opt_rss.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For ECN definitions. */ #include /* For ECN definitions. */ #ifdef MAC #include #endif /* * A "big picture" of how IPv6 fragment queues are all linked together. * * struct ip6qbucket ip6qb[...]; hashed buckets * |||||||| * | * +--- TAILQ(struct ip6q, packets) *q6; tailq entries holding * |||||||| fragmented packets * | (1 per original packet) * | * +--- TAILQ(struct ip6asfrag, ip6q_frags) *af6; tailq entries of IPv6 * | *ip6af;fragment packets * | for one original packet * + *mbuf */ /* Reassembly headers are stored in hash buckets. */ #define IP6REASS_NHASH_LOG2 10 #define IP6REASS_NHASH (1 << IP6REASS_NHASH_LOG2) #define IP6REASS_HMASK (IP6REASS_NHASH - 1) TAILQ_HEAD(ip6qhead, ip6q); struct ip6qbucket { struct ip6qhead packets; struct mtx lock; int count; }; struct ip6asfrag { TAILQ_ENTRY(ip6asfrag) ip6af_tq; struct mbuf *ip6af_m; int ip6af_offset; /* Offset in ip6af_m to next header. */ int ip6af_frglen; /* Fragmentable part length. */ int ip6af_off; /* Fragment offset. */ bool ip6af_mff; /* More fragment bit in frag off. */ }; static MALLOC_DEFINE(M_FRAG6, "frag6", "IPv6 fragment reassembly header"); #ifdef VIMAGE /* A flag to indicate if IPv6 fragmentation is initialized. */ VNET_DEFINE_STATIC(bool, frag6_on); #define V_frag6_on VNET(frag6_on) #endif /* System wide (global) maximum and count of packets in reassembly queues. */ static int ip6_maxfrags; static u_int __exclusive_cache_line frag6_nfrags; /* Maximum and current packets in per-VNET reassembly queue. */ VNET_DEFINE_STATIC(int, ip6_maxfragpackets); VNET_DEFINE_STATIC(volatile u_int, frag6_nfragpackets); #define V_ip6_maxfragpackets VNET(ip6_maxfragpackets) #define V_frag6_nfragpackets VNET(frag6_nfragpackets) +/* Maximum per-VNET reassembly timeout (milliseconds) */ +VNET_DEFINE_STATIC(u_int, ip6_fraglifetime) = IPV6_DEFFRAGTTL; +#define V_ip6_fraglifetime VNET(ip6_fraglifetime) + /* Maximum per-VNET reassembly queues per bucket and fragments per packet. */ VNET_DEFINE_STATIC(int, ip6_maxfragbucketsize); VNET_DEFINE_STATIC(int, ip6_maxfragsperpacket); #define V_ip6_maxfragbucketsize VNET(ip6_maxfragbucketsize) #define V_ip6_maxfragsperpacket VNET(ip6_maxfragsperpacket) /* Per-VNET reassembly queue buckets. */ VNET_DEFINE_STATIC(struct ip6qbucket, ip6qb[IP6REASS_NHASH]); VNET_DEFINE_STATIC(uint32_t, ip6qb_hashseed); #define V_ip6qb VNET(ip6qb) #define V_ip6qb_hashseed VNET(ip6qb_hashseed) #define IP6QB_LOCK(_b) mtx_lock(&V_ip6qb[(_b)].lock) #define IP6QB_TRYLOCK(_b) mtx_trylock(&V_ip6qb[(_b)].lock) #define IP6QB_LOCK_ASSERT(_b) mtx_assert(&V_ip6qb[(_b)].lock, MA_OWNED) #define IP6QB_UNLOCK(_b) mtx_unlock(&V_ip6qb[(_b)].lock) #define IP6QB_HEAD(_b) (&V_ip6qb[(_b)].packets) /* * By default, limit the number of IP6 fragments across all reassembly * queues to 1/32 of the total number of mbuf clusters. * * Limit the total number of reassembly queues per VNET to the * IP6 fragment limit, but ensure the limit will not allow any bucket * to grow above 100 items. (The bucket limit is * IP_MAXFRAGPACKETS / (IPREASS_NHASH / 2), so the 50 is the correct * multiplier to reach a 100-item limit.) * The 100-item limit was chosen as brief testing seems to show that * this produces "reasonable" performance on some subset of systems * under DoS attack. */ #define IP6_MAXFRAGS (nmbclusters / 32) #define IP6_MAXFRAGPACKETS (imin(IP6_MAXFRAGS, IP6REASS_NHASH * 50)) +/* Interval between periodic reassembly queue inspections */ +#define IP6_CALLOUT_INTERVAL_MS 500 + /* * Sysctls and helper function. */ SYSCTL_DECL(_net_inet6_ip6); SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, frag6_nfrags, CTLFLAG_RD, &frag6_nfrags, 0, "Global number of IPv6 fragments across all reassembly queues."); static void frag6_set_bucketsize(void) { int i; if ((i = V_ip6_maxfragpackets) > 0) V_ip6_maxfragbucketsize = imax(i / (IP6REASS_NHASH / 2), 1); } SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGS, maxfrags, CTLFLAG_RW, &ip6_maxfrags, 0, "Maximum allowed number of outstanding IPv6 packet fragments. " "A value of 0 means no fragmented packets will be accepted, while " "a value of -1 means no limit"); static int sysctl_ip6_maxfragpackets(SYSCTL_HANDLER_ARGS) { int error, val; val = V_ip6_maxfragpackets; error = sysctl_handle_int(oidp, &val, 0, req); if (error != 0 || !req->newptr) return (error); V_ip6_maxfragpackets = val; frag6_set_bucketsize(); return (0); } SYSCTL_PROC(_net_inet6_ip6, IPV6CTL_MAXFRAGPACKETS, maxfragpackets, CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0, sysctl_ip6_maxfragpackets, "I", "Default maximum number of outstanding fragmented IPv6 packets. " "A value of 0 means no fragmented packets will be accepted, while a " "a value of -1 means no limit"); SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, frag6_nfragpackets, CTLFLAG_VNET | CTLFLAG_RD, __DEVOLATILE(u_int *, &VNET_NAME(frag6_nfragpackets)), 0, "Per-VNET number of IPv6 fragments across all reassembly queues."); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGSPERPACKET, maxfragsperpacket, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_maxfragsperpacket), 0, "Maximum allowed number of fragments per packet"); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGBUCKETSIZE, maxfragbucketsize, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_maxfragbucketsize), 0, "Maximum number of reassembly queues per hash bucket"); +static int +frag6_milli_to_callout_ticks(int ms) +{ + return (ms / IP6_CALLOUT_INTERVAL_MS); +} + +static int +frag6_callout_ticks_to_milli(int ms) +{ + return (ms * IP6_CALLOUT_INTERVAL_MS); +} + +_Static_assert(sizeof(((struct ip6q *)NULL)->ip6q_ttl) >= 2, + "ip6q_ttl field is not large enough"); + +static int +sysctl_ip6_fraglifetime(SYSCTL_HANDLER_ARGS) +{ + int error, val; + + val = V_ip6_fraglifetime; + error = sysctl_handle_int(oidp, &val, 0, req); + if (error != 0 || !req->newptr) + return (error); + if (val <= 0) + val = IPV6_DEFFRAGTTL; + + if (frag6_milli_to_callout_ticks(val) >= 65536) + val = frag6_callout_ticks_to_milli(65535); +#ifdef VIMAGE + if (!IS_DEFAULT_VNET(curvnet)) { + CURVNET_SET(vnet0); + int host_val = V_ip6_fraglifetime; + CURVNET_RESTORE(); + + if (val > host_val) + val = host_val; + } +#endif + V_ip6_fraglifetime = val; + return (0); +} +SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, fraglifetime_ms, + CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, + NULL, 0, sysctl_ip6_fraglifetime, "I", + "Fragment lifetime, in milliseconds"); + /* * Remove the IPv6 fragmentation header from the mbuf. */ int ip6_deletefraghdr(struct mbuf *m, int offset, int wait __unused) { struct ip6_hdr *ip6; KASSERT(m->m_len >= offset + sizeof(struct ip6_frag), ("%s: ext headers not contigous in mbuf %p m_len %d >= " "offset %d + %zu\n", __func__, m, m->m_len, offset, sizeof(struct ip6_frag))); /* Delete frag6 header. */ ip6 = mtod(m, struct ip6_hdr *); bcopy(ip6, (char *)ip6 + sizeof(struct ip6_frag), offset); m->m_data += sizeof(struct ip6_frag); m->m_len -= sizeof(struct ip6_frag); m->m_flags |= M_FRAGMENTED; return (0); } /* * Free a fragment reassembly header and all associated datagrams. */ static void frag6_freef(struct ip6q *q6, uint32_t bucket) { struct ip6_hdr *ip6; struct ip6asfrag *af6; struct mbuf *m; IP6QB_LOCK_ASSERT(bucket); while ((af6 = TAILQ_FIRST(&q6->ip6q_frags)) != NULL) { m = af6->ip6af_m; TAILQ_REMOVE(&q6->ip6q_frags, af6, ip6af_tq); /* * Return ICMP time exceeded error for the 1st fragment. * Just free other fragments. */ if (af6->ip6af_off == 0 && m->m_pkthdr.rcvif != NULL) { /* Adjust pointer. */ ip6 = mtod(m, struct ip6_hdr *); /* Restore source and destination addresses. */ ip6->ip6_src = q6->ip6q_src; ip6->ip6_dst = q6->ip6q_dst; icmp6_error(m, ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY, 0); } else m_freem(m); free(af6, M_FRAG6); } TAILQ_REMOVE(IP6QB_HEAD(bucket), q6, ip6q_tq); V_ip6qb[bucket].count--; atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag); #ifdef MAC mac_ip6q_destroy(q6); #endif free(q6, M_FRAG6); atomic_subtract_int(&V_frag6_nfragpackets, 1); } /* * Drain off all datagram fragments belonging to * the given network interface. */ static void frag6_cleanup(void *arg __unused, struct ifnet *ifp) { struct ip6qhead *head; struct ip6q *q6; struct ip6asfrag *af6; uint32_t bucket; KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); CURVNET_SET_QUIET(ifp->if_vnet); #ifdef VIMAGE /* * Skip processing if IPv6 reassembly is not initialised or * torn down by frag6_destroy(). */ if (!V_frag6_on) { CURVNET_RESTORE(); return; } #endif for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { IP6QB_LOCK(bucket); head = IP6QB_HEAD(bucket); /* Scan fragment list. */ TAILQ_FOREACH(q6, head, ip6q_tq) { TAILQ_FOREACH(af6, &q6->ip6q_frags, ip6af_tq) { /* Clear no longer valid rcvif pointer. */ if (af6->ip6af_m->m_pkthdr.rcvif == ifp) af6->ip6af_m->m_pkthdr.rcvif = NULL; } } IP6QB_UNLOCK(bucket); } CURVNET_RESTORE(); } EVENTHANDLER_DEFINE(ifnet_departure_event, frag6_cleanup, NULL, 0); /* * Like in RFC2460, in RFC8200, fragment and reassembly rules do not agree with * each other, in terms of next header field handling in fragment header. * While the sender will use the same value for all of the fragmented packets, * receiver is suggested not to check for consistency. * * Fragment rules (p18,p19): * (2) A Fragment header containing: * The Next Header value that identifies the first header * after the Per-Fragment headers of the original packet. * -> next header field is same for all fragments * * Reassembly rule (p20): * The Next Header field of the last header of the Per-Fragment * headers is obtained from the Next Header field of the first * fragment's Fragment header. * -> should grab it from the first fragment only * * The following note also contradicts with fragment rule - no one is going to * send different fragment with different next header field. * * Additional note (p22) [not an error]: * The Next Header values in the Fragment headers of different * fragments of the same original packet may differ. Only the value * from the Offset zero fragment packet is used for reassembly. * -> should grab it from the first fragment only * * There is no explicit reason given in the RFC. Historical reason maybe? */ /* * Fragment input. */ int frag6_input(struct mbuf **mp, int *offp, int proto) { struct mbuf *m, *t; struct ip6_hdr *ip6; struct ip6_frag *ip6f; struct ip6qhead *head; struct ip6q *q6; struct ip6asfrag *af6, *ip6af, *af6tmp; struct in6_ifaddr *ia6; struct ifnet *dstifp, *srcifp; uint32_t hashkey[(sizeof(struct in6_addr) * 2 + sizeof(ip6f->ip6f_ident)) / sizeof(uint32_t)]; uint32_t bucket, *hashkeyp; int fragoff, frgpartlen; /* Must be larger than uint16_t. */ int nxt, offset, plen; uint8_t ecn, ecn0; bool only_frag; #ifdef RSS struct ip6_direct_ctx *ip6dc; struct m_tag *mtag; #endif m = *mp; offset = *offp; M_ASSERTPKTHDR(m); if (m->m_len < offset + sizeof(struct ip6_frag)) { m = m_pullup(m, offset + sizeof(struct ip6_frag)); if (m == NULL) { IP6STAT_INC(ip6s_exthdrtoolong); *mp = NULL; return (IPPROTO_DONE); } } ip6 = mtod(m, struct ip6_hdr *); dstifp = NULL; /* Find the destination interface of the packet. */ ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false); if (ia6 != NULL) dstifp = ia6->ia_ifp; /* Jumbo payload cannot contain a fragment header. */ if (ip6->ip6_plen == 0) { icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); in6_ifstat_inc(dstifp, ifs6_reass_fail); *mp = NULL; return (IPPROTO_DONE); } /* * Check whether fragment packet's fragment length is a * multiple of 8 octets (unless it is the last one). * sizeof(struct ip6_frag) == 8 * sizeof(struct ip6_hdr) = 40 */ ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) { icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offsetof(struct ip6_hdr, ip6_plen)); in6_ifstat_inc(dstifp, ifs6_reass_fail); *mp = NULL; return (IPPROTO_DONE); } IP6STAT_INC(ip6s_fragments); in6_ifstat_inc(dstifp, ifs6_reass_reqd); /* * Handle "atomic" fragments (offset and m bit set to 0) upfront, * unrelated to any reassembly. We need to remove the frag hdr * which is ugly. * See RFC 6946 and section 4.5 of RFC 8200. */ if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) { IP6STAT_INC(ip6s_atomicfrags); nxt = ip6f->ip6f_nxt; /* * Set nxt(-hdr field value) to the original value. * We cannot just set ip6->ip6_nxt as there might be * an unfragmentable part with extension headers and * we must update the last one. */ m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t), (caddr_t)&nxt); ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - sizeof(struct ip6_frag)); if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) goto dropfrag2; m->m_pkthdr.len -= sizeof(struct ip6_frag); in6_ifstat_inc(dstifp, ifs6_reass_ok); *mp = m; return (nxt); } /* Offset now points to data portion. */ offset += sizeof(struct ip6_frag); /* Get fragment length and discard 0-byte fragments. */ frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset; if (frgpartlen == 0) { icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offsetof(struct ip6_hdr, ip6_plen)); in6_ifstat_inc(dstifp, ifs6_reass_fail); IP6STAT_INC(ip6s_fragdropped); *mp = NULL; return (IPPROTO_DONE); } /* * Enforce upper bound on number of fragments for the entire system. * If maxfrag is 0, never accept fragments. * If maxfrag is -1, accept all fragments without limitation. */ if (ip6_maxfrags < 0) ; else if (atomic_load_int(&frag6_nfrags) >= (u_int)ip6_maxfrags) goto dropfrag2; /* * Validate that a full header chain to the ULP is present in the * packet containing the first fragment as per RFC RFC7112 and * RFC 8200 pages 18,19: * The first fragment packet is composed of: * (3) Extension headers, if any, and the Upper-Layer header. These * headers must be in the first fragment. ... */ fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); /* XXX TODO. thj has D16851 open for this. */ /* Send ICMPv6 4,3 in case of violation. */ /* Store receive network interface pointer for later. */ srcifp = m->m_pkthdr.rcvif; /* Generate a hash value for fragment bucket selection. */ hashkeyp = hashkey; memcpy(hashkeyp, &ip6->ip6_src, sizeof(struct in6_addr)); hashkeyp += sizeof(struct in6_addr) / sizeof(*hashkeyp); memcpy(hashkeyp, &ip6->ip6_dst, sizeof(struct in6_addr)); hashkeyp += sizeof(struct in6_addr) / sizeof(*hashkeyp); *hashkeyp = ip6f->ip6f_ident; bucket = jenkins_hash32(hashkey, nitems(hashkey), V_ip6qb_hashseed); bucket &= IP6REASS_HMASK; IP6QB_LOCK(bucket); head = IP6QB_HEAD(bucket); TAILQ_FOREACH(q6, head, ip6q_tq) if (ip6f->ip6f_ident == q6->ip6q_ident && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst) #ifdef MAC && mac_ip6q_match(m, q6) #endif ) break; only_frag = false; if (q6 == NULL) { /* A first fragment to arrive creates a reassembly queue. */ only_frag = true; /* * Enforce upper bound on number of fragmented packets * for which we attempt reassembly; * If maxfragpackets is 0, never accept fragments. * If maxfragpackets is -1, accept all fragments without * limitation. */ if (V_ip6_maxfragpackets < 0) ; else if (V_ip6qb[bucket].count >= V_ip6_maxfragbucketsize || atomic_load_int(&V_frag6_nfragpackets) >= (u_int)V_ip6_maxfragpackets) goto dropfrag; /* Allocate IPv6 fragement packet queue entry. */ q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FRAG6, M_NOWAIT | M_ZERO); if (q6 == NULL) goto dropfrag; #ifdef MAC if (mac_ip6q_init(q6, M_NOWAIT) != 0) { free(q6, M_FRAG6); goto dropfrag; } mac_ip6q_create(m, q6); #endif atomic_add_int(&V_frag6_nfragpackets, 1); /* ip6q_nxt will be filled afterwards, from 1st fragment. */ TAILQ_INIT(&q6->ip6q_frags); q6->ip6q_ident = ip6f->ip6f_ident; - q6->ip6q_ttl = IPV6_FRAGTTL; + q6->ip6q_ttl = frag6_milli_to_callout_ticks(V_ip6_fraglifetime); q6->ip6q_src = ip6->ip6_src; q6->ip6q_dst = ip6->ip6_dst; q6->ip6q_ecn = IPV6_ECN(ip6); q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ /* Add the fragemented packet to the bucket. */ TAILQ_INSERT_HEAD(head, q6, ip6q_tq); V_ip6qb[bucket].count++; } /* * If it is the 1st fragment, record the length of the * unfragmentable part and the next header of the fragment header. * Assume the first 1st fragement to arrive will be correct. * We do not have any duplicate checks here yet so another packet * with fragoff == 0 could come and overwrite the ip6q_unfrglen * and worse, the next header, at any time. */ if (fragoff == 0 && q6->ip6q_unfrglen == -1) { q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - sizeof(struct ip6_frag); q6->ip6q_nxt = ip6f->ip6f_nxt; /* XXX ECN? */ } /* * Check that the reassembled packet would not exceed 65535 bytes * in size. * If it would exceed, discard the fragment and return an ICMP error. */ if (q6->ip6q_unfrglen >= 0) { /* The 1st fragment has already arrived. */ if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { if (only_frag) { TAILQ_REMOVE(head, q6, ip6q_tq); V_ip6qb[bucket].count--; atomic_subtract_int(&V_frag6_nfragpackets, 1); #ifdef MAC mac_ip6q_destroy(q6); #endif free(q6, M_FRAG6); } IP6QB_UNLOCK(bucket); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); *mp = NULL; return (IPPROTO_DONE); } } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { if (only_frag) { TAILQ_REMOVE(head, q6, ip6q_tq); V_ip6qb[bucket].count--; atomic_subtract_int(&V_frag6_nfragpackets, 1); #ifdef MAC mac_ip6q_destroy(q6); #endif free(q6, M_FRAG6); } IP6QB_UNLOCK(bucket); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); *mp = NULL; return (IPPROTO_DONE); } /* * If it is the first fragment, do the above check for each * fragment already stored in the reassembly queue. */ if (fragoff == 0 && !only_frag) { TAILQ_FOREACH_SAFE(af6, &q6->ip6q_frags, ip6af_tq, af6tmp) { if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen > IPV6_MAXPACKET) { struct ip6_hdr *ip6err; struct mbuf *merr; int erroff; merr = af6->ip6af_m; erroff = af6->ip6af_offset; /* Dequeue the fragment. */ TAILQ_REMOVE(&q6->ip6q_frags, af6, ip6af_tq); q6->ip6q_nfrag--; atomic_subtract_int(&frag6_nfrags, 1); free(af6, M_FRAG6); /* Set a valid receive interface pointer. */ merr->m_pkthdr.rcvif = srcifp; /* Adjust pointer. */ ip6err = mtod(merr, struct ip6_hdr *); /* * Restore source and destination addresses * in the erroneous IPv6 header. */ ip6err->ip6_src = q6->ip6q_src; ip6err->ip6_dst = q6->ip6q_dst; icmp6_error(merr, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff - sizeof(struct ip6_frag) + offsetof(struct ip6_frag, ip6f_offlg)); } } } /* Allocate an IPv6 fragement queue entry for this fragmented part. */ ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FRAG6, M_NOWAIT | M_ZERO); if (ip6af == NULL) goto dropfrag; ip6af->ip6af_mff = (ip6f->ip6f_offlg & IP6F_MORE_FRAG) ? true : false; ip6af->ip6af_off = fragoff; ip6af->ip6af_frglen = frgpartlen; ip6af->ip6af_offset = offset; ip6af->ip6af_m = m; if (only_frag) { /* * Do a manual insert rather than a hard-to-understand cast * to a different type relying on data structure order to work. */ TAILQ_INSERT_HEAD(&q6->ip6q_frags, ip6af, ip6af_tq); goto postinsert; } /* Do duplicate, condition, and boundry checks. */ /* * Handle ECN by comparing this segment with the first one; * if CE is set, do not lose CE. * Drop if CE and not-ECT are mixed for the same packet. */ ecn = IPV6_ECN(ip6); ecn0 = q6->ip6q_ecn; if (ecn == IPTOS_ECN_CE) { if (ecn0 == IPTOS_ECN_NOTECT) { free(ip6af, M_FRAG6); goto dropfrag; } if (ecn0 != IPTOS_ECN_CE) q6->ip6q_ecn = IPTOS_ECN_CE; } if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) { free(ip6af, M_FRAG6); goto dropfrag; } /* Find a fragmented part which begins after this one does. */ TAILQ_FOREACH(af6, &q6->ip6q_frags, ip6af_tq) if (af6->ip6af_off > ip6af->ip6af_off) break; /* * If the incoming framgent overlaps some existing fragments in * the reassembly queue, drop both the new fragment and the * entire reassembly queue. However, if the new fragment * is an exact duplicate of an existing fragment, only silently * drop the existing fragment and leave the fragmentation queue * unchanged, as allowed by the RFC. (RFC 8200, 4.5) */ if (af6 != NULL) af6tmp = TAILQ_PREV(af6, ip6fraghead, ip6af_tq); else af6tmp = TAILQ_LAST(&q6->ip6q_frags, ip6fraghead); if (af6tmp != NULL) { if (af6tmp->ip6af_off + af6tmp->ip6af_frglen - ip6af->ip6af_off > 0) { if (af6tmp->ip6af_off != ip6af->ip6af_off || af6tmp->ip6af_frglen != ip6af->ip6af_frglen) frag6_freef(q6, bucket); free(ip6af, M_FRAG6); goto dropfrag; } } if (af6 != NULL) { if (ip6af->ip6af_off + ip6af->ip6af_frglen - af6->ip6af_off > 0) { if (af6->ip6af_off != ip6af->ip6af_off || af6->ip6af_frglen != ip6af->ip6af_frglen) frag6_freef(q6, bucket); free(ip6af, M_FRAG6); goto dropfrag; } } #ifdef MAC mac_ip6q_update(m, q6); #endif /* * Stick new segment in its place; check for complete reassembly. * If not complete, check fragment limit. Move to front of packet * queue, as we are the most recently active fragmented packet. */ if (af6 != NULL) TAILQ_INSERT_BEFORE(af6, ip6af, ip6af_tq); else TAILQ_INSERT_TAIL(&q6->ip6q_frags, ip6af, ip6af_tq); postinsert: atomic_add_int(&frag6_nfrags, 1); q6->ip6q_nfrag++; plen = 0; TAILQ_FOREACH(af6, &q6->ip6q_frags, ip6af_tq) { if (af6->ip6af_off != plen) { if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); *mp = NULL; return (IPPROTO_DONE); } plen += af6->ip6af_frglen; } af6 = TAILQ_LAST(&q6->ip6q_frags, ip6fraghead); if (af6->ip6af_mff) { if (q6->ip6q_nfrag > V_ip6_maxfragsperpacket) { IP6STAT_ADD(ip6s_fragdropped, q6->ip6q_nfrag); frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); *mp = NULL; return (IPPROTO_DONE); } /* Reassembly is complete; concatenate fragments. */ ip6af = TAILQ_FIRST(&q6->ip6q_frags); t = m = ip6af->ip6af_m; TAILQ_REMOVE(&q6->ip6q_frags, ip6af, ip6af_tq); while ((af6 = TAILQ_FIRST(&q6->ip6q_frags)) != NULL) { m->m_pkthdr.csum_flags &= af6->ip6af_m->m_pkthdr.csum_flags; m->m_pkthdr.csum_data += af6->ip6af_m->m_pkthdr.csum_data; TAILQ_REMOVE(&q6->ip6q_frags, af6, ip6af_tq); t = m_last(t); m_adj(af6->ip6af_m, af6->ip6af_offset); m_demote_pkthdr(af6->ip6af_m); m_cat(t, af6->ip6af_m); free(af6, M_FRAG6); } while (m->m_pkthdr.csum_data & 0xffff0000) m->m_pkthdr.csum_data = (m->m_pkthdr.csum_data & 0xffff) + (m->m_pkthdr.csum_data >> 16); /* Adjust offset to point where the original next header starts. */ offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); free(ip6af, M_FRAG6); ip6 = mtod(m, struct ip6_hdr *); ip6->ip6_plen = htons((u_short)plen + offset - sizeof(struct ip6_hdr)); if (q6->ip6q_ecn == IPTOS_ECN_CE) ip6->ip6_flow |= htonl(IPTOS_ECN_CE << 20); nxt = q6->ip6q_nxt; TAILQ_REMOVE(head, q6, ip6q_tq); V_ip6qb[bucket].count--; atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag); ip6_deletefraghdr(m, offset, M_NOWAIT); /* Set nxt(-hdr field value) to the original value. */ m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t), (caddr_t)&nxt); #ifdef MAC mac_ip6q_reassemble(q6, m); mac_ip6q_destroy(q6); #endif free(q6, M_FRAG6); atomic_subtract_int(&V_frag6_nfragpackets, 1); if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ plen = 0; for (t = m; t; t = t->m_next) plen += t->m_len; m->m_pkthdr.len = plen; /* Set a valid receive interface pointer. */ m->m_pkthdr.rcvif = srcifp; } #ifdef RSS mtag = m_tag_alloc(MTAG_ABI_IPV6, IPV6_TAG_DIRECT, sizeof(*ip6dc), M_NOWAIT); if (mtag == NULL) goto dropfrag; ip6dc = (struct ip6_direct_ctx *)(mtag + 1); ip6dc->ip6dc_nxt = nxt; ip6dc->ip6dc_off = offset; m_tag_prepend(m, mtag); #endif IP6QB_UNLOCK(bucket); IP6STAT_INC(ip6s_reassembled); in6_ifstat_inc(dstifp, ifs6_reass_ok); #ifdef RSS /* Queue/dispatch for reprocessing. */ netisr_dispatch(NETISR_IPV6_DIRECT, m); *mp = NULL; return (IPPROTO_DONE); #endif /* Tell launch routine the next header. */ *mp = m; *offp = offset; return (nxt); dropfrag: IP6QB_UNLOCK(bucket); dropfrag2: in6_ifstat_inc(dstifp, ifs6_reass_fail); IP6STAT_INC(ip6s_fragdropped); m_freem(m); *mp = NULL; return (IPPROTO_DONE); } /* * IPv6 reassembling timer processing; * if a timer expires on a reassembly queue, discard it. */ static struct callout frag6_callout; static void frag6_slowtimo(void *arg __unused) { VNET_ITERATOR_DECL(vnet_iter); struct ip6qhead *head; struct ip6q *q6, *q6tmp; uint32_t bucket; if (atomic_load_int(&frag6_nfrags) == 0) goto done; VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { if (V_ip6qb[bucket].count == 0) continue; IP6QB_LOCK(bucket); head = IP6QB_HEAD(bucket); TAILQ_FOREACH_SAFE(q6, head, ip6q_tq, q6tmp) if (--q6->ip6q_ttl == 0) { IP6STAT_ADD(ip6s_fragtimeout, q6->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(q6, bucket); } /* * If we are over the maximum number of fragments * (due to the limit being lowered), drain off * enough to get down to the new limit. * Note that we drain all reassembly queues if * maxfragpackets is 0 (fragmentation is disabled), * and do not enforce a limit when maxfragpackets * is negative. */ while ((V_ip6_maxfragpackets == 0 || (V_ip6_maxfragpackets > 0 && V_ip6qb[bucket].count > V_ip6_maxfragbucketsize)) && (q6 = TAILQ_LAST(head, ip6qhead)) != NULL) { IP6STAT_ADD(ip6s_fragoverflow, q6->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); } /* * If we are still over the maximum number of fragmented * packets, drain off enough to get down to the new limit. */ bucket = 0; while (V_ip6_maxfragpackets >= 0 && atomic_load_int(&V_frag6_nfragpackets) > (u_int)V_ip6_maxfragpackets) { IP6QB_LOCK(bucket); q6 = TAILQ_LAST(IP6QB_HEAD(bucket), ip6qhead); if (q6 != NULL) { IP6STAT_ADD(ip6s_fragoverflow, q6->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); bucket = (bucket + 1) % IP6REASS_NHASH; } CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); done: - callout_reset_sbt(&frag6_callout, SBT_1MS * 500, SBT_1MS * 10, - frag6_slowtimo, NULL, 0); + callout_reset_sbt(&frag6_callout, SBT_1MS * IP6_CALLOUT_INTERVAL_MS, + SBT_1MS * 10, frag6_slowtimo, NULL, 0); } static void frag6_slowtimo_init(void *arg __unused) { callout_init(&frag6_callout, 1); - callout_reset_sbt(&frag6_callout, SBT_1MS * 500, SBT_1MS * 10, - frag6_slowtimo, NULL, 0); + callout_reset_sbt(&frag6_callout, SBT_1MS * IP6_CALLOUT_INTERVAL_MS, + SBT_1MS * 10, frag6_slowtimo, NULL, 0); } SYSINIT(frag6, SI_SUB_VNET_DONE, SI_ORDER_ANY, frag6_slowtimo_init, NULL); /* * Eventhandler to adjust limits in case nmbclusters change. */ static void frag6_change(void *tag) { VNET_ITERATOR_DECL(vnet_iter); ip6_maxfrags = IP6_MAXFRAGS; VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); V_ip6_maxfragpackets = IP6_MAXFRAGPACKETS; frag6_set_bucketsize(); CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); } /* * Initialise reassembly queue and fragment identifier. */ void frag6_init(void) { uint32_t bucket; V_ip6_maxfragpackets = IP6_MAXFRAGPACKETS; frag6_set_bucketsize(); for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { TAILQ_INIT(IP6QB_HEAD(bucket)); mtx_init(&V_ip6qb[bucket].lock, "ip6qb", NULL, MTX_DEF); V_ip6qb[bucket].count = 0; } V_ip6qb_hashseed = arc4random(); V_ip6_maxfragsperpacket = 64; #ifdef VIMAGE V_frag6_on = true; #endif if (!IS_DEFAULT_VNET(curvnet)) return; ip6_maxfrags = IP6_MAXFRAGS; EVENTHANDLER_REGISTER(nmbclusters_change, frag6_change, NULL, EVENTHANDLER_PRI_ANY); } /* * Drain off all datagram fragments. */ static void frag6_drain_one(void) { struct ip6q *q6; uint32_t bucket; for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { IP6QB_LOCK(bucket); while ((q6 = TAILQ_FIRST(IP6QB_HEAD(bucket))) != NULL) { IP6STAT_INC(ip6s_fragdropped); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); } } void frag6_drain(void) { VNET_ITERATOR_DECL(vnet_iter); VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); frag6_drain_one(); CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); } #ifdef VIMAGE /* * Clear up IPv6 reassembly structures. */ void frag6_destroy(void) { uint32_t bucket; frag6_drain_one(); V_frag6_on = false; for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { KASSERT(V_ip6qb[bucket].count == 0, ("%s: V_ip6qb[%d] (%p) count not 0 (%d)", __func__, bucket, &V_ip6qb[bucket], V_ip6qb[bucket].count)); mtx_destroy(&V_ip6qb[bucket].lock); } } #endif diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index c267503d7151..bc409780feec 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,464 +1,464 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $KAME: ip6_var.h,v 1.62 2001/05/03 14:51:48 itojun Exp $ */ /*- * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip_var.h 8.1 (Berkeley) 6/10/93 * $FreeBSD$ */ #ifndef _NETINET6_IP6_VAR_H_ #define _NETINET6_IP6_VAR_H_ #include #ifdef _KERNEL struct ip6asfrag; /* frag6.c */ TAILQ_HEAD(ip6fraghead, ip6asfrag); /* * IP6 reassembly queue structure. Each fragment * being reassembled is attached to one of these structures. */ struct ip6q { struct ip6fraghead ip6q_frags; u_int32_t ip6q_ident; u_int8_t ip6q_nxt; u_int8_t ip6q_ecn; - u_int8_t ip6q_ttl; + u_int16_t ip6q_ttl; struct in6_addr ip6q_src, ip6q_dst; TAILQ_ENTRY(ip6q) ip6q_tq; int ip6q_unfrglen; /* len of unfragmentable part */ int ip6q_nfrag; /* # of fragments */ struct label *ip6q_label; }; #endif /* _KERNEL */ /* * IP6 reinjecting structure. */ struct ip6_direct_ctx { uint32_t ip6dc_nxt; /* next header to process */ uint32_t ip6dc_off; /* offset to next header */ }; #if defined(_NETINET6_IN6_VAR_H_) && defined(_KERNEL) /* * Structure attached to inpcb.in6p_moptions and * passed to ip6_output when IPv6 multicast options are in use. * This structure is lazy-allocated. */ struct ip6_moptions { struct ifnet *im6o_multicast_ifp; /* ifp for outgoing multicasts */ u_char im6o_multicast_hlim; /* hoplimit for outgoing multicasts */ u_char im6o_multicast_loop; /* 1 >= hear sends if a member */ struct ip6_mfilter_head im6o_head; /* group membership list */ }; #else struct ip6_moptions; #endif /* * Control options for outgoing packets */ /* Routing header related info */ struct ip6po_rhinfo { struct ip6_rthdr *ip6po_rhi_rthdr; /* Routing header */ struct route_in6 ip6po_rhi_route; /* Route to the 1st hop */ }; #define ip6po_rthdr ip6po_rhinfo.ip6po_rhi_rthdr #define ip6po_route ip6po_rhinfo.ip6po_rhi_route /* Nexthop related info */ struct ip6po_nhinfo { struct sockaddr *ip6po_nhi_nexthop; struct route_in6 ip6po_nhi_route; /* Route to the nexthop */ }; #define ip6po_nexthop ip6po_nhinfo.ip6po_nhi_nexthop #define ip6po_nextroute ip6po_nhinfo.ip6po_nhi_route struct ip6_pktopts { struct mbuf *ip6po_m; /* Pointer to mbuf storing the data */ int ip6po_hlim; /* Hoplimit for outgoing packets */ /* Outgoing IF/address information */ struct in6_pktinfo *ip6po_pktinfo; /* Next-hop address information */ struct ip6po_nhinfo ip6po_nhinfo; struct ip6_hbh *ip6po_hbh; /* Hop-by-Hop options header */ /* Destination options header (before a routing header) */ struct ip6_dest *ip6po_dest1; /* Routing header related info. */ struct ip6po_rhinfo ip6po_rhinfo; /* Destination options header (after a routing header) */ struct ip6_dest *ip6po_dest2; int ip6po_tclass; /* traffic class */ int ip6po_minmtu; /* fragment vs PMTU discovery policy */ #define IP6PO_MINMTU_MCASTONLY -1 /* default; send at min MTU for multicast*/ #define IP6PO_MINMTU_DISABLE 0 /* always perform pmtu disc */ #define IP6PO_MINMTU_ALL 1 /* always send at min MTU */ int ip6po_prefer_tempaddr; /* whether temporary addresses are preferred as source address */ #define IP6PO_TEMPADDR_SYSTEM -1 /* follow the system default */ #define IP6PO_TEMPADDR_NOTPREFER 0 /* not prefer temporary address */ #define IP6PO_TEMPADDR_PREFER 1 /* prefer temporary address */ int ip6po_flags; #if 0 /* parameters in this block is obsolete. do not reuse the values. */ #define IP6PO_REACHCONF 0x01 /* upper-layer reachability confirmation. */ #define IP6PO_MINMTU 0x02 /* use minimum MTU (IPV6_USE_MIN_MTU) */ #endif #define IP6PO_DONTFRAG 0x04 /* disable fragmentation (IPV6_DONTFRAG) */ #define IP6PO_USECOA 0x08 /* use care of address */ }; /* * Control options for incoming packets */ struct ip6stat { uint64_t ip6s_total; /* total packets received */ uint64_t ip6s_tooshort; /* packet too short */ uint64_t ip6s_toosmall; /* not enough data */ uint64_t ip6s_fragments; /* fragments received */ uint64_t ip6s_fragdropped; /* frags dropped(dups, out of space) */ uint64_t ip6s_fragtimeout; /* fragments timed out */ uint64_t ip6s_fragoverflow; /* fragments that exceeded limit */ uint64_t ip6s_forward; /* packets forwarded */ uint64_t ip6s_cantforward; /* packets rcvd for unreachable dest */ uint64_t ip6s_redirectsent; /* packets forwarded on same net */ uint64_t ip6s_delivered; /* datagrams delivered to upper level*/ uint64_t ip6s_localout; /* total ip packets generated here */ uint64_t ip6s_odropped; /* lost packets due to nobufs, etc. */ uint64_t ip6s_reassembled; /* total packets reassembled ok */ uint64_t ip6s_atomicfrags; /* atomic fragments */ uint64_t ip6s_fragmented; /* datagrams successfully fragmented */ uint64_t ip6s_ofragments; /* output fragments created */ uint64_t ip6s_cantfrag; /* don't fragment flag was set, etc. */ uint64_t ip6s_badoptions; /* error in option processing */ uint64_t ip6s_noroute; /* packets discarded due to no route */ uint64_t ip6s_badvers; /* ip6 version != 6 */ uint64_t ip6s_rawout; /* total raw ip packets generated */ uint64_t ip6s_badscope; /* scope error */ uint64_t ip6s_notmember; /* don't join this multicast group */ #define IP6S_HDRCNT 256 /* headers count */ uint64_t ip6s_nxthist[IP6S_HDRCNT]; /* next header history */ uint64_t ip6s_m1; /* one mbuf */ #define IP6S_M2MMAX 32 uint64_t ip6s_m2m[IP6S_M2MMAX]; /* two or more mbuf */ uint64_t ip6s_mext1; /* one ext mbuf */ uint64_t ip6s_mext2m; /* two or more ext mbuf */ uint64_t ip6s_exthdrtoolong; /* ext hdr are not contiguous */ uint64_t ip6s_nogif; /* no match gif found */ uint64_t ip6s_toomanyhdr; /* discarded due to too many headers */ /* * statistics for improvement of the source address selection * algorithm: * XXX: hardcoded 16 = # of ip6 multicast scope types + 1 */ #define IP6S_RULESMAX 16 #define IP6S_SCOPECNT 16 /* number of times that address selection fails */ uint64_t ip6s_sources_none; /* number of times that an address on the outgoing I/F is chosen */ uint64_t ip6s_sources_sameif[IP6S_SCOPECNT]; /* number of times that an address on a non-outgoing I/F is chosen */ uint64_t ip6s_sources_otherif[IP6S_SCOPECNT]; /* * number of times that an address that has the same scope * from the destination is chosen. */ uint64_t ip6s_sources_samescope[IP6S_SCOPECNT]; /* * number of times that an address that has a different scope * from the destination is chosen. */ uint64_t ip6s_sources_otherscope[IP6S_SCOPECNT]; /* number of times that a deprecated address is chosen */ uint64_t ip6s_sources_deprecated[IP6S_SCOPECNT]; /* number of times that each rule of source selection is applied. */ uint64_t ip6s_sources_rule[IP6S_RULESMAX]; }; #ifdef _KERNEL #include VNET_PCPUSTAT_DECLARE(struct ip6stat, ip6stat); #define IP6STAT_ADD(name, val) \ VNET_PCPUSTAT_ADD(struct ip6stat, ip6stat, name, (val)) #define IP6STAT_SUB(name, val) IP6STAT_ADD(name, -(val)) #define IP6STAT_INC(name) IP6STAT_ADD(name, 1) #define IP6STAT_DEC(name) IP6STAT_SUB(name, 1) #endif #ifdef _KERNEL /* flags passed to ip6_output as last parameter */ #define IPV6_UNSPECSRC 0x01 /* allow :: as the source address */ #define IPV6_FORWARDING 0x02 /* most of IPv6 header exists */ #define IPV6_MINMTU 0x04 /* use minimum MTU (IPV6_USE_MIN_MTU) */ #ifdef __NO_STRICT_ALIGNMENT #define IP6_HDR_ALIGNED_P(ip) 1 #else #define IP6_HDR_ALIGNED_P(ip) ((((intptr_t) (ip)) & 3) == 0) #endif VNET_DECLARE(int, ip6_defhlim); /* default hop limit */ VNET_DECLARE(int, ip6_defmcasthlim); /* default multicast hop limit */ VNET_DECLARE(int, ip6_forwarding); /* act as router? */ VNET_DECLARE(int, ip6_use_deprecated); /* allow deprecated addr as source */ VNET_DECLARE(int, ip6_rr_prune); /* router renumbering prefix * walk list every 5 sec. */ VNET_DECLARE(int, ip6_mcast_pmtu); /* enable pMTU discovery for multicast? */ VNET_DECLARE(int, ip6_v6only); #define V_ip6_defhlim VNET(ip6_defhlim) #define V_ip6_defmcasthlim VNET(ip6_defmcasthlim) #define V_ip6_forwarding VNET(ip6_forwarding) #define V_ip6_use_deprecated VNET(ip6_use_deprecated) #define V_ip6_rr_prune VNET(ip6_rr_prune) #define V_ip6_mcast_pmtu VNET(ip6_mcast_pmtu) #define V_ip6_v6only VNET(ip6_v6only) VNET_DECLARE(struct socket *, ip6_mrouter); /* multicast routing daemon */ VNET_DECLARE(int, ip6_sendredirects); /* send IP redirects when forwarding? */ VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */ VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */ VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA * receiving IF. */ VNET_DECLARE(int, ip6_rfc6204w3); /* Accept defroute from RA even when forwarding enabled */ VNET_DECLARE(int, ip6_hdrnestlimit); /* upper limit of # of extension * headers */ VNET_DECLARE(int, ip6_dad_count); /* DupAddrDetectionTransmits */ #define V_ip6_mrouter VNET(ip6_mrouter) #define V_ip6_sendredirects VNET(ip6_sendredirects) #define V_ip6_accept_rtadv VNET(ip6_accept_rtadv) #define V_ip6_no_radr VNET(ip6_no_radr) #define V_ip6_norbit_raif VNET(ip6_norbit_raif) #define V_ip6_rfc6204w3 VNET(ip6_rfc6204w3) #define V_ip6_hdrnestlimit VNET(ip6_hdrnestlimit) #define V_ip6_dad_count VNET(ip6_dad_count) VNET_DECLARE(int, ip6_auto_flowlabel); VNET_DECLARE(int, ip6_auto_linklocal); #define V_ip6_auto_flowlabel VNET(ip6_auto_flowlabel) #define V_ip6_auto_linklocal VNET(ip6_auto_linklocal) VNET_DECLARE(int, ip6_use_tempaddr); /* Whether to use temporary addresses */ VNET_DECLARE(int, ip6_prefer_tempaddr); /* Whether to prefer temporary * addresses in the source address * selection */ #define V_ip6_use_tempaddr VNET(ip6_use_tempaddr) #define V_ip6_prefer_tempaddr VNET(ip6_prefer_tempaddr) VNET_DECLARE(int, ip6_use_defzone); /* Whether to use the default scope * zone when unspecified */ #define V_ip6_use_defzone VNET(ip6_use_defzone) VNET_DECLARE(struct pfil_head *, inet6_pfil_head); #define V_inet6_pfil_head VNET(inet6_pfil_head) #define PFIL_INET6_NAME "inet6" VNET_DECLARE(struct pfil_head *, inet6_local_pfil_head); #define V_inet6_local_pfil_head VNET(inet6_local_pfil_head) #define PFIL_INET6_LOCAL_NAME "inet6-local" #ifdef IPSTEALTH VNET_DECLARE(int, ip6stealth); #define V_ip6stealth VNET(ip6stealth) #endif #ifdef EXPERIMENTAL VNET_DECLARE(int, nd6_ignore_ipv6_only_ra); #define V_nd6_ignore_ipv6_only_ra VNET(nd6_ignore_ipv6_only_ra) #endif VNET_DECLARE(bool, ip6_log_cannot_forward); #define V_ip6_log_cannot_forward VNET(ip6_log_cannot_forward) extern struct pr_usrreqs rip6_usrreqs; struct sockopt; struct inpcb; int icmp6_ctloutput(struct socket *, struct sockopt *sopt); void ip6_input(struct mbuf *); void ip6_direct_input(struct mbuf *); void ip6_freepcbopts(struct ip6_pktopts *); int ip6_unknown_opt(u_int8_t *, struct mbuf *, int); int ip6_get_prevhdr(const struct mbuf *, int); int ip6_nexthdr(const struct mbuf *, int, int, int *); int ip6_lasthdr(const struct mbuf *, int, int, int *); extern int (*ip6_mforward)(struct ip6_hdr *, struct ifnet *, struct mbuf *); int ip6_process_hopopts(struct mbuf *, u_int8_t *, int, u_int32_t *, u_int32_t *); struct mbuf **ip6_savecontrol_v4(struct inpcb *, struct mbuf *, struct mbuf **, int *); void ip6_savecontrol(struct inpcb *, struct mbuf *, struct mbuf **); void ip6_notify_pmtu(struct inpcb *, struct sockaddr_in6 *, u_int32_t); int ip6_sysctl(int *, u_int, void *, size_t *, void *, size_t); void ip6_forward(struct mbuf *, int); void ip6_mloopback(struct ifnet *, struct mbuf *); int ip6_output(struct mbuf *, struct ip6_pktopts *, struct route_in6 *, int, struct ip6_moptions *, struct ifnet **, struct inpcb *); int ip6_ctloutput(struct socket *, struct sockopt *); int ip6_raw_ctloutput(struct socket *, struct sockopt *); void ip6_initpktopts(struct ip6_pktopts *); int ip6_setpktopts(struct mbuf *, struct ip6_pktopts *, struct ip6_pktopts *, struct ucred *, int); void ip6_clearpktopts(struct ip6_pktopts *, int); struct ip6_pktopts *ip6_copypktopts(struct ip6_pktopts *, int); int ip6_optlen(struct inpcb *); int ip6_deletefraghdr(struct mbuf *, int, int); int ip6_fragment(struct ifnet *, struct mbuf *, int, u_char, int, uint32_t); int route6_input(struct mbuf **, int *, int); void frag6_init(void); void frag6_destroy(void); int frag6_input(struct mbuf **, int *, int); void frag6_drain(void); void rip6_init(void); int rip6_ctloutput(struct socket *, struct sockopt *); int rip6_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct thread *); int dest6_input(struct mbuf **, int *, int); int none_input(struct mbuf **, int *, int); int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *, struct inpcb *, struct ucred *, int, struct in6_addr *, int *); int in6_selectsrc_addr(uint32_t, const struct in6_addr *, uint32_t, struct ifnet *, struct in6_addr *, int *); int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct nhop_object **, u_int, uint32_t); u_int32_t ip6_randomid(void); u_int32_t ip6_randomflowlabel(void); void in6_delayed_cksum(struct mbuf *m, uint32_t plen, u_short offset); int ip6_log_ratelimit(void); /* * Argument type for the last arg of ip6proto_ctlinput_t(). * * IPv6 ICMP IPv6 [exthdrs] finalhdr payload * ^ ^ ^ ^ * | | ip6c_ip6 ip6c_off * | ip6c_icmp6 * ip6c_m * * ip6c_finaldst's sin6_addr usually points to ip6c_ip6->ip6_dst. If the * original * (internal) packet carries a routing header, it may point the * final * destination address in the routing header. * * ip6c_src: ip6c_ip6->ip6_src + scope info + flowlabel in ip6c_ip6 * (beware of flowlabel, if you try to compare it against others) * ip6c_dst: ip6c_finaldst + scope info */ struct ip6ctlparam { struct mbuf *ip6c_m; /* start of mbuf chain */ struct icmp6_hdr *ip6c_icmp6; /* icmp6 header of target packet */ struct ip6_hdr *ip6c_ip6; /* ip6 header of target packet */ int ip6c_off; /* offset of the target proto header */ struct sockaddr_in6 *ip6c_src; /* srcaddr w/ additional info */ struct sockaddr_in6 *ip6c_dst; /* (final) dstaddr w/ additional info */ struct sockaddr_in6 *ip6c_finaldst; /* final destination address */ void *ip6c_cmdarg; /* control command dependent data */ u_int8_t ip6c_nxt; /* final next header field */ }; typedef int ip6proto_input_t(struct mbuf **, int *, int); typedef void ip6proto_ctlinput_t(struct ip6ctlparam *); int ip6proto_register(uint8_t, ip6proto_input_t, ip6proto_ctlinput_t); int ip6proto_unregister(uint8_t); #define IP6PROTO_REGISTER(prot, input, ctl) do { \ int error __diagused; \ error = ip6proto_register(prot, input, ctl); \ MPASS(error == 0); \ } while (0) ip6proto_input_t rip6_input; ip6proto_ctlinput_t rip6_ctlinput; #endif /* _KERNEL */ #endif /* !_NETINET6_IP6_VAR_H_ */ diff --git a/tests/sys/netinet6/frag6/frag6.subr b/tests/sys/netinet6/frag6/frag6.subr index 1ea947c72de5..6f7d0799642c 100644 --- a/tests/sys/netinet6/frag6/frag6.subr +++ b/tests/sys/netinet6/frag6/frag6.subr @@ -1,122 +1,126 @@ # $FreeBSD$ #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # . $(atf_get_srcdir)/../../common/vnet.subr frag6_head() { atf_set descr 'Test IPv6 fragmentation code' atf_set require.user root atf_set require.progs scapy } frag6_body() { ids=${1:="65533"} shift id=`printf "%x" ${ids}` if [ $$ -gt 65535 ]; then xl=`printf "%x" $(($$ - 65535))` yl="1" else xl=`printf "%x" $$` yl="" fi vnet_init ip6a="2001:db8:6666:6666:${yl}:${id}:1:${xl}" ip6b="2001:db8:6666:6666:${yl}:${id}:2:${xl}" epair=$(vnet_mkepair) ifconfig ${epair}a up ifconfig ${epair}a inet6 ${ip6a}/64 jname="v6t-${id}-${yl}-${xl}" vnet_mkjail ${jname} ${epair}b + jexec ${jname} sysctl net.inet6.ip6.dad_count=0 jexec ${jname} ifconfig ${epair}b up jexec ${jname} ifconfig ${epair}b inet6 ${ip6b}/64 + # Set max fragment reassembly time to 2 seconds + jexec ${jname} sysctl net.inet6.ip6.fraglifetime_ms=2000 + # Let IPv6 ND do its thing. - #ping6 -q -c 1 ff02::1%${epair}a - #ping6 -q -c 1 ${ip6b} - sleep 3 + while [ `ifconfig ${epair}a inet6 | grep -c tentative` != "0" ]; do + sleep 0.1 + done # We need to try to make sure all expiry happened, otherwise there might # be global fragments queued. (This still does not rule out that there # are no other fragments queued anywhere else in the system). i=0 while test $i -lt 60; do nf=`sysctl -n net.inet6.ip6.frag6_nfrags` case ${nf} in 0) break ;; esac sleep 1 i=$((i + 1)) done case ${nf} in 0) ;; *) atf_fail "Global frag6_nfrags count is not zero but ${nf}" ;; esac pretestf=$2 case "${pretestf}" in "") ;; [A-Za-z0-9_]*) eval ${pretestf} "${jname}" "${epair}b" ;; esac # Clear statistics. jexec ${jname} netstat -z -s > /dev/null # Run fragment tests. pyname=$(atf_get ident) pyname=${pyname%*_[0-9]} atf_check -s exit:0 $(atf_get_srcdir)/${pyname}.py \ --sendif ${epair}a \ --recvif ${epair}a \ --src ${ip6a} \ --to ${ip6b} checkf=$1 case "${checkf}" in "") ;; [A-Za-z0-9_]*) eval ${checkf} "${jname}" "${epair}b" ;; esac } frag6_cleanup() { vnet_cleanup } # end diff --git a/tests/sys/netinet6/frag6/frag6_01.py b/tests/sys/netinet6/frag6/frag6_01.py index efa99ce65759..db6cabc1a84a 100644 --- a/tests/sys/netinet6/frag6/frag6_01.py +++ b/tests/sys/netinet6/frag6/frag6_01.py @@ -1,117 +1,117 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6ParamProblem) if not icmp6: return False # ICMP6_PARAMPROB_HEADER 0 if icmp6.code != 0: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Param Prob so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) ######################################################################## # # A single start fragment with zero length IPv6 header (jumbo). # Make sure we do hit the Fragment case, which is tricky as the # jumbogram needs to be > 64k. # # A: Jumbo-Fragment not allowed. # R: ICMPv6 param problem. # #data = "6" * (65536 - 2 - 6 - 8 - 8) data = "6" * 65512 ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0], plen=0) / \ sp.IPv6ExtHdrHopByHop(options=sp.Jumbo(jumboplen=65536)) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=6) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # We should only need to sleep 0.10 but it seems scapy # takes time for this one. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_05.py b/tests/sys/netinet6/frag6/frag6_05.py index f9bc947d5465..9c98ea1aaf2e 100644 --- a/tests/sys/netinet6/frag6/frag6_05.py +++ b/tests/sys/netinet6/frag6/frag6_05.py @@ -1,86 +1,86 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from time import sleep def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() ######################################################################## # # Sysctl set to accept (no|maximum 10) fragments. # # A: Discarded. # R: Silence (statistics only) or ICMPv6 timeout expiry. # data = "6" * 1280 bfid = 0x5001 for i in range(20): fid = bfid + i ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=fid) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for possible expiry to happen. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_07.py b/tests/sys/netinet6/frag6/frag6_07.py index 231f49eac2e0..540c5012e524 100644 --- a/tests/sys/netinet6/frag6/frag6_07.py +++ b/tests/sys/netinet6/frag6/frag6_07.py @@ -1,180 +1,180 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6ParamProblem) if not icmp6: return False # ICMP6_PARAMPROB_HEADER 0 if icmp6.code != 0: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Param Prob so leave it. #icmp6.display() return True def check_icmp6_error_2(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded) if not icmp6: return False # ICMP6_TIME_EXCEED_REASSEMBLY 1 if icmp6.code != 1: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) sniffer2 = Sniffer(args, check_icmp6_error_2) ######################################################################## # # Two fragments with payload and offset set to add up to >64k. # # Make a first fragment arrive and a second to explode everything. # # A: Reassembly failure. # R: ICMPv6 param prob, param header. # R: ICMPv6 timeout (1st frag, off=0) # data = "6" * 1280 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=7) / \ sp.UDP(dport=3456, sport=6543) / \ data ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0x1fff, m=1, id=7) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) sleep(1.00) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## # # A fragment with payload and offset set to add up to >64k. # # Try again with the first packet to make things explode. # # A: Reassembly failure. # R: ICMPv6 param prob, param header. # # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0x1fff, m=1, id=0x7001) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sleep(0.10) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) # Wait for expiry from first test run. - sleep(75) + sleep(3) sniffer2.setEnd() sniffer2.join() if not sniffer2.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_08.py b/tests/sys/netinet6/frag6/frag6_08.py index 25f57f702e71..74d7495f43cb 100644 --- a/tests/sys/netinet6/frag6/frag6_08.py +++ b/tests/sys/netinet6/frag6/frag6_08.py @@ -1,154 +1,154 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6ParamProblem) if not icmp6: return False # ICMP6_PARAMPROB_HEADER 0 if icmp6.code != 0: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Param Prob so leave it. #icmp6.display() return True def check_icmp6_error_2(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded) if not icmp6: return False # ICMP6_TIME_EXCEED_REASSEMBLY 1 if icmp6.code != 1: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) sniffer2 = Sniffer(args, check_icmp6_error_2) ######################################################################## # # A fragment with payload and offset set to add up to >64k when # another frag with offset=0 arrives and has an unfrag part. # This is us checking for all fragments queued already when the # one with off=0 arrives. Note: unless the off=0 has its own problem # it will be queued and off!=0 ones might be expunged with param prob. # # A: Reassembly failure, timeout after # R: ICMPv6 param prob, param header (1st frag) # R: ICMPv6 time exceeded (2nd frag, as off=0) # data = "6" * 15 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0x1ffc, m=0, id=8) / \ sp.UDP(dport=3456, sport=6543) / \ data data = "6" * 8 ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrDestOpt(options = \ sp.PadN(optdata="\x00\x00\x00\x00\x00\x00")) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=8) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) sleep(1.00) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) - sleep(75) + sleep(3) sniffer2.setEnd() sniffer2.join() if not sniffer2.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_09.py b/tests/sys/netinet6/frag6/frag6_09.py index 63ec646e1175..b5c519040292 100644 --- a/tests/sys/netinet6/frag6/frag6_09.py +++ b/tests/sys/netinet6/frag6/frag6_09.py @@ -1,111 +1,111 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded) if not icmp6: return False # ICMP6_TIME_EXCEED_REASSEMBLY 1 if icmp6.code != 1: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) ######################################################################## # # A single start fragment. # # A: Waiting for more data. # R: Timeout / Expiry. # ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=2) / \ sp.UDP(dport=3456, sport=6543) if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for ICMPv6 error generation on timeout. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_10.py b/tests/sys/netinet6/frag6/frag6_10.py index fcd331190c02..191e3fc3e075 100644 --- a/tests/sys/netinet6/frag6/frag6_10.py +++ b/tests/sys/netinet6/frag6/frag6_10.py @@ -1,83 +1,83 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from time import sleep def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() ######################################################################## # # A single middle fragment. # # A: Waiting for more data. # R: Timeout / Expiry. # ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=161, m=1, id=7) / \ sp.UDP(dport=3456, sport=6543) if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # We do not generate ICMPv6 for non-off=0-segments. # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_11.py b/tests/sys/netinet6/frag6/frag6_11.py index 6b9643337597..be50a766ab1a 100644 --- a/tests/sys/netinet6/frag6/frag6_11.py +++ b/tests/sys/netinet6/frag6/frag6_11.py @@ -1,83 +1,83 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from time import sleep def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() ######################################################################## # # A single last fragment. # # A: Waiting for more data. # R: Timeout / Expiry. # ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=321, m=0, id=8) / \ sp.UDP(dport=3456, sport=6543) if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for expiration to happen. We will not see an ICMPv6 as there # is no frag with offset=0. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_12.py b/tests/sys/netinet6/frag6/frag6_12.py index a683782f2b69..d82610a0f75b 100644 --- a/tests/sys/netinet6/frag6/frag6_12.py +++ b/tests/sys/netinet6/frag6/frag6_12.py @@ -1,113 +1,113 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded) if not icmp6: return False # ICMP6_TIME_EXCEED_REASSEMBLY 1 if icmp6.code != 1: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) ######################################################################## # # A single start fragment with payload. # # A: Waiting for more data. # R: Timeout / Expiry. # data = "6" * 1280 ip6f01 = sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=3) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) # Wait for ICMPv6 error generation on timeout. - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_13.py b/tests/sys/netinet6/frag6/frag6_13.py index e377a4272fa1..a8717c2c795c 100644 --- a/tests/sys/netinet6/frag6/frag6_13.py +++ b/tests/sys/netinet6/frag6/frag6_13.py @@ -1,124 +1,124 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from time import sleep def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() ######################################################################## # # Two fragments with different ECN (Traffic Clas) bits to trigger # error cases. # # A: Reassembly failure. # R: ip6f02 dropped / Timeout (not waiting for). # data = "6" * 8 # IPTOS_ECN_NOTECT ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0], tc=0x00) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=13) / \ sp.UDP(dport=3456, sport=6543) / \ data # IPTOS_ECN_CE ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0], tc=0x03) / \ sp.IPv6ExtHdrFragment(offset=16, m=0, id=13) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## # # Two fragments with different ECN (Traffic Clas) bits to trigger # error cases. # # A: Reassembly failure. # R: ip6f02 dropped / Timeout (not waiting for). # # IPTOS_ECN_ECT1 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0], tc=0x01) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=0x1301) / \ sp.UDP(dport=3456, sport=6543) / \ data # IPTOS_ECN_NOTECT ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0], tc=0x00) / \ sp.IPv6ExtHdrFragment(offset=16, m=0, id=0x1301) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_14.py b/tests/sys/netinet6/frag6/frag6_14.py index b53a65e67529..49fae50f4bae 100644 --- a/tests/sys/netinet6/frag6/frag6_14.py +++ b/tests/sys/netinet6/frag6/frag6_14.py @@ -1,139 +1,139 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from time import sleep def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() ######################################################################## # # Send multiple fragments, with an exact overlap in a middle one, # not finishing the full packet (and ignoring the content anyway). # # A: Reassembly failure. # R: dup dropped silently / Timeout (not waiting for). # data = "6" * 8 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=14) / \ sp.UDP(dport=3456, sport=6543) / \ data ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0x1000, m=0, id=14) / \ sp.UDP(dport=3456, sport=6543) / \ data ip6f03 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=16, m=1, id=14) / \ sp.UDP(dport=3456, sport=6543) / \ data ip6f04 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=16, m=1, id=14) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() ip6f03.display() ip6f04.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) sp.sendp(ip6f03, iface=args.sendif[0], verbose=False) sp.sendp(ip6f04, iface=args.sendif[0], verbose=False) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## # # Send multiple fragments, with a partial overlap on the first one # not finishing the full packet (and ignoring the content anyway). # The second packet needs to be the first one in the fragment chain # in order to trigger the 2nd case to test. # # A: Reassembly failure. # R: dup dropped silently / Timeout (not waiting for). # data = "6" * 8 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=10, m=1, id=0x1401) / \ sp.UDP(dport=3456, sport=6543) / \ data ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=9, m=0, id=0x1401) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f01.display() ip6f02.display() sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) # Wait for expiry. - sleep(75) + sleep(3) sys.exit(0) if __name__ == '__main__': main() diff --git a/tests/sys/netinet6/frag6/frag6_20.py b/tests/sys/netinet6/frag6/frag6_20.py index 6dd4c2379357..4a68b242a23e 100755 --- a/tests/sys/netinet6/frag6/frag6_20.py +++ b/tests/sys/netinet6/frag6/frag6_20.py @@ -1,139 +1,139 @@ #!/usr/bin/env python #- # SPDX-License-Identifier: BSD-2-Clause # # Copyright (c) 2019 Netflix, Inc. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # import argparse import logging logging.getLogger("scapy").setLevel(logging.CRITICAL) import scapy.all as sp import socket import sys from sniffer import Sniffer from time import sleep def check_icmp6_error(args, packet): ip6 = packet.getlayer(sp.IPv6) if not ip6: return False oip6 = sp.IPv6(src=args.src[0], dst=args.to[0]) if ip6.dst != oip6.src: return False icmp6 = packet.getlayer(sp.ICMPv6TimeExceeded) if not icmp6: return False # ICMP6_TIME_EXCEED_REASSEMBLY 1 if icmp6.code != 1: return False # Should we check the payload as well? # We are running in a very isolated environment and nothing else # should trigger an ICMPv6 Time Exceeded / Frag reassembly so leave it. #icmp6.display() return True def main(): parser = argparse.ArgumentParser("frag6.py", description="IPv6 fragementation test tool") parser.add_argument('--sendif', nargs=1, required=True, help='The interface through which the packet will be sent') parser.add_argument('--recvif', nargs=1, required=True, help='The interface on which to check for the packet') parser.add_argument('--src', nargs=1, required=True, help='The source IP address') parser.add_argument('--to', nargs=1, required=True, help='The destination IP address') parser.add_argument('--debug', required=False, action='store_true', help='Enable test debugging') args = parser.parse_args() # Start sniffing on recvif sniffer = Sniffer(args, check_icmp6_error) ######################################################################## # # Send a proper first fragment (off=0) and a second fragment which # just fits the 64k. The re-send the first fragment with an extra # unfragmentable part making the 64k to exceed the limit. # This is to make sure we don't allow to update meta-data for a # 1st fragmented packet should a second arrive but given the # fragmentable part is an exact duplicate only that fragment # will be silently discarded. # # A: Reassembly failure, timeout after # R: ICMPv6 time exceeded / statistics for the duplicate # data = "6" * 8 ip6f00 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=20) / \ sp.UDP(dport=3456, sport=6543) / \ data data = "6" * 15 ip6f01 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrFragment(offset=0x1ffc, m=0, id=20) / \ sp.UDP(dport=3456, sport=6543) / \ data data = "6" * 8 ip6f02 = \ sp.Ether() / \ sp.IPv6(src=args.src[0], dst=args.to[0]) / \ sp.IPv6ExtHdrDestOpt(options = \ sp.PadN(optdata="\x00\x00\x00\x00\x00\x00")) / \ sp.IPv6ExtHdrFragment(offset=0, m=1, id=20) / \ sp.UDP(dport=3456, sport=6543) / \ data if args.debug : ip6f00.display() ip6f01.display() ip6f02.display() sp.sendp(ip6f00, iface=args.sendif[0], verbose=False) sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) sp.sendp(ip6f02, iface=args.sendif[0], verbose=False) - sleep(75) + sleep(3) sniffer.setEnd() sniffer.join() if not sniffer.foundCorrectPacket: sys.exit(1) sys.exit(0) if __name__ == '__main__': main()