Index: stable/12/etc/mtree/BSD.tests.dist =================================================================== --- stable/12/etc/mtree/BSD.tests.dist (revision 356490) +++ stable/12/etc/mtree/BSD.tests.dist (revision 356491) @@ -1,1094 +1,1098 @@ # $FreeBSD$ # # Please see the file src/etc/mtree/README before making changes to this file. # /set type=dir uname=root gname=wheel mode=0755 . bin cat .. chflags .. chmod .. date .. dd .. echo .. expr .. ln .. ls .. mkdir .. mv .. pax .. pkill .. pwait .. rm .. rmdir .. sh builtins .. errors .. execution .. expansion .. invocation .. parameters .. parser .. set-e .. .. sleep .. test .. .. cddl lib .. sbin .. usr.bin ctfconvert .. ztest .. .. usr.sbin dtrace common aggs .. arithmetic .. arrays .. assocs .. begin .. bitfields .. buffering .. builtinvar .. cg .. clauses .. cpc .. decls .. drops .. dtraceUtil .. end .. env .. enum .. error .. exit .. fbtprovider .. funcs .. grammar .. include .. inline .. io .. ip .. java_api .. json .. lexer .. llquantize .. mdb .. mib .. misc .. multiaggs .. offsetof .. operators .. pid .. plockstat .. pointers .. pragma .. predicates .. preprocessor .. print .. printa .. printf .. privs .. probes .. proc .. profile-n .. providers .. raise .. rates .. safety .. scalars .. sched .. scripting .. sdt .. sizeof .. speculation .. stability .. stack .. stackdepth .. stop .. strlen .. strtoll .. struct .. sugar .. syscall .. sysevent .. tick-n .. trace .. tracemem .. translators .. typedef .. types .. uctf .. union .. usdt .. ustack .. vars .. version .. .. i386 arrays .. funcs .. pid .. ustack .. .. .. zfsd .. .. .. etc rc.d .. .. games .. gnu lib .. usr.bin diff .. .. .. lib atf libatf-c detail .. .. libatf-c++ detail .. .. test-programs .. .. csu dynamic .. dynamiclib .. static .. .. googletest gmock .. gmock_main .. gtest .. gtest_main .. .. libarchive .. libbe .. libc c063 .. db .. gen execve .. posix_spawn .. .. hash data .. .. iconv .. inet .. locale .. net getaddrinfo data .. .. .. nss .. regex data .. .. resolv .. rpc .. ssp .. setjmp .. stdio .. stdlib .. string .. sys .. time .. tls dso .. .. termios .. ttyio .. .. libcam .. libcasper services cap_dns .. cap_grp .. cap_pwd .. cap_sysctl .. .. .. libcrypt .. libdevdctl .. libkvm .. libmp .. libnv .. libproc .. libregex data .. .. librt .. libsbuf .. libthr dlopen .. .. libutil .. libxo .. msun .. .. libexec atf atf-check .. atf-sh .. .. rtld-elf .. tftpd .. .. sbin bectl .. dhclient .. devd .. growfs .. ifconfig .. mdconfig .. pfctl files .. .. ping .. .. secure lib .. libexec .. usr.bin .. usr.sbin .. .. share examples tests atf .. googletest .. plain .. tap .. .. .. zoneinfo .. .. sys acl .. aio .. audit .. auditpipe .. capsicum .. cddl zfs bin .. include .. tests acl cifs .. nontrivial .. trivial .. .. atime .. bootfs .. cache .. cachefile .. clean_mirror .. cli_root zfs_upgrade .. zfs_promote .. zfs_clone .. zfs_property .. zfs_destroy .. zpool_create .. zpool_history .. zpool_expand .. zpool_remove .. zfs_mount .. zfs_unshare .. zdb .. zpool_online .. zpool_get .. zpool_export .. zfs_copies .. zfs_get .. zfs .. zpool_clear .. zpool_import blockfiles .. .. zpool .. zpool_offline .. zpool_replace .. zfs_rollback .. zpool_set .. zfs_send .. zfs_set .. zpool_detach .. zfs_diff .. zpool_scrub .. zfs_inherit .. zfs_snapshot .. zfs_share .. zpool_destroy .. zpool_status .. zfs_unmount .. zfs_receive .. zfs_create .. zpool_upgrade blockfiles .. .. zpool_add .. zfs_rename .. zpool_attach .. zfs_reservation .. .. cli_user misc .. zfs_list .. zpool_iostat .. zpool_list .. .. compression .. ctime .. delegate .. devices .. exec .. grow_pool .. grow_replicas .. history .. hotplug .. hotspare .. inheritance .. interop .. inuse .. iscsi .. large_files .. largest_pool .. link_count .. migration .. mmap .. mount .. mv_files .. nestedfs .. no_space .. online_offline .. pool_names .. poolversion .. quota .. redundancy .. refquota .. refreserv .. rename_dirs .. replacement .. reservation .. rootpool .. rsend .. scrub_mirror .. slog .. snapshot .. snapused .. sparse .. threadsappend .. truncate .. txg_integrity .. userquota .. utils_test .. write_dirs .. xattr .. zfsd .. zil .. zinject .. zones .. zvol zvol_ENOSPC .. zvol_cli .. zvol_misc .. zvol_swap .. .. zvol_thrash .. .. .. .. dtrace .. fifo .. file .. fs fusefs .. tmpfs .. .. geom class concat .. eli .. gate .. gpt .. mirror .. nop .. part .. raid3 .. shsec .. stripe .. uzip etalon .. .. .. .. kern acct .. execve .. pipe .. .. kqueue libkqueue .. .. mac bsdextended .. portacl .. .. mqueue .. net .. netinet .. + netinet6 + frag6 + .. + .. netipsec tunnel .. .. netmap .. netpfil pf ioctl .. .. .. opencrypto .. pjdfstest chflags .. chmod .. chown .. ftruncate .. granular .. link .. mkdir .. mkfifo .. mknod .. open .. rename .. rmdir .. symlink .. truncate .. unlink .. utimensat .. .. posixshm .. sys .. vfs .. vm .. .. usr.bin apply .. awk .. basename .. bmake archives fmt_44bsd .. fmt_44bsd_mod .. fmt_oldbsd .. .. basic t0 .. t1 .. t2 .. t3 .. .. execution ellipsis .. empty .. joberr .. plus .. .. shell builtin .. meta .. path .. path_select .. replace .. select .. .. suffixes basic .. src_wild1 .. src_wild2 .. .. syntax directive-t0 .. enl .. funny-targets .. semi .. .. sysmk t0 2 1 .. .. mk .. .. t1 2 1 .. .. mk .. .. t2 2 1 .. .. mk .. .. .. variables modifier_M .. modifier_t .. opt_V .. t0 .. .. .. bsdcat .. calendar .. cmp .. compress .. cpio .. col .. comm .. csplit .. cut .. dc .. diff .. dirname .. du .. file2c .. find .. fold .. getconf .. grep .. gzip .. head .. hexdump .. ident .. indent .. join .. jot .. lastcomm .. limits .. locale .. m4 .. mkimg .. ncal .. opensm .. patch .. pr .. printf .. procstat .. rs .. sdiff .. sed regress.multitest.out .. .. seq .. soelim .. stat .. tail .. tar .. timeout .. tr .. truncate .. units .. uudecode .. uuencode .. uniq .. vmstat .. xargs .. xinstall .. xo .. yacc yacc .. .. .. usr.sbin chown .. etcupdate .. extattr .. fstyp .. jail .. makefs .. newsyslog .. nmtree .. praudit .. pw .. rpcbind .. sa .. .. .. # vim: set expandtab ts=4 sw=4: Index: stable/12/sys/netinet6/frag6.c =================================================================== --- stable/12/sys/netinet6/frag6.c (revision 356490) +++ stable/12/sys/netinet6/frag6.c (revision 356491) @@ -1,1009 +1,1048 @@ /*- * 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 /* 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) -static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *, - uint32_t bucket __unused); -static void frag6_deq(struct ip6asfrag *, uint32_t bucket __unused); -static void frag6_insque_head(struct ip6q *, struct ip6q *, - uint32_t bucket); -static void frag6_remque(struct ip6q *, uint32_t bucket); -static void frag6_freef(struct ip6q *, uint32_t bucket); - +TAILQ_HEAD(ip6qhead, ip6q); struct ip6qbucket { - struct ip6q ip6q; + 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"); -/* System wide (global) maximum and count of packets in reassembly queues. */ +#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 volatile u_int frag6_nfrags = 0; /* 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 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)].ip6q) +#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)) /* * Sysctls and helper function. */ SYSCTL_DECL(_net_inet6_ip6); +SYSCTL_UINT(_net_inet6_ip6, OID_AUTO, frag6_nfrags, + CTLFLAG_RD, __DEVOLATILE(u_int *, &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 " "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, 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"); /* * Remove the IPv6 fragmentation header from the mbuf. */ int ip6_deletefraghdr(struct mbuf *m, int offset, int wait) { struct ip6_hdr *ip6; struct mbuf *t; /* Delete frag6 header. */ if (m->m_len >= offset + sizeof(struct ip6_frag)) { /* This is the only possible case with !PULLDOWN_TEST. */ - ip6 = mtod(m, struct ip6_hdr *); + 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); } else { /* This comes with no copy if the boundary is on cluster. */ if ((t = m_split(m, offset, wait)) == NULL) return (ENOMEM); m_adj(t, sizeof(struct ip6_frag)); m_cat(m, t); } 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, *down6; + struct ip6asfrag *af6; struct mbuf *m; IP6QB_LOCK_ASSERT(bucket); - for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; - af6 = down6) { + while ((af6 = TAILQ_FIRST(&q6->ip6q_frags)) != NULL) { - m = IP6_REASS_MBUF(af6); - down6 = af6->ip6af_down; - frag6_deq(af6, bucket); + 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); } - frag6_remque(q6, bucket); + + 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 ip6q *q6, *q6n, *head; + struct ip6qhead *head; + struct ip6q *q6; struct ip6asfrag *af6; - struct mbuf *m; - int i; + uint32_t bucket; KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__)); +#ifdef VIMAGE + /* + * Skip processing if IPv6 reassembly is not initialised or + * torn down by frag6_destroy(). + */ + if (!V_frag6_on) + return; +#endif + CURVNET_SET_QUIET(ifp->if_vnet); - for (i = 0; i < IP6REASS_NHASH; i++) { - IP6QB_LOCK(i); - head = IP6QB_HEAD(i); + for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { + IP6QB_LOCK(bucket); + head = IP6QB_HEAD(bucket); /* Scan fragment list. */ - for (q6 = head->ip6q_next; q6 != head; q6 = q6n) { - q6n = q6->ip6q_next; + TAILQ_FOREACH(q6, head, ip6q_tq) { + TAILQ_FOREACH(af6, &q6->ip6q_frags, ip6af_tq) { - for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; - af6 = af6->ip6af_down) { - m = IP6_REASS_MBUF(af6); - - /* clear no longer valid rcvif pointer */ - if (m->m_pkthdr.rcvif == ifp) - m->m_pkthdr.rcvif = NULL; + /* Clear no longer valid rcvif pointer. */ + if (af6->ip6af_m->m_pkthdr.rcvif == ifp) + af6->ip6af_m->m_pkthdr.rcvif = NULL; } } - IP6QB_UNLOCK(i); + 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 ifnet *dstifp; - struct ifnet *srcifp; - struct in6_ifaddr *ia6; + struct mbuf *m, *t; struct ip6_hdr *ip6; struct ip6_frag *ip6f; - struct ip6q *head, *q6; - struct ip6asfrag *af6, *af6dwn, *ip6af; - struct mbuf *m, *t; + 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; ip6 = mtod(m, struct ip6_hdr *); #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE); ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); #else IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); if (ip6f == NULL) return (IPPROTO_DONE); #endif - /* - * Store receive network interface pointer for later. - */ - srcifp = m->m_pkthdr.rcvif; - dstifp = NULL; /* Find the destination interface of the packet. */ ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); if (ia6 != NULL) { dstifp = ia6->ia_ifp; ifa_free(&ia6->ia_ifa); } /* 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); 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 */ 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); return (IPPROTO_DONE); } IP6STAT_INC(ip6s_fragments); in6_ifstat_inc(dstifp, ifs6_reass_reqd); /* Offset now points to data portion. */ offset += sizeof(struct ip6_frag); /* * Handle "atomic" fragments (offset and m bit set to 0) upfront, * unrelated to any reassembly. Still need to remove the frag hdr. * See RFC 6946 and section 4.5 of RFC 8200. */ if ((ip6f->ip6f_offlg & ~IP6F_RESERVED_MASK) == 0) { /* XXX-BZ we want dedicated counters for this. */ IP6STAT_INC(ip6s_reassembled); /* XXX-BZ handle correctly. */ in6_ifstat_inc(dstifp, ifs6_reass_ok); *offp = offset; m->m_flags |= M_FRAGMENTED; return (ip6f->ip6f_nxt); } /* 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); 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; - head = IP6QB_HEAD(bucket); IP6QB_LOCK(bucket); + head = IP6QB_HEAD(bucket); - /* - * 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 dropfrag; - - for (q6 = head->ip6q_next; q6 != head; q6 = q6->ip6q_next) + 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 == head) { + 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; - atomic_add_int(&V_frag6_nfragpackets, 1); /* 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 - frag6_insque_head(q6, head, bucket); + atomic_add_int(&V_frag6_nfragpackets, 1); /* ip6q_nxt will be filled afterwards, from 1st fragment. */ - q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; -#ifdef notyet - q6->ip6q_nxtp = (u_char *)nxtp; -#endif + TAILQ_INIT(&q6->ip6q_frags); q6->ip6q_ident = ip6f->ip6f_ident; q6->ip6q_ttl = IPV6_FRAGTTL; q6->ip6q_src = ip6->ip6_src; q6->ip6q_dst = ip6->ip6_dst; q6->ip6q_ecn = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK; q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ - q6->ip6q_nfrag = 0; + /* 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. */ - fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); - if (fragoff == 0) { + 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)); - IP6QB_UNLOCK(bucket); 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)); - IP6QB_UNLOCK(bucket); 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) { - for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; - af6 = af6dwn) { - af6dwn = af6->ip6af_down; + 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) { + if (q6->ip6q_unfrglen + af6->ip6af_off + + af6->ip6af_frglen > IPV6_MAXPACKET) { struct ip6_hdr *ip6err; struct mbuf *merr; int erroff; - merr = IP6_REASS_MBUF(af6); + merr = af6->ip6af_m; erroff = af6->ip6af_offset; /* Dequeue the fragment. */ - frag6_deq(af6, bucket); + 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; + ip6af->ip6af_mff = (ip6f->ip6f_offlg & IP6F_MORE_FRAG) ? true : false; ip6af->ip6af_off = fragoff; ip6af->ip6af_frglen = frgpartlen; ip6af->ip6af_offset = offset; - IP6_REASS_MBUF(ip6af) = m; + ip6af->ip6af_m = m; if (only_frag) { - af6 = (struct ip6asfrag *)q6; - goto insert; + /* + * 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 = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK; 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. */ - for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; - af6 = af6->ip6af_down) + 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->ip6af_up != (struct ip6asfrag *)q6) { - if (af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen - + 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 != (struct ip6asfrag *)q6) { + 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; } } -insert: #ifdef MAC - if (!only_frag) - mac_ip6q_update(m, q6); + 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. */ - frag6_enq(ip6af, af6->ip6af_up, bucket); + 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; - for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; - af6 = af6->ip6af_down) { + 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); return (IPPROTO_DONE); } plen += af6->ip6af_frglen; } - if (af6->ip6af_up->ip6af_mff) { + 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); return (IPPROTO_DONE); } /* Reassembly is complete; concatenate fragments. */ - ip6af = q6->ip6q_down; - t = m = IP6_REASS_MBUF(ip6af); - af6 = ip6af->ip6af_down; - frag6_deq(ip6af, bucket); - while (af6 != (struct ip6asfrag *)q6) { + 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 &= - IP6_REASS_MBUF(af6)->m_pkthdr.csum_flags; + af6->ip6af_m->m_pkthdr.csum_flags; m->m_pkthdr.csum_data += - IP6_REASS_MBUF(af6)->m_pkthdr.csum_data; + af6->ip6af_m->m_pkthdr.csum_data; - af6dwn = af6->ip6af_down; - frag6_deq(af6, bucket); - while (t->m_next) - t = t->m_next; - m_adj(IP6_REASS_MBUF(af6), af6->ip6af_offset); - m_demote_pkthdr(IP6_REASS_MBUF(af6)); - m_cat(t, IP6_REASS_MBUF(af6)); + 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); - af6 = af6dwn; } 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); + if (ip6_deletefraghdr(m, offset, M_NOWAIT) != 0) { - frag6_remque(q6, bucket); - 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); goto dropfrag; } /* Set nxt(-hdr field value) to the original value. */ m_copyback(m, ip6_get_prevhdr(m, offset), sizeof(uint8_t), (caddr_t)&nxt); - frag6_remque(q6, bucket); - atomic_subtract_int(&frag6_nfrags, q6->ip6q_nfrag); #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); 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); return (IPPROTO_DONE); } /* * IPv6 reassembling timer processing; * if a timer expires on a reassembly queue, discard it. */ void frag6_slowtimo(void) { VNET_ITERATOR_DECL(vnet_iter); - struct ip6q *head, *q6; + struct ip6qhead *head; + struct ip6q *q6, *q6tmp; uint32_t bucket; VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { IP6QB_LOCK(bucket); head = IP6QB_HEAD(bucket); - q6 = head->ip6q_next; - if (q6 == NULL) { - /* - * XXXJTL: This should never happen. This - * should turn into an assertion. - */ - IP6QB_UNLOCK(bucket); - continue; - } - while (q6 != head) { - --q6->ip6q_ttl; - q6 = q6->ip6q_next; - if (q6->ip6q_prev->ip6q_ttl == 0) { + TAILQ_FOREACH_SAFE(q6, head, ip6q_tq, q6tmp) + if (--q6->ip6q_ttl == 0) { IP6STAT_ADD(ip6s_fragtimeout, - q6->ip6q_prev->ip6q_nfrag); + q6->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(q6->ip6q_prev, bucket); + 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)) && - head->ip6q_prev != head) { - IP6STAT_ADD(ip6s_fragoverflow, - q6->ip6q_prev->ip6q_nfrag); + (q6 = TAILQ_LAST(head, ip6qhead)) != NULL) { + IP6STAT_ADD(ip6s_fragoverflow, q6->ip6q_nfrag); /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(head->ip6q_prev, bucket); + 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); - head = IP6QB_HEAD(bucket); - if (head->ip6q_prev != head) { - IP6STAT_ADD(ip6s_fragoverflow, - q6->ip6q_prev->ip6q_nfrag); + 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(head->ip6q_prev, bucket); + frag6_freef(q6, bucket); } IP6QB_UNLOCK(bucket); bucket = (bucket + 1) % IP6REASS_NHASH; } CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); } /* * 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) { - struct ip6q *q6; uint32_t bucket; V_ip6_maxfragpackets = IP6_MAXFRAGPACKETS; frag6_set_bucketsize(); for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { - q6 = IP6QB_HEAD(bucket); - q6->ip6q_next = q6->ip6q_prev = q6; - mtx_init(&V_ip6qb[bucket].lock, "ip6qlock", NULL, MTX_DEF); + 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); - struct ip6q *head; - uint32_t bucket; VNET_LIST_RLOCK_NOSLEEP(); VNET_FOREACH(vnet_iter) { CURVNET_SET(vnet_iter); - for (bucket = 0; bucket < IP6REASS_NHASH; bucket++) { - if (IP6QB_TRYLOCK(bucket) == 0) - continue; - head = IP6QB_HEAD(bucket); - while (head->ip6q_next != head) { - IP6STAT_INC(ip6s_fragdropped); - /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ - frag6_freef(head->ip6q_next, bucket); - } - IP6QB_UNLOCK(bucket); - } + frag6_drain_one(); CURVNET_RESTORE(); } VNET_LIST_RUNLOCK_NOSLEEP(); } +#ifdef VIMAGE /* - * Put an ip fragment on a reassembly chain. - * Like insque, but pointers in middle of structure. + * Clear up IPv6 reassembly structures. */ -static void -frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6, - uint32_t bucket __unused) +void +frag6_destroy(void) { + uint32_t bucket; - IP6QB_LOCK_ASSERT(bucket); - - af6->ip6af_up = up6; - af6->ip6af_down = up6->ip6af_down; - up6->ip6af_down->ip6af_up = af6; - up6->ip6af_down = af6; + 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); + } } - -/* - * To frag6_enq as remque is to insque. - */ -static void -frag6_deq(struct ip6asfrag *af6, uint32_t bucket __unused) -{ - - IP6QB_LOCK_ASSERT(bucket); - - af6->ip6af_up->ip6af_down = af6->ip6af_down; - af6->ip6af_down->ip6af_up = af6->ip6af_up; -} - -static void -frag6_insque_head(struct ip6q *new, struct ip6q *old, uint32_t bucket) -{ - - IP6QB_LOCK_ASSERT(bucket); - KASSERT(IP6QB_HEAD(bucket) == old, - ("%s: attempt to insert at head of wrong bucket" - " (bucket=%u, old=%p)", __func__, bucket, old)); - - new->ip6q_prev = old; - new->ip6q_next = old->ip6q_next; - old->ip6q_next->ip6q_prev= new; - old->ip6q_next = new; - V_ip6qb[bucket].count++; -} - -static void -frag6_remque(struct ip6q *p6, uint32_t bucket) -{ - - IP6QB_LOCK_ASSERT(bucket); - - p6->ip6q_prev->ip6q_next = p6->ip6q_next; - p6->ip6q_next->ip6q_prev = p6->ip6q_prev; - V_ip6qb[bucket].count--; -} +#endif Index: stable/12/sys/netinet6/ip6_input.c =================================================================== --- stable/12/sys/netinet6/ip6_input.c (revision 356490) +++ stable/12/sys/netinet6/ip6_input.c (revision 356491) @@ -1,1866 +1,1867 @@ /*- * 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_input.c,v 1.259 2002/01/21 04:58:09 jinmei Exp $ */ /*- * Copyright (c) 1982, 1986, 1988, 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_input.c 8.2 (Berkeley) 1/4/94 */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" #include "opt_route.h" #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 #include #include #include #include #include #include #include #ifdef INET #include #include #endif /* INET */ #include #include #include #include #include #include #include #include #include #include #include #include extern struct domain inet6domain; u_char ip6_protox[IPPROTO_MAX]; VNET_DEFINE(struct in6_ifaddrhead, in6_ifaddrhead); VNET_DEFINE(struct in6_ifaddrlisthead *, in6_ifaddrhashtbl); VNET_DEFINE(u_long, in6_ifaddrhmask); static struct netisr_handler ip6_nh = { .nh_name = "ip6", .nh_handler = ip6_input, .nh_proto = NETISR_IPV6, #ifdef RSS .nh_m2cpuid = rss_soft_m2cpuid_v6, .nh_policy = NETISR_POLICY_CPU, .nh_dispatch = NETISR_DISPATCH_HYBRID, #else .nh_policy = NETISR_POLICY_FLOW, #endif }; static int sysctl_netinet6_intr_queue_maxlen(SYSCTL_HANDLER_ARGS) { int error, qlimit; netisr_getqlimit(&ip6_nh, &qlimit); error = sysctl_handle_int(oidp, &qlimit, 0, req); if (error || !req->newptr) return (error); if (qlimit < 1) return (EINVAL); return (netisr_setqlimit(&ip6_nh, qlimit)); } SYSCTL_DECL(_net_inet6_ip6); SYSCTL_PROC(_net_inet6_ip6, IPV6CTL_INTRQMAXLEN, intr_queue_maxlen, CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_netinet6_intr_queue_maxlen, "I", "Maximum size of the IPv6 input queue"); #ifdef RSS static struct netisr_handler ip6_direct_nh = { .nh_name = "ip6_direct", .nh_handler = ip6_direct_input, .nh_proto = NETISR_IPV6_DIRECT, .nh_m2cpuid = rss_soft_m2cpuid_v6, .nh_policy = NETISR_POLICY_CPU, .nh_dispatch = NETISR_DISPATCH_HYBRID, }; static int sysctl_netinet6_intr_direct_queue_maxlen(SYSCTL_HANDLER_ARGS) { int error, qlimit; netisr_getqlimit(&ip6_direct_nh, &qlimit); error = sysctl_handle_int(oidp, &qlimit, 0, req); if (error || !req->newptr) return (error); if (qlimit < 1) return (EINVAL); return (netisr_setqlimit(&ip6_direct_nh, qlimit)); } SYSCTL_PROC(_net_inet6_ip6, IPV6CTL_INTRDQMAXLEN, intr_direct_queue_maxlen, CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_netinet6_intr_direct_queue_maxlen, "I", "Maximum size of the IPv6 direct input queue"); #endif VNET_DEFINE(struct pfil_head, inet6_pfil_hook); VNET_PCPUSTAT_DEFINE(struct ip6stat, ip6stat); VNET_PCPUSTAT_SYSINIT(ip6stat); #ifdef VIMAGE VNET_PCPUSTAT_SYSUNINIT(ip6stat); #endif /* VIMAGE */ struct rmlock in6_ifaddr_lock; RM_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock"); static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); #ifdef PULLDOWN_TEST static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); #endif /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. */ void ip6_init(void) { struct protosw *pr; int i; TUNABLE_INT_FETCH("net.inet6.ip6.auto_linklocal", &V_ip6_auto_linklocal); TUNABLE_INT_FETCH("net.inet6.ip6.accept_rtadv", &V_ip6_accept_rtadv); TUNABLE_INT_FETCH("net.inet6.ip6.no_radr", &V_ip6_no_radr); CK_STAILQ_INIT(&V_in6_ifaddrhead); V_in6_ifaddrhashtbl = hashinit(IN6ADDR_NHASH, M_IFADDR, &V_in6_ifaddrhmask); /* Initialize packet filter hooks. */ V_inet6_pfil_hook.ph_type = PFIL_TYPE_AF; V_inet6_pfil_hook.ph_af = AF_INET6; if ((i = pfil_head_register(&V_inet6_pfil_hook)) != 0) printf("%s: WARNING: unable to register pfil hook, " "error %d\n", __func__, i); if (hhook_head_register(HHOOK_TYPE_IPSEC_IN, AF_INET6, &V_ipsec_hhh_in[HHOOK_IPSEC_INET6], HHOOK_WAITOK | HHOOK_HEADISINVNET) != 0) printf("%s: WARNING: unable to register input helper hook\n", __func__); if (hhook_head_register(HHOOK_TYPE_IPSEC_OUT, AF_INET6, &V_ipsec_hhh_out[HHOOK_IPSEC_INET6], HHOOK_WAITOK | HHOOK_HEADISINVNET) != 0) printf("%s: WARNING: unable to register output helper hook\n", __func__); scope6_init(); addrsel_policy_init(); nd6_init(); frag6_init(); V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; /* Skip global initialization stuff for non-default instances. */ #ifdef VIMAGE if (!IS_DEFAULT_VNET(curvnet)) { netisr_register_vnet(&ip6_nh); #ifdef RSS netisr_register_vnet(&ip6_direct_nh); #endif return; } #endif pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == NULL) panic("ip6_init"); /* Initialize the entire ip6_protox[] array to IPPROTO_RAW. */ for (i = 0; i < IPPROTO_MAX; i++) ip6_protox[i] = pr - inet6sw; /* * Cycle through IP protocols and put them into the appropriate place * in ip6_protox[]. */ for (pr = inet6domain.dom_protosw; pr < inet6domain.dom_protoswNPROTOSW; pr++) if (pr->pr_domain->dom_family == PF_INET6 && pr->pr_protocol && pr->pr_protocol != IPPROTO_RAW) { /* Be careful to only index valid IP protocols. */ if (pr->pr_protocol < IPPROTO_MAX) ip6_protox[pr->pr_protocol] = pr - inet6sw; } netisr_register(&ip6_nh); #ifdef RSS netisr_register(&ip6_direct_nh); #endif } /* * The protocol to be inserted into ip6_protox[] must be already registered * in inet6sw[], either statically or through pf_proto_register(). */ int ip6proto_register(short ip6proto) { struct protosw *pr; /* Sanity checks. */ if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) return (EPROTONOSUPPORT); /* * The protocol slot must not be occupied by another protocol * already. An index pointing to IPPROTO_RAW is unused. */ pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == NULL) return (EPFNOSUPPORT); if (ip6_protox[ip6proto] != pr - inet6sw) /* IPPROTO_RAW */ return (EEXIST); /* * Find the protocol position in inet6sw[] and set the index. */ for (pr = inet6domain.dom_protosw; pr < inet6domain.dom_protoswNPROTOSW; pr++) { if (pr->pr_domain->dom_family == PF_INET6 && pr->pr_protocol && pr->pr_protocol == ip6proto) { ip6_protox[pr->pr_protocol] = pr - inet6sw; return (0); } } return (EPROTONOSUPPORT); } int ip6proto_unregister(short ip6proto) { struct protosw *pr; /* Sanity checks. */ if (ip6proto <= 0 || ip6proto >= IPPROTO_MAX) return (EPROTONOSUPPORT); /* Check if the protocol was indeed registered. */ pr = pffindproto(PF_INET6, IPPROTO_RAW, SOCK_RAW); if (pr == NULL) return (EPFNOSUPPORT); if (ip6_protox[ip6proto] == pr - inet6sw) /* IPPROTO_RAW */ return (ENOENT); /* Reset the protocol slot to IPPROTO_RAW. */ ip6_protox[ip6proto] = pr - inet6sw; return (0); } #ifdef VIMAGE static void ip6_destroy(void *unused __unused) { struct ifaddr *ifa, *nifa; struct ifnet *ifp; int error; #ifdef RSS netisr_unregister_vnet(&ip6_direct_nh); #endif netisr_unregister_vnet(&ip6_nh); if ((error = pfil_head_unregister(&V_inet6_pfil_hook)) != 0) printf("%s: WARNING: unable to unregister pfil hook, " "error %d\n", __func__, error); error = hhook_head_deregister(V_ipsec_hhh_in[HHOOK_IPSEC_INET6]); if (error != 0) { printf("%s: WARNING: unable to deregister input helper hook " "type HHOOK_TYPE_IPSEC_IN, id HHOOK_IPSEC_INET6: " "error %d returned\n", __func__, error); } error = hhook_head_deregister(V_ipsec_hhh_out[HHOOK_IPSEC_INET6]); if (error != 0) { printf("%s: WARNING: unable to deregister output helper hook " "type HHOOK_TYPE_IPSEC_OUT, id HHOOK_IPSEC_INET6: " "error %d returned\n", __func__, error); } /* Cleanup addresses. */ IFNET_RLOCK(); CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { /* Cannot lock here - lock recursion. */ /* IF_ADDR_LOCK(ifp); */ CK_STAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; in6_purgeaddr(ifa); } /* IF_ADDR_UNLOCK(ifp); */ in6_ifdetach_destroy(ifp); mld_domifdetach(ifp); /* Make sure any routes are gone as well. */ rt_flushifroutes_af(ifp, AF_INET6); } IFNET_RUNLOCK(); + frag6_destroy(); nd6_destroy(); in6_ifattach_destroy(); hashdestroy(V_in6_ifaddrhashtbl, M_IFADDR, V_in6_ifaddrhmask); } VNET_SYSUNINIT(inet6, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_destroy, NULL); #endif static int ip6_input_hbh(struct mbuf **mp, uint32_t *plen, uint32_t *rtalert, int *off, int *nxt, int *ours) { struct mbuf *m; struct ip6_hdr *ip6; struct ip6_hbh *hbh; if (ip6_hopopts_input(plen, rtalert, mp, off)) { #if 0 /*touches NULL pointer*/ in6_ifstat_inc((*mp)->m_pkthdr.rcvif, ifs6_in_discard); #endif goto out; /* m have already been freed */ } /* adjust pointer */ m = *mp; ip6 = mtod(m, struct ip6_hdr *); /* * if the payload length field is 0 and the next header field * indicates Hop-by-Hop Options header, then a Jumbo Payload * option MUST be included. */ if (ip6->ip6_plen == 0 && *plen == 0) { /* * Note that if a valid jumbo payload option is * contained, ip6_hopopts_input() must set a valid * (non-zero) payload length to the variable plen. */ IP6STAT_INC(ip6s_badoptions); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (caddr_t)&ip6->ip6_plen - (caddr_t)ip6); goto out; } #ifndef PULLDOWN_TEST /* ip6_hopopts_input() ensures that mbuf is contiguous */ hbh = (struct ip6_hbh *)(ip6 + 1); #else IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { IP6STAT_INC(ip6s_tooshort); goto out; } #endif *nxt = hbh->ip6h_nxt; /* * If we are acting as a router and the packet contains a * router alert option, see if we know the option value. * Currently, we only support the option value for MLD, in which * case we should pass the packet to the multicast routing * daemon. */ if (*rtalert != ~0) { switch (*rtalert) { case IP6OPT_RTALERT_MLD: if (V_ip6_forwarding) *ours = 1; break; default: /* * RFC2711 requires unrecognized values must be * silently ignored. */ break; } } return (0); out: return (1); } #ifdef RSS /* * IPv6 direct input routine. * * This is called when reinjecting completed fragments where * all of the previous checking and book-keeping has been done. */ void ip6_direct_input(struct mbuf *m) { int off, nxt; int nest; struct m_tag *mtag; struct ip6_direct_ctx *ip6dc; mtag = m_tag_locate(m, MTAG_ABI_IPV6, IPV6_TAG_DIRECT, NULL); KASSERT(mtag != NULL, ("Reinjected packet w/o direct ctx tag!")); ip6dc = (struct ip6_direct_ctx *)(mtag + 1); nxt = ip6dc->ip6dc_nxt; off = ip6dc->ip6dc_off; nest = 0; m_tag_delete(m, mtag); while (nxt != IPPROTO_DONE) { if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { IP6STAT_INC(ip6s_toomanyhdr); goto bad; } /* * protection against faulty packet - there should be * more sanity checks in header chain processing. */ if (m->m_pkthdr.len < off) { IP6STAT_INC(ip6s_tooshort); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } #if defined(IPSEC) || defined(IPSEC_SUPPORT) if (IPSEC_ENABLED(ipv6)) { if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) return; } #endif /* IPSEC */ nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; bad: m_freem(m); } #endif void ip6_input(struct mbuf *m) { struct in6_addr odst; struct ip6_hdr *ip6; struct in6_ifaddr *ia; struct ifnet *rcvif; u_int32_t plen; u_int32_t rtalert = ~0; int off = sizeof(struct ip6_hdr), nest; int nxt, ours = 0; int srcrt = 0; /* * Drop the packet if IPv6 operation is disabled on the interface. */ rcvif = m->m_pkthdr.rcvif; if ((ND_IFINFO(rcvif)->flags & ND6_IFF_IFDISABLED)) goto bad; #if defined(IPSEC) || defined(IPSEC_SUPPORT) /* * should the inner packet be considered authentic? * see comment in ah4_input(). * NB: m cannot be NULL when passed to the input routine */ m->m_flags &= ~M_AUTHIPHDR; m->m_flags &= ~M_AUTHIPDGM; #endif /* IPSEC */ if (m->m_flags & M_FASTFWD_OURS) { /* * Firewall changed destination to local. */ ip6 = mtod(m, struct ip6_hdr *); goto passin; } /* * mbuf statistics */ if (m->m_flags & M_EXT) { if (m->m_next) IP6STAT_INC(ip6s_mext2m); else IP6STAT_INC(ip6s_mext1); } else { if (m->m_next) { if (m->m_flags & M_LOOP) { IP6STAT_INC(ip6s_m2m[V_loif->if_index]); } else if (rcvif->if_index < IP6S_M2MMAX) IP6STAT_INC(ip6s_m2m[rcvif->if_index]); else IP6STAT_INC(ip6s_m2m[0]); } else IP6STAT_INC(ip6s_m1); } in6_ifstat_inc(rcvif, ifs6_in_receive); IP6STAT_INC(ip6s_total); #ifndef PULLDOWN_TEST /* * L2 bridge code and some other code can return mbuf chain * that does not conform to KAME requirement. too bad. * XXX: fails to join if interface MTU > MCLBYTES. jumbogram? */ if (m && m->m_next != NULL && m->m_pkthdr.len < MCLBYTES) { struct mbuf *n; if (m->m_pkthdr.len > MHLEN) n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); else n = m_gethdr(M_NOWAIT, MT_DATA); if (n == NULL) goto bad; m_move_pkthdr(n, m); m_copydata(m, 0, n->m_pkthdr.len, mtod(n, caddr_t)); n->m_len = n->m_pkthdr.len; m_freem(m); m = n; } IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */); #endif if (m->m_len < sizeof(struct ip6_hdr)) { if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { IP6STAT_INC(ip6s_toosmall); in6_ifstat_inc(rcvif, ifs6_in_hdrerr); goto bad; } } ip6 = mtod(m, struct ip6_hdr *); if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { IP6STAT_INC(ip6s_badvers); in6_ifstat_inc(rcvif, ifs6_in_hdrerr); goto bad; } IP6STAT_INC(ip6s_nxthist[ip6->ip6_nxt]); IP_PROBE(receive, NULL, NULL, ip6, rcvif, NULL, ip6); /* * Check against address spoofing/corruption. */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_dst)) { /* * XXX: "badscope" is not very suitable for a multicast source. */ IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) && !(m->m_flags & M_LOOP)) { /* * In this case, the packet should come from the loopback * interface. However, we cannot just check the if_flags, * because ip6_mloopback() passes the "actual" interface * as the outgoing/incoming interface. */ IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) && IPV6_ADDR_MC_SCOPE(&ip6->ip6_dst) == 0) { /* * RFC4291 2.7: * Nodes must not originate a packet to a multicast address * whose scop field contains the reserved value 0; if such * a packet is received, it must be silently dropped. */ IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } #ifdef ALTQ if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { /* packet is dropped by traffic conditioner */ return; } #endif /* * The following check is not documented in specs. A malicious * party may be able to use IPv4 mapped addr to confuse tcp/udp stack * and bypass security checks (act as if it was from 127.0.0.1 by using * IPv6 src ::ffff:127.0.0.1). Be cautious. * * This check chokes if we are in an SIIT cloud. As none of BSDs * support IPv4-less kernel compilation, we cannot support SIIT * environment at all. So, it makes more sense for us to reject any * malicious packets for non-SIIT environment, than try to do a * partial support for SIIT environment. */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } #if 0 /* * Reject packets with IPv4 compatible addresses (auto tunnel). * * The code forbids auto tunnel relay case in RFC1933 (the check is * stronger than RFC1933). We may want to re-enable it if mech-xx * is revised to forbid relaying case. */ if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } #endif /* * Try to forward the packet, but if we fail continue. * ip6_tryforward() does not generate redirects, so fall * through to normal processing if redirects are required. * ip6_tryforward() does inbound and outbound packet firewall * processing. If firewall has decided that destination becomes * our local address, it sets M_FASTFWD_OURS flag. In this * case skip another inbound firewall processing and update * ip6 pointer. */ if (V_ip6_forwarding != 0 && V_ip6_sendredirects == 0 #if defined(IPSEC) || defined(IPSEC_SUPPORT) && (!IPSEC_ENABLED(ipv6) || IPSEC_CAPS(ipv6, m, IPSEC_CAP_OPERABLE) == 0) #endif ) { if ((m = ip6_tryforward(m)) == NULL) return; if (m->m_flags & M_FASTFWD_OURS) { ip6 = mtod(m, struct ip6_hdr *); goto passin; } } #if defined(IPSEC) || defined(IPSEC_SUPPORT) /* * Bypass packet filtering for packets previously handled by IPsec. */ if (IPSEC_ENABLED(ipv6) && IPSEC_CAPS(ipv6, m, IPSEC_CAP_BYPASS_FILTER) != 0) goto passin; #endif /* * Run through list of hooks for input packets. * * NB: Beware of the destination address changing * (e.g. by NAT rewriting). When this happens, * tell ip6_forward to do the right thing. */ /* Jump over all PFIL processing if hooks are not active. */ if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passin; odst = ip6->ip6_dst; if (pfil_run_hooks(&V_inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, 0, NULL)) return; if (m == NULL) /* consumed by filter */ return; ip6 = mtod(m, struct ip6_hdr *); srcrt = !IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst); if ((m->m_flags & (M_IP6_NEXTHOP | M_FASTFWD_OURS)) == M_IP6_NEXTHOP && m_tag_find(m, PACKET_TAG_IPFORWARD, NULL) != NULL) { /* * Directly ship the packet on. This allows forwarding * packets originally destined to us to some other directly * connected host. */ ip6_forward(m, 1); return; } passin: /* * Disambiguate address scope zones (if there is ambiguity). * We first make sure that the original source or destination address * is not in our internal form for scoped addresses. Such addresses * are not necessarily invalid spec-wise, but we cannot accept them due * to the usage conflict. * in6_setscope() then also checks and rejects the cases where src or * dst are the loopback address and the receiving interface * is not loopback. */ if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); /* XXX */ goto bad; } if (in6_setscope(&ip6->ip6_src, rcvif, NULL) || in6_setscope(&ip6->ip6_dst, rcvif, NULL)) { IP6STAT_INC(ip6s_badscope); goto bad; } if (m->m_flags & M_FASTFWD_OURS) { m->m_flags &= ~M_FASTFWD_OURS; ours = 1; goto hbhcheck; } /* * Multicast check. Assume packet is for us to avoid * prematurely taking locks. */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { ours = 1; in6_ifstat_inc(rcvif, ifs6_in_mcast); goto hbhcheck; } /* * Unicast check * XXX: For now we keep link-local IPv6 addresses with embedded * scope zone id, therefore we use zero zoneid here. */ ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); if (ia != NULL) { if (ia->ia6_flags & IN6_IFF_NOTREADY) { char ip6bufs[INET6_ADDRSTRLEN]; char ip6bufd[INET6_ADDRSTRLEN]; /* address is not ready, so discard the packet. */ nd6log((LOG_INFO, "ip6_input: packet to an unready address %s->%s\n", ip6_sprintf(ip6bufs, &ip6->ip6_src), ip6_sprintf(ip6bufd, &ip6->ip6_dst))); ifa_free(&ia->ia_ifa); goto bad; } /* Count the packet in the ip address stats */ counter_u64_add(ia->ia_ifa.ifa_ipackets, 1); counter_u64_add(ia->ia_ifa.ifa_ibytes, m->m_pkthdr.len); ifa_free(&ia->ia_ifa); ours = 1; goto hbhcheck; } /* * Now there is no reason to process the packet if it's not our own * and we're not a router. */ if (!V_ip6_forwarding) { IP6STAT_INC(ip6s_cantforward); goto bad; } hbhcheck: /* * Process Hop-by-Hop options header if it's contained. * m may be modified in ip6_hopopts_input(). * If a JumboPayload option is included, plen will also be modified. */ plen = (u_int32_t)ntohs(ip6->ip6_plen); if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { if (ip6_input_hbh(&m, &plen, &rtalert, &off, &nxt, &ours) != 0) return; } else nxt = ip6->ip6_nxt; /* * Use mbuf flags to propagate Router Alert option to * ICMPv6 layer, as hop-by-hop options have been stripped. */ if (rtalert != ~0) m->m_flags |= M_RTALERT_MLD; /* * Check that the amount of data in the buffers * is as at least much as the IPv6 header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { IP6STAT_INC(ip6s_tooshort); in6_ifstat_inc(rcvif, ifs6_in_truncated); goto bad; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { if (m->m_len == m->m_pkthdr.len) { m->m_len = sizeof(struct ip6_hdr) + plen; m->m_pkthdr.len = sizeof(struct ip6_hdr) + plen; } else m_adj(m, sizeof(struct ip6_hdr) + plen - m->m_pkthdr.len); } /* * Forward if desirable. */ if (V_ip6_mrouter && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { /* * If we are acting as a multicast router, all * incoming multicast packets are passed to the * kernel-level multicast forwarding function. * The packet is returned (relatively) intact; if * ip6_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. * * XXX TODO: Check hlim and multicast scope here to avoid * unnecessarily calling into ip6_mforward(). */ if (ip6_mforward && ip6_mforward(ip6, rcvif, m)) { IP6STAT_INC(ip6s_cantforward); goto bad; } } else if (!ours) { ip6_forward(m, srcrt); return; } ip6 = mtod(m, struct ip6_hdr *); /* * Malicious party may be able to use IPv4 mapped addr to confuse * tcp/udp stack and bypass security checks (act as if it was from * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious. * * For SIIT end node behavior, you may want to disable the check. * However, you will become vulnerable to attacks using IPv4 mapped * source. */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6STAT_INC(ip6s_badscope); in6_ifstat_inc(rcvif, ifs6_in_addrerr); goto bad; } /* * Tell launch routine the next header */ IP6STAT_INC(ip6s_delivered); in6_ifstat_inc(rcvif, ifs6_in_deliver); nest = 0; while (nxt != IPPROTO_DONE) { if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) { IP6STAT_INC(ip6s_toomanyhdr); goto bad; } /* * protection against faulty packet - there should be * more sanity checks in header chain processing. */ if (m->m_pkthdr.len < off) { IP6STAT_INC(ip6s_tooshort); in6_ifstat_inc(rcvif, ifs6_in_truncated); goto bad; } #if defined(IPSEC) || defined(IPSEC_SUPPORT) if (IPSEC_ENABLED(ipv6)) { if (IPSEC_INPUT(ipv6, m, off, nxt) != 0) return; } #endif /* IPSEC */ nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt); } return; bad: in6_ifstat_inc(rcvif, ifs6_in_discard); if (m != NULL) m_freem(m); } /* * Hop-by-Hop options header processing. If a valid jumbo payload option is * included, the real payload length will be stored in plenp. * * rtalertp - XXX: should be stored more smart way */ static int ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp, struct mbuf **mp, int *offp) { struct mbuf *m = *mp; int off = *offp, hbhlen; struct ip6_hbh *hbh; /* validation of the length of the header */ #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1); hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); hbhlen = (hbh->ip6h_len + 1) << 3; IP6_EXTHDR_CHECK(m, off, hbhlen, -1); hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off); #else IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { IP6STAT_INC(ip6s_tooshort); return -1; } hbhlen = (hbh->ip6h_len + 1) << 3; IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), hbhlen); if (hbh == NULL) { IP6STAT_INC(ip6s_tooshort); return -1; } #endif off += hbhlen; hbhlen -= sizeof(struct ip6_hbh); if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh), hbhlen, rtalertp, plenp) < 0) return (-1); *offp = off; *mp = m; return (0); } /* * Search header for all Hop-by-hop options and process each option. * This function is separate from ip6_hopopts_input() in order to * handle a case where the sending node itself process its hop-by-hop * options header. In such a case, the function is called from ip6_output(). * * The function assumes that hbh header is located right after the IPv6 header * (RFC2460 p7), opthead is pointer into data content in m, and opthead to * opthead + hbhlen is located in contiguous memory region. */ int ip6_process_hopopts(struct mbuf *m, u_int8_t *opthead, int hbhlen, u_int32_t *rtalertp, u_int32_t *plenp) { struct ip6_hdr *ip6; int optlen = 0; u_int8_t *opt = opthead; u_int16_t rtalert_val; u_int32_t jumboplen; const int erroff = sizeof(struct ip6_hdr) + sizeof(struct ip6_hbh); for (; hbhlen > 0; hbhlen -= optlen, opt += optlen) { switch (*opt) { case IP6OPT_PAD1: optlen = 1; break; case IP6OPT_PADN: if (hbhlen < IP6OPT_MINLEN) { IP6STAT_INC(ip6s_toosmall); goto bad; } optlen = *(opt + 1) + 2; break; case IP6OPT_ROUTER_ALERT: /* XXX may need check for alignment */ if (hbhlen < IP6OPT_RTALERT_LEN) { IP6STAT_INC(ip6s_toosmall); goto bad; } if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { /* XXX stat */ icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 1 - opthead); return (-1); } optlen = IP6OPT_RTALERT_LEN; bcopy((caddr_t)(opt + 2), (caddr_t)&rtalert_val, 2); *rtalertp = ntohs(rtalert_val); break; case IP6OPT_JUMBO: /* XXX may need check for alignment */ if (hbhlen < IP6OPT_JUMBO_LEN) { IP6STAT_INC(ip6s_toosmall); goto bad; } if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { /* XXX stat */ icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 1 - opthead); return (-1); } optlen = IP6OPT_JUMBO_LEN; /* * IPv6 packets that have non 0 payload length * must not contain a jumbo payload option. */ ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_plen) { IP6STAT_INC(ip6s_badoptions); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt - opthead); return (-1); } /* * We may see jumbolen in unaligned location, so * we'd need to perform bcopy(). */ bcopy(opt + 2, &jumboplen, sizeof(jumboplen)); jumboplen = (u_int32_t)htonl(jumboplen); #if 1 /* * if there are multiple jumbo payload options, * *plenp will be non-zero and the packet will be * rejected. * the behavior may need some debate in ipngwg - * multiple options does not make sense, however, * there's no explicit mention in specification. */ if (*plenp != 0) { IP6STAT_INC(ip6s_badoptions); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 2 - opthead); return (-1); } #endif /* * jumbo payload length must be larger than 65535. */ if (jumboplen <= IPV6_MAXPACKET) { IP6STAT_INC(ip6s_badoptions); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 2 - opthead); return (-1); } *plenp = jumboplen; break; default: /* unknown option */ if (hbhlen < IP6OPT_MINLEN) { IP6STAT_INC(ip6s_toosmall); goto bad; } optlen = ip6_unknown_opt(opt, m, erroff + opt - opthead); if (optlen == -1) return (-1); optlen += 2; break; } } return (0); bad: m_freem(m); return (-1); } /* * Unknown option processing. * The third argument `off' is the offset from the IPv6 header to the option, * which is necessary if the IPv6 header the and option header and IPv6 header * is not contiguous in order to return an ICMPv6 error. */ int ip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off) { struct ip6_hdr *ip6; switch (IP6OPT_TYPE(*optp)) { case IP6OPT_TYPE_SKIP: /* ignore the option */ return ((int)*(optp + 1)); case IP6OPT_TYPE_DISCARD: /* silently discard */ m_freem(m); return (-1); case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ IP6STAT_INC(ip6s_badoptions); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); return (-1); case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ IP6STAT_INC(ip6s_badoptions); ip6 = mtod(m, struct ip6_hdr *); if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || (m->m_flags & (M_BCAST|M_MCAST))) m_freem(m); else icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); return (-1); } m_freem(m); /* XXX: NOTREACHED */ return (-1); } /* * Create the "control" list for this pcb. * These functions will not modify mbuf chain at all. * * With KAME mbuf chain restriction: * The routine will be called from upper layer handlers like tcp6_input(). * Thus the routine assumes that the caller (tcp6_input) have already * called IP6_EXTHDR_CHECK() and all the extension headers are located in the * very first mbuf on the mbuf chain. * * ip6_savecontrol_v4 will handle those options that are possible to be * set on a v4-mapped socket. * ip6_savecontrol will directly call ip6_savecontrol_v4 to handle those * options and handle the v6-only ones itself. */ struct mbuf ** ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp, int *v4only) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); #ifdef SO_TIMESTAMP if ((inp->inp_socket->so_options & SO_TIMESTAMP) != 0) { union { struct timeval tv; struct bintime bt; struct timespec ts; } t; struct bintime boottimebin, bt1; struct timespec ts1; bool stamped; stamped = false; switch (inp->inp_socket->so_ts_clock) { case SO_TS_REALTIME_MICRO: if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR | M_TSTMP)) { mbuf_tstmp2timespec(m, &ts1); timespec2bintime(&ts1, &bt1); getboottimebin(&boottimebin); bintime_add(&bt1, &boottimebin); bintime2timeval(&bt1, &t.tv); } else { microtime(&t.tv); } *mp = sbcreatecontrol((caddr_t) &t.tv, sizeof(t.tv), SCM_TIMESTAMP, SOL_SOCKET); if (*mp != NULL) { mp = &(*mp)->m_next; stamped = true; } break; case SO_TS_BINTIME: if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR | M_TSTMP)) { mbuf_tstmp2timespec(m, &ts1); timespec2bintime(&ts1, &t.bt); getboottimebin(&boottimebin); bintime_add(&t.bt, &boottimebin); } else { bintime(&t.bt); } *mp = sbcreatecontrol((caddr_t)&t.bt, sizeof(t.bt), SCM_BINTIME, SOL_SOCKET); if (*mp != NULL) { mp = &(*mp)->m_next; stamped = true; } break; case SO_TS_REALTIME: if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR | M_TSTMP)) { mbuf_tstmp2timespec(m, &t.ts); getboottimebin(&boottimebin); bintime2timespec(&boottimebin, &ts1); timespecadd(&t.ts, &ts1, &t.ts); } else { nanotime(&t.ts); } *mp = sbcreatecontrol((caddr_t)&t.ts, sizeof(t.ts), SCM_REALTIME, SOL_SOCKET); if (*mp != NULL) { mp = &(*mp)->m_next; stamped = true; } break; case SO_TS_MONOTONIC: if ((m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR | M_TSTMP)) mbuf_tstmp2timespec(m, &t.ts); else nanouptime(&t.ts); *mp = sbcreatecontrol((caddr_t)&t.ts, sizeof(t.ts), SCM_MONOTONIC, SOL_SOCKET); if (*mp != NULL) { mp = &(*mp)->m_next; stamped = true; } break; default: panic("unknown (corrupted) so_ts_clock"); } if (stamped && (m->m_flags & (M_PKTHDR | M_TSTMP)) == (M_PKTHDR | M_TSTMP)) { struct sock_timestamp_info sti; bzero(&sti, sizeof(sti)); sti.st_info_flags = ST_INFO_HW; if ((m->m_flags & M_TSTMP_HPREC) != 0) sti.st_info_flags |= ST_INFO_HW_HPREC; *mp = sbcreatecontrol((caddr_t)&sti, sizeof(sti), SCM_TIME_INFO, SOL_SOCKET); if (*mp != NULL) mp = &(*mp)->m_next; } } #endif #define IS2292(inp, x, y) (((inp)->inp_flags & IN6P_RFC2292) ? (x) : (y)) /* RFC 2292 sec. 5 */ if ((inp->inp_flags & IN6P_PKTINFO) != 0) { struct in6_pktinfo pi6; if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { #ifdef INET struct ip *ip; ip = mtod(m, struct ip *); pi6.ipi6_addr.s6_addr32[0] = 0; pi6.ipi6_addr.s6_addr32[1] = 0; pi6.ipi6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; pi6.ipi6_addr.s6_addr32[3] = ip->ip_dst.s_addr; #else /* We won't hit this code */ bzero(&pi6.ipi6_addr, sizeof(struct in6_addr)); #endif } else { bcopy(&ip6->ip6_dst, &pi6.ipi6_addr, sizeof(struct in6_addr)); in6_clearscope(&pi6.ipi6_addr); /* XXX */ } pi6.ipi6_ifindex = (m && m->m_pkthdr.rcvif) ? m->m_pkthdr.rcvif->if_index : 0; *mp = sbcreatecontrol((caddr_t) &pi6, sizeof(struct in6_pktinfo), IS2292(inp, IPV6_2292PKTINFO, IPV6_PKTINFO), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } if ((inp->inp_flags & IN6P_HOPLIMIT) != 0) { int hlim; if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { #ifdef INET struct ip *ip; ip = mtod(m, struct ip *); hlim = ip->ip_ttl; #else /* We won't hit this code */ hlim = 0; #endif } else { hlim = ip6->ip6_hlim & 0xff; } *mp = sbcreatecontrol((caddr_t) &hlim, sizeof(int), IS2292(inp, IPV6_2292HOPLIMIT, IPV6_HOPLIMIT), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } if ((inp->inp_flags & IN6P_TCLASS) != 0) { int tclass; if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { #ifdef INET struct ip *ip; ip = mtod(m, struct ip *); tclass = ip->ip_tos; #else /* We won't hit this code */ tclass = 0; #endif } else { u_int32_t flowinfo; flowinfo = (u_int32_t)ntohl(ip6->ip6_flow & IPV6_FLOWINFO_MASK); flowinfo >>= 20; tclass = flowinfo & 0xff; } *mp = sbcreatecontrol((caddr_t) &tclass, sizeof(int), IPV6_TCLASS, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } if (v4only != NULL) { if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { *v4only = 1; } else { *v4only = 0; } } return (mp); } void ip6_savecontrol(struct inpcb *inp, struct mbuf *m, struct mbuf **mp) { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); int v4only = 0; mp = ip6_savecontrol_v4(inp, m, mp, &v4only); if (v4only) return; /* * IPV6_HOPOPTS socket option. Recall that we required super-user * privilege for the option (see ip6_ctloutput), but it might be too * strict, since there might be some hop-by-hop options which can be * returned to normal user. * See also RFC 2292 section 6 (or RFC 3542 section 8). */ if ((inp->inp_flags & IN6P_HOPOPTS) != 0) { /* * Check if a hop-by-hop options header is contatined in the * received packet, and if so, store the options as ancillary * data. Note that a hop-by-hop options header must be * just after the IPv6 header, which is assured through the * IPv6 input processing. */ if (ip6->ip6_nxt == IPPROTO_HOPOPTS) { struct ip6_hbh *hbh; int hbhlen = 0; #ifdef PULLDOWN_TEST struct mbuf *ext; #endif #ifndef PULLDOWN_TEST hbh = (struct ip6_hbh *)(ip6 + 1); hbhlen = (hbh->ip6h_len + 1) << 3; #else ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), ip6->ip6_nxt); if (ext == NULL) { IP6STAT_INC(ip6s_tooshort); return; } hbh = mtod(ext, struct ip6_hbh *); hbhlen = (hbh->ip6h_len + 1) << 3; if (hbhlen != ext->m_len) { m_freem(ext); IP6STAT_INC(ip6s_tooshort); return; } #endif /* * XXX: We copy the whole header even if a * jumbo payload option is included, the option which * is to be removed before returning according to * RFC2292. * Note: this constraint is removed in RFC3542 */ *mp = sbcreatecontrol((caddr_t)hbh, hbhlen, IS2292(inp, IPV6_2292HOPOPTS, IPV6_HOPOPTS), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; #ifdef PULLDOWN_TEST m_freem(ext); #endif } } if ((inp->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) { int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr); /* * Search for destination options headers or routing * header(s) through the header chain, and stores each * header as ancillary data. * Note that the order of the headers remains in * the chain of ancillary data. */ while (1) { /* is explicit loop prevention necessary? */ struct ip6_ext *ip6e = NULL; int elen; #ifdef PULLDOWN_TEST struct mbuf *ext = NULL; #endif /* * if it is not an extension header, don't try to * pull it from the chain. */ switch (nxt) { case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: case IPPROTO_AH: /* is it possible? */ break; default: goto loopend; } #ifndef PULLDOWN_TEST if (off + sizeof(*ip6e) > m->m_len) goto loopend; ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; if (off + elen > m->m_len) goto loopend; #else ext = ip6_pullexthdr(m, off, nxt); if (ext == NULL) { IP6STAT_INC(ip6s_tooshort); return; } ip6e = mtod(ext, struct ip6_ext *); if (nxt == IPPROTO_AH) elen = (ip6e->ip6e_len + 2) << 2; else elen = (ip6e->ip6e_len + 1) << 3; if (elen != ext->m_len) { m_freem(ext); IP6STAT_INC(ip6s_tooshort); return; } #endif switch (nxt) { case IPPROTO_DSTOPTS: if (!(inp->inp_flags & IN6P_DSTOPTS)) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, IS2292(inp, IPV6_2292DSTOPTS, IPV6_DSTOPTS), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; break; case IPPROTO_ROUTING: if (!(inp->inp_flags & IN6P_RTHDR)) break; *mp = sbcreatecontrol((caddr_t)ip6e, elen, IS2292(inp, IPV6_2292RTHDR, IPV6_RTHDR), IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; break; case IPPROTO_HOPOPTS: case IPPROTO_AH: /* is it possible? */ break; default: /* * other cases have been filtered in the above. * none will visit this case. here we supply * the code just in case (nxt overwritten or * other cases). */ #ifdef PULLDOWN_TEST m_freem(ext); #endif goto loopend; } /* proceed with the next header. */ off += elen; nxt = ip6e->ip6e_nxt; ip6e = NULL; #ifdef PULLDOWN_TEST m_freem(ext); ext = NULL; #endif } loopend: ; } if (inp->inp_flags2 & INP_RECVFLOWID) { uint32_t flowid, flow_type; flowid = m->m_pkthdr.flowid; flow_type = M_HASHTYPE_GET(m); /* * XXX should handle the failure of one or the * other - don't populate both? */ *mp = sbcreatecontrol((caddr_t) &flowid, sizeof(uint32_t), IPV6_FLOWID, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; *mp = sbcreatecontrol((caddr_t) &flow_type, sizeof(uint32_t), IPV6_FLOWTYPE, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } #ifdef RSS if (inp->inp_flags2 & INP_RECVRSSBUCKETID) { uint32_t flowid, flow_type; uint32_t rss_bucketid; flowid = m->m_pkthdr.flowid; flow_type = M_HASHTYPE_GET(m); if (rss_hash2bucket(flowid, flow_type, &rss_bucketid) == 0) { *mp = sbcreatecontrol((caddr_t) &rss_bucketid, sizeof(uint32_t), IPV6_RSSBUCKETID, IPPROTO_IPV6); if (*mp) mp = &(*mp)->m_next; } } #endif } #undef IS2292 void ip6_notify_pmtu(struct inpcb *inp, struct sockaddr_in6 *dst, u_int32_t mtu) { struct socket *so; struct mbuf *m_mtu; struct ip6_mtuinfo mtuctl; KASSERT(inp != NULL, ("%s: inp == NULL", __func__)); /* * Notify the error by sending IPV6_PATHMTU ancillary data if * application wanted to know the MTU value. * NOTE: we notify disconnected sockets, because some udp * applications keep sending sockets disconnected. * NOTE: our implementation doesn't notify connected sockets that has * foreign address that is different than given destination addresses * (this is permitted by RFC 3542). */ if ((inp->inp_flags & IN6P_MTU) == 0 || ( !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, &dst->sin6_addr))) return; mtuctl.ip6m_mtu = mtu; mtuctl.ip6m_addr = *dst; if (sa6_recoverscope(&mtuctl.ip6m_addr)) return; if ((m_mtu = sbcreatecontrol((caddr_t)&mtuctl, sizeof(mtuctl), IPV6_PATHMTU, IPPROTO_IPV6)) == NULL) return; so = inp->inp_socket; if (sbappendaddr(&so->so_rcv, (struct sockaddr *)dst, NULL, m_mtu) == 0) { m_freem(m_mtu); /* XXX: should count statistics */ } else sorwakeup(so); } #ifdef PULLDOWN_TEST /* * pull single extension header from mbuf chain. returns single mbuf that * contains the result, or NULL on error. */ static struct mbuf * ip6_pullexthdr(struct mbuf *m, size_t off, int nxt) { struct ip6_ext ip6e; size_t elen; struct mbuf *n; #ifdef DIAGNOSTIC switch (nxt) { case IPPROTO_DSTOPTS: case IPPROTO_ROUTING: case IPPROTO_HOPOPTS: case IPPROTO_AH: /* is it possible? */ break; default: printf("ip6_pullexthdr: invalid nxt=%d\n", nxt); } #endif m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); if (nxt == IPPROTO_AH) elen = (ip6e.ip6e_len + 2) << 2; else elen = (ip6e.ip6e_len + 1) << 3; if (elen > MLEN) n = m_getcl(M_NOWAIT, MT_DATA, 0); else n = m_get(M_NOWAIT, MT_DATA); if (n == NULL) return NULL; m_copydata(m, off, elen, mtod(n, caddr_t)); n->m_len = elen; return n; } #endif /* * Get pointer to the previous header followed by the header * currently processed. */ int ip6_get_prevhdr(const struct mbuf *m, int off) { struct ip6_ext ip6e; struct ip6_hdr *ip6; int len, nlen, nxt; if (off == sizeof(struct ip6_hdr)) return (offsetof(struct ip6_hdr, ip6_nxt)); if (off < sizeof(struct ip6_hdr)) panic("%s: off < sizeof(struct ip6_hdr)", __func__); ip6 = mtod(m, struct ip6_hdr *); nxt = ip6->ip6_nxt; len = sizeof(struct ip6_hdr); nlen = 0; while (len < off) { m_copydata(m, len, sizeof(ip6e), (caddr_t)&ip6e); switch (nxt) { case IPPROTO_FRAGMENT: nlen = sizeof(struct ip6_frag); break; case IPPROTO_AH: nlen = (ip6e.ip6e_len + 2) << 2; break; default: nlen = (ip6e.ip6e_len + 1) << 3; } len += nlen; nxt = ip6e.ip6e_nxt; } return (len - nlen); } /* * get next header offset. m will be retained. */ int ip6_nexthdr(const struct mbuf *m, int off, int proto, int *nxtp) { struct ip6_hdr ip6; struct ip6_ext ip6e; struct ip6_frag fh; /* just in case */ if (m == NULL) panic("ip6_nexthdr: m == NULL"); if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len < off) return -1; switch (proto) { case IPPROTO_IPV6: if (m->m_pkthdr.len < off + sizeof(ip6)) return -1; m_copydata(m, off, sizeof(ip6), (caddr_t)&ip6); if (nxtp) *nxtp = ip6.ip6_nxt; off += sizeof(ip6); return off; case IPPROTO_FRAGMENT: /* * terminate parsing if it is not the first fragment, * it does not make sense to parse through it. */ if (m->m_pkthdr.len < off + sizeof(fh)) return -1; m_copydata(m, off, sizeof(fh), (caddr_t)&fh); /* IP6F_OFF_MASK = 0xfff8(BigEndian), 0xf8ff(LittleEndian) */ if (fh.ip6f_offlg & IP6F_OFF_MASK) return -1; if (nxtp) *nxtp = fh.ip6f_nxt; off += sizeof(struct ip6_frag); return off; case IPPROTO_AH: if (m->m_pkthdr.len < off + sizeof(ip6e)) return -1; m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); if (nxtp) *nxtp = ip6e.ip6e_nxt; off += (ip6e.ip6e_len + 2) << 2; return off; case IPPROTO_HOPOPTS: case IPPROTO_ROUTING: case IPPROTO_DSTOPTS: if (m->m_pkthdr.len < off + sizeof(ip6e)) return -1; m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e); if (nxtp) *nxtp = ip6e.ip6e_nxt; off += (ip6e.ip6e_len + 1) << 3; return off; case IPPROTO_NONE: case IPPROTO_ESP: case IPPROTO_IPCOMP: /* give up */ return -1; default: return -1; } /* NOTREACHED */ } /* * get offset for the last header in the chain. m will be kept untainted. */ int ip6_lasthdr(const struct mbuf *m, int off, int proto, int *nxtp) { int newoff; int nxt; if (!nxtp) { nxt = -1; nxtp = &nxt; } while (1) { newoff = ip6_nexthdr(m, off, proto, nxtp); if (newoff < 0) return off; else if (newoff < off) return -1; /* invalid */ else if (newoff == off) return newoff; off = newoff; proto = *nxtp; } } /* * System control for IP6 */ u_char inet6ctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, EHOSTUNREACH, 0, ENOPROTOOPT, ECONNREFUSED }; Index: stable/12/sys/netinet6/ip6_var.h =================================================================== --- stable/12/sys/netinet6/ip6_var.h (revision 356490) +++ stable/12/sys/netinet6/ip6_var.h (revision 356491) @@ -1,431 +1,420 @@ /*- * 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 ip6asfrag *ip6q_down; - struct ip6asfrag *ip6q_up; + struct ip6fraghead ip6q_frags; u_int32_t ip6q_ident; u_int8_t ip6q_nxt; u_int8_t ip6q_ecn; u_int8_t ip6q_ttl; struct in6_addr ip6q_src, ip6q_dst; - struct ip6q *ip6q_next; - struct ip6q *ip6q_prev; + TAILQ_ENTRY(ip6q) ip6q_tq; int ip6q_unfrglen; /* len of unfragmentable part */ -#ifdef notyet - u_char *ip6q_nxtp; -#endif int ip6q_nfrag; /* # of fragments */ struct label *ip6q_label; }; +#endif /* _KERNEL */ -struct ip6asfrag { - struct ip6asfrag *ip6af_down; - struct ip6asfrag *ip6af_up; - 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 */ - u_int16_t ip6af_mff; /* more fragment bit in frag off */ -}; - -#define IP6_REASS_MBUF(ip6af) (*(struct mbuf **)&((ip6af)->ip6af_m)) - /* * 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_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_log_interval); VNET_DECLARE(time_t, ip6_log_time); 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_log_interval VNET(ip6_log_interval) #define V_ip6_log_time VNET(ip6_log_time) #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_hook); /* packet filter hooks */ #define V_inet6_pfil_hook VNET(inet6_pfil_hook) #ifdef IPSTEALTH VNET_DECLARE(int, ip6stealth); #define V_ip6stealth VNET(ip6stealth) #endif extern struct pr_usrreqs rip6_usrreqs; struct sockopt; struct inpcb; int icmp6_ctloutput(struct socket *, struct sockopt *sopt); struct in6_ifaddr; void ip6_init(void); int ip6proto_register(short); int ip6proto_unregister(short); 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_slowtimo(void); void frag6_drain(void); void rip6_init(void); int rip6_input(struct mbuf **, int *, int); void rip6_ctlinput(int, struct sockaddr *, void *); int rip6_ctloutput(struct socket *, struct sockopt *); int rip6_output(struct mbuf *, struct socket *, ...); 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 rtentry **); int in6_selectroute_fib(struct sockaddr_in6 *, struct ip6_pktopts *, struct ip6_moptions *, struct route_in6 *, struct ifnet **, struct rtentry **, u_int); 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); #endif /* _KERNEL */ #endif /* !_NETINET6_IP6_VAR_H_ */ Index: stable/12/tests/sys/Makefile =================================================================== --- stable/12/tests/sys/Makefile (revision 356490) +++ stable/12/tests/sys/Makefile (revision 356491) @@ -1,44 +1,45 @@ # $FreeBSD$ .include TESTSDIR= ${TESTSBASE}/sys TESTS_SUBDIRS+= acl TESTS_SUBDIRS+= aio TESTS_SUBDIRS+= ${_audit} TESTS_SUBDIRS+= auditpipe TESTS_SUBDIRS+= capsicum TESTS_SUBDIRS+= ${_cddl} TESTS_SUBDIRS+= fifo TESTS_SUBDIRS+= file TESTS_SUBDIRS+= fs TESTS_SUBDIRS+= geom TESTS_SUBDIRS+= kern TESTS_SUBDIRS+= kqueue TESTS_SUBDIRS+= mac TESTS_SUBDIRS+= mqueue TESTS_SUBDIRS+= netinet +TESTS_SUBDIRS+= netinet6 TESTS_SUBDIRS+= netipsec TESTS_SUBDIRS+= netmap TESTS_SUBDIRS+= netpfil TESTS_SUBDIRS+= opencrypto TESTS_SUBDIRS+= posixshm TESTS_SUBDIRS+= sys TESTS_SUBDIRS+= vfs TESTS_SUBDIRS+= vm .if ${MK_AUDIT} != "no" _audit= audit .endif .if ${MK_CDDL} != "no" _cddl= cddl .endif # Items not integrated into kyua runs by default SUBDIR+= pjdfstest SUBDIR+= common .include Index: stable/12/tests/sys/netinet6/frag6/Makefile =================================================================== --- stable/12/tests/sys/netinet6/frag6/Makefile (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/Makefile (revision 356491) @@ -0,0 +1,79 @@ +# $FreeBSD$ + +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/netinet6/frag6 +FILESDIR= ${TESTSDIR} + +# We split these up so they can run in parallel. +# Seems kyua is not running the test cases from one file in parallel. +# Otherwise we could cat the files together into one shell file. +ATF_TESTS_SH= \ + frag6_01 \ + frag6_02 \ + frag6_03 \ + frag6_04 \ + frag6_05 \ + frag6_06 \ + frag6_07 \ + frag6_08 \ + frag6_09 \ + frag6_10 \ + frag6_11 \ + frag6_12 \ + frag6_13 \ + frag6_14 \ + frag6_15 \ + frag6_16 \ + frag6_17 \ + frag6_18 \ + frag6_19 \ + frag6_20 + +${PACKAGE}FILES+= frag6.subr +${PACKAGE}FILES+= sniffer.py +${PACKAGE}FILES+= frag6_01.py +${PACKAGE}FILES+= frag6_02.py +${PACKAGE}FILES+= frag6_03.py +${PACKAGE}FILES+= frag6_04.py +${PACKAGE}FILES+= frag6_05.py +${PACKAGE}FILES+= frag6_06.py +${PACKAGE}FILES+= frag6_07.py +${PACKAGE}FILES+= frag6_08.py +${PACKAGE}FILES+= frag6_09.py +${PACKAGE}FILES+= frag6_10.py +${PACKAGE}FILES+= frag6_11.py +${PACKAGE}FILES+= frag6_12.py +${PACKAGE}FILES+= frag6_13.py +${PACKAGE}FILES+= frag6_14.py +${PACKAGE}FILES+= frag6_15.py +${PACKAGE}FILES+= frag6_16.py +${PACKAGE}FILES+= frag6_17.py +${PACKAGE}FILES+= frag6_18.py +${PACKAGE}FILES+= frag6_19.py +${PACKAGE}FILES+= frag6_20.py + +${PACKAGE}FILESMODE_frag6.subr= 0444 +${PACKAGE}FILESMODE_sniffer.py= 0555 +${PACKAGE}FILESMODE_frag6_01.py= 0555 +${PACKAGE}FILESMODE_frag6_02.py= 0555 +${PACKAGE}FILESMODE_frag6_03.py= 0555 +${PACKAGE}FILESMODE_frag6_04.py= 0555 +${PACKAGE}FILESMODE_frag6_05.py= 0555 +${PACKAGE}FILESMODE_frag6_06.py= 0555 +${PACKAGE}FILESMODE_frag6_07.py= 0555 +${PACKAGE}FILESMODE_frag6_08.py= 0555 +${PACKAGE}FILESMODE_frag6_09.py= 0555 +${PACKAGE}FILESMODE_frag6_10.py= 0555 +${PACKAGE}FILESMODE_frag6_11.py= 0555 +${PACKAGE}FILESMODE_frag6_12.py= 0555 +${PACKAGE}FILESMODE_frag6_13.py= 0555 +${PACKAGE}FILESMODE_frag6_14.py= 0555 +${PACKAGE}FILESMODE_frag6_15.py= 0555 +${PACKAGE}FILESMODE_frag6_16.py= 0555 +${PACKAGE}FILESMODE_frag6_17.py= 0555 +${PACKAGE}FILESMODE_frag6_18.py= 0555 +${PACKAGE}FILESMODE_frag6_19.py= 0555 +${PACKAGE}FILESMODE_frag6_20.py= 0555 + +.include Property changes on: stable/12/tests/sys/netinet6/frag6/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_01.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_01.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_01.sh (revision 356491) @@ -0,0 +1,233 @@ +# $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)/frag6.subr + +atf_test_case "frag6_01" "cleanup" +frag6_01_head() { + frag6_head 1 +} + +frag6_01_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # XXX-BZ TODO FIXME reassembly-failed should be 1? + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_01_body() { + + atf_skip "Sending IPv6 Jumbograms needs 1 kernel changes and BPF fixes" + + frag6_body 1 frag6_01_check_stats +} + +frag6_01_cleanup() { + frag6_cleanup 1 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_01" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_01.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_02.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_02.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_02.sh (revision 356491) @@ -0,0 +1,230 @@ +# $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)/frag6.subr + +atf_test_case "frag6_02" "cleanup" +frag6_02_head() { + frag6_head 2 +} + +frag6_02_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # XXX-TODO no global stats for this case? + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_02_body() { + frag6_body 2 frag6_02_check_stats +} + +frag6_02_cleanup() { + frag6_cleanup 2 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_02" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_02.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_03.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_03.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_03.py (revision 356491) @@ -0,0 +1,107 @@ +#!/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 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.ICMPv6DestUnreach) + if not icmp6: + return False + # ICMP6_DST_UNREACH_NOPORT 4 + if icmp6.code != 4: + return False + # Should we check the payload as well? + # We are running in a very isolated environment and nothing else + # should trigger an ICMPv6 Dest Unreach / Port Unreach 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) + + + ######################################################################## + # + # Atomic fragment. + # + # A: Nothing listening on UDP port. + # R: ICMPv6 dst unreach, unreach port. + # + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=0, m=0, id=3) / \ + sp.UDP(dport=3456, sport=6543) + 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) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_03.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_03.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_03.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_03.sh (revision 356491) @@ -0,0 +1,231 @@ +# $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)/frag6.subr + +atf_test_case "frag6_03" "cleanup" +frag6_03_head() { + frag6_head 3 +} + +frag6_03_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_03_body() { + frag6_body 3 frag6_03_check_stats +} + +frag6_03_cleanup() { + frag6_cleanup 3 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_03" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_03.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_04.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_04.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_04.sh (revision 356491) @@ -0,0 +1,231 @@ +# $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)/frag6.subr + +atf_test_case "frag6_04" "cleanup" +frag6_04_head() { + frag6_head 4 +} + +frag6_04_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 1 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_04_body() { + frag6_body 4 frag6_04_check_stats +} + +frag6_04_cleanup() { + frag6_cleanup 4 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_04" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_04.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_05.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_05.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_05.py (revision 356491) @@ -0,0 +1,84 @@ +#!/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 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) + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_05.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_05.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_05.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_05.sh (revision 356491) @@ -0,0 +1,475 @@ +# $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)/frag6.subr + +frag6_05_check_stats_0() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check that the sysctl is set to what we expect. + # + sn=`sysctl -n net.inet6.ip6.maxfrags` + case "${sn}" in + 0) ;; + *) atf_fail "Sysctl net.inet6.ip6.maxfrags is ${sn} and not 0" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 20 + 20 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 20 + 0 + 20 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_05_check_stats_1() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check that the sysctl is set to what we expect. + # + sn=`sysctl -n net.inet6.ip6.maxfrags` + case "${sn}" in + 10) ;; + *) atf_fail "Sysctl net.inet6.ip6.maxfrags is ${sn} and not 10" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 20 + 10 + 10 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 10 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 10 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 20 + 0 + 10 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 10 + 0 + 0 + 10 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_05_0" "cleanup" +frag6_05_0_head() { + frag6_head 5_0 +} + +frag6_05_0_body() { + + # Save current sysctl value. + ov=`sysctl -n net.inet6.ip6.maxfrags` + echo "${ov}" > ${HOME}/sysctl-$(atf_get ident).txt + + # Never accept fragments. + sysctl net.inet6.ip6.maxfrags=0 + + frag6_body 5 frag6_05_check_stats_0 +} + +frag6_05_0_cleanup() { + frag6_cleanup 5_0 + + # Restore sysctl back to default. + ov=`cat ${HOME}/sysctl-$(atf_get ident).txt` + rm -f ${HOME}/sysctl-$(atf_get ident).txt + sysctl net.inet6.ip6.maxfrags=${ov} +} + + +atf_test_case "frag6_05_1" "cleanup" +frag6_05_1_head() { + frag6_head 5_1 +} + +frag6_05_1_body() { + + # Save current sysctl value. + ov=`sysctl -n net.inet6.ip6.maxfrags` + echo "${ov}" > ${HOME}/sysctl-$(atf_get ident).txt + + # Maximum of 10 global system-wide fragments. + sysctl net.inet6.ip6.maxfrags=10 + + frag6_body 5 frag6_05_check_stats_1 +} + +frag6_05_1_cleanup() { + frag6_cleanup 5_1 + + # Restore sysctl back to default. + ov=`cat ${HOME}/sysctl-$(atf_get ident).txt` + rm -f ${HOME}/sysctl-$(atf_get ident).txt + sysctl net.inet6.ip6.maxfrags=${ov} +} + + +atf_init_test_cases() +{ + atf_add_test_case "frag6_05_0" + atf_add_test_case "frag6_05_1" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_05.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_06.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_06.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_06.sh (revision 356491) @@ -0,0 +1,263 @@ +# $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)/frag6.subr + +frag6_06_pre_test_0() { + + local jname ifname + jname=$1 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + + # Never accept fragments. + jexec ${jname} sysctl net.inet6.ip6.maxfragbucketsize=0 +} + + +frag6_06_check_stats_0() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check that the sysctl is set to what we expect. + # + sn=`jexec ${jname} sysctl -n net.inet6.ip6.maxfragbucketsize` + case "${sn}" in + 0) ;; + *) atf_fail "Sysctl net.inet6.ip6.maxfragbucketsize is ${sn} and not 0" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 20 + 20 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 20 + 0 + 20 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_06_0" "cleanup" +frag6_06_0_head() { + frag6_head 6_0 +} + +frag6_06_0_body() { + frag6_body 6 frag6_06_check_stats_0 frag6_06_pre_test_0 +} + +frag6_06_0_cleanup() { + frag6_cleanup 6_0 + + # No need to restore the sysctl back to default as the jail is gone. +} + + +#atf_test_case "frag6_06_1" "cleanup" +# There is no point in testing a != 0 value for net.inet6.ip6.maxfragbucketsize. +# We would have to be able to generate hash collisions to end up in the same +# bucket (or re-compile a kernel with only 1 bucket). + + +atf_init_test_cases() +{ + atf_add_test_case "frag6_06_0" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_06.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_07.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_07.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_07.py (revision 356491) @@ -0,0 +1,178 @@ +#!/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 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) + sniffer2.setEnd() + sniffer2.join() + if not sniffer2.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_07.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_07.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_07.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_07.sh (revision 356491) @@ -0,0 +1,232 @@ +# $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)/frag6.subr + +frag6_07_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # XXX-BZ Only ICMPv6 errors and no proper stats! + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 3 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 0 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_07" "cleanup" +frag6_07_head() { + frag6_head 7 +} + +frag6_07_body() { + frag6_body 7 frag6_07_check_stats +} + +frag6_07_cleanup() { + frag6_cleanup 7 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_07" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_07.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_08.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_08.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_08.py (revision 356491) @@ -0,0 +1,152 @@ +#!/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 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) + sniffer2.setEnd() + sniffer2.join() + if not sniffer2.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_08.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_08.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_08.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_08.sh (revision 356491) @@ -0,0 +1,232 @@ +# $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)/frag6.subr + +frag6_08_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # XXX-BZ Only ICMPv6 errors and no proper stats! + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 2 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_08" "cleanup" +frag6_08_head() { + frag6_head 8 +} + +frag6_08_body() { + frag6_body 8 frag6_08_check_stats +} + +frag6_08_cleanup() { + frag6_cleanup 8 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_08" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_08.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_09.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_09.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_09.sh (revision 356491) @@ -0,0 +1,229 @@ +# $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)/frag6.subr + +atf_test_case "frag6_09" "cleanup" +frag6_09_head() { + frag6_head 9 +} + +frag6_09_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_09_body() { + frag6_body 9 frag6_09_check_stats +} + +frag6_09_cleanup() { + frag6_cleanup 9 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_09" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_09.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_10.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_10.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_10.py (revision 356491) @@ -0,0 +1,81 @@ +#!/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 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) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_10.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_10.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_10.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_10.sh (revision 356491) @@ -0,0 +1,231 @@ +# $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)/frag6.subr + +atf_test_case "frag6_10" "cleanup" +frag6_10_head() { + frag6_head 10 +} + +frag6_10_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # We do not sent a timeout ICMPv6 for this one + # as it is not an off=0 segment. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_10_body() { + frag6_body 10 frag6_10_check_stats +} + +frag6_10_cleanup() { + frag6_cleanup 10 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_10" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_10.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_11.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_11.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_11.sh (revision 356491) @@ -0,0 +1,230 @@ +# $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)/frag6.subr + +atf_test_case "frag6_11" "cleanup" +frag6_11_head() { + frag6_head 11 +} + +frag6_11_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # XXX-TODO We do not seem to sent a timeout ICMPv6 for this one? + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +frag6_11_body() { + frag6_body 11 frag6_11_check_stats +} + +frag6_11_cleanup() { + frag6_cleanup 11 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_11" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_11.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_12.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_12.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_12.sh (revision 356491) @@ -0,0 +1,228 @@ +# $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)/frag6.subr + +atf_test_case "frag6_12" "cleanup" +frag6_12_head() { + frag6_head 12 +} + +frag6_12_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} +frag6_12_body() { + frag6_body 12 frag6_12_check_stats +} + +frag6_12_cleanup() { + frag6_cleanup 12 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_12" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_12.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_13.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_13.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_13.py (revision 356491) @@ -0,0 +1,122 @@ +#!/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 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) + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_13.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_13.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_13.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_13.sh (revision 356491) @@ -0,0 +1,228 @@ +# $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)/frag6.subr + +atf_test_case "frag6_13" "cleanup" +frag6_13_head() { + frag6_head 13 +} + +frag6_13_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 4 + 2 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 2 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} +frag6_13_body() { + frag6_body 13 frag6_13_check_stats +} + +frag6_13_cleanup() { + frag6_cleanup 13 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_13" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_13.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_14.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_14.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_14.py (revision 356491) @@ -0,0 +1,137 @@ +#!/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 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) + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_14.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_14.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_14.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_14.sh (revision 356491) @@ -0,0 +1,228 @@ +# $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)/frag6.subr + +atf_test_case "frag6_14" "cleanup" +frag6_14_head() { + frag6_head 14 +} + +frag6_14_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 6 + 2 + 3 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 6 + 0 + 2 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} +frag6_14_body() { + frag6_body 14 frag6_14_check_stats +} + +frag6_14_cleanup() { + frag6_cleanup 14 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_14" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_14.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_15.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_15.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_15.sh (revision 356491) @@ -0,0 +1,257 @@ +# $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)/frag6.subr + +frag6_15_pre_test() { + + local jname ifname + jname=$1 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + + # Accept 3 fragments per fragmented packet. + jexec ${jname} sysctl net.inet6.ip6.maxfragsperpacket=3 +} + + +frag6_15_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check that the sysctl is set to what we expect. + # + sn=`jexec ${jname} sysctl -n net.inet6.ip6.maxfragsperpacket` + case "${sn}" in + 3) ;; + *) atf_fail "Sysctl net.inet6.ip6.maxfragsperpacket is ${sn} and not 3" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 8 + 8 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # XXX-BZ no reassembly failed stats.# + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 8 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_15" "cleanup" +frag6_15_head() { + frag6_head 15 +} + +frag6_15_body() { + frag6_body 15 frag6_15_check_stats frag6_15_pre_test +} + +frag6_15_cleanup() { + frag6_cleanup 15 + + # No need to restore the sysctl back to default as the jail is gone. +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_15" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_15.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_16.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_16.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_16.sh (revision 356491) @@ -0,0 +1,233 @@ +# $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)/frag6.subr + + +frag6_16_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 30 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # XXX-BZ no reassembly failed stats.# + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 30 + 1 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_16" "cleanup" +frag6_16_head() { + frag6_head 16 +} + +frag6_16_body() { + frag6_body 16 frag6_16_check_stats +} + +frag6_16_cleanup() { + frag6_cleanup 16 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_16" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_16.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_20.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_20.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_20.py (revision 356491) @@ -0,0 +1,137 @@ +#!/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 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) + sniffer.setEnd() + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_20.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_20.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_20.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_20.sh (revision 356491) @@ -0,0 +1,231 @@ +# $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)/frag6.subr + +frag6_20_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + nf=`jexec ${jname} sysctl -n net.inet6.ip6.frag6_nfragpackets` + case ${nf} in + 0) break ;; + *) atf_fail "VNET frag6_nfragpackets not 0 but: ${nf}" ;; + esac + nf=`sysctl -n net.inet6.ip6.frag6_nfrags` + case ${nf} in + 0) break ;; + *) atf_fail "Global frag6_nfrags not 0 but: ${nf}" ;; + esac + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 3 + 1 + 2 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 3 + 0 + 1 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_20" "cleanup" +frag6_20_head() { + frag6_head 20 +} + +frag6_20_body() { + frag6_body 20 frag6_20_check_stats +} + +frag6_20_cleanup() { + frag6_cleanup 20 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_20" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_20.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6.subr =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6.subr (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6.subr (revision 356491) @@ -0,0 +1,122 @@ +# $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 mtu 131071 up + ifconfig ${epair}a inet6 ${ip6a}/64 + + jname="v6t-${id}-${yl}-${xl}" + vnet_mkjail ${jname} ${epair}b + jexec ${jname} ifconfig ${epair}b mtu 131071 up + jexec ${jname} ifconfig ${epair}b inet6 ${ip6b}/64 + + # Let IPv6 ND do its thing. + #ping6 -q -c 1 ff02::1%${epair}a + #ping6 -q -c 1 ${ip6b} + sleep 3 + + # 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 Property changes on: stable/12/tests/sys/netinet6/frag6/frag6.subr ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_01.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_01.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_01.py (revision 356491) @@ -0,0 +1,115 @@ +#!/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 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) + sniffer.setEnd() + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_01.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_02.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_02.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_02.py (revision 356491) @@ -0,0 +1,108 @@ +#!/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 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 payload length not % 8. + # + # A: Error handling in code. + # R: ICMPv6 param problem. + # + data = "6" * 1287 + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=0, m=1, id=5) / \ + 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.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_02.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_04.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_04.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_04.py (revision 356491) @@ -0,0 +1,105 @@ +#!/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 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) + + + ######################################################################## + # + # 0-byte first fragment. + # + # A: 0-byte fragment payload not allowed. Discarded. + # R: ICMPv6 param prob, paramprob header. + # + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=0, m=1, id=4) + if args.debug : + ip6f01.display() + sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) + + sleep(0.10) + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_04.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_06.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_06.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_06.py (revision 356491) @@ -0,0 +1,81 @@ +#!/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 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 on a reassembly queue. + # + # A: Discarded. + # R: Silence (statistics only) or ICMPv6 timeout expiry. + # + data = "66666666" + for i in range(20): + foffset=(i * (int)(16 / 8)) + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, 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) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_06.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_09.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_09.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_09.py (revision 356491) @@ -0,0 +1,109 @@ +#!/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 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) + sniffer.setEnd() + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_09.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_11.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_11.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_11.py (revision 356491) @@ -0,0 +1,81 @@ +#!/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 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) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_11.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_12.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_12.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_12.py (revision 356491) @@ -0,0 +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 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) + sniffer.setEnd() + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_12.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_15.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_15.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_15.py (revision 356491) @@ -0,0 +1,105 @@ +#!/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 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 maximum 3 segments on a fragmented packet. + # The 4th packet will flush the entire q6. + # + # A: 4 Discarded. + # R: Silence (statistics only) no ICMPv6 as we skip the off=0 segment. + # + data = "66666666" + for i in range(4): + foffset=16 + (i * (0x100 + (int)(16 / 8))) + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, m=1, id=15) / \ + sp.UDP(dport=3456, sport=6543) / \ + data + if args.debug : + ip6f01.display() + sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) + + + # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ## + # + # Sysctl set to accept maximum 3 segments on a fragmented packet. + # The 4th packet will flush the entire q6. + # This time we play proper offset/length games on the packets in order + # to trigger the 2nd test case, with the last packet still having m=1. + # + # A: 4 Discarded. + # R: ICMPv6 timeout expired. + # + data = "66666666" + for i in range(4): + foffset=(i * (int)(16 / 8)) + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, m=1, id=0x1501) / \ + sp.UDP(dport=3456, sport=6543) / \ + data + if args.debug : + ip6f01.display() + sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_15.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_16.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_16.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_16.py (revision 356491) @@ -0,0 +1,132 @@ +#!/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 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.ICMPv6DestUnreach) + if not icmp6: + return False + # ICMP6_DST_UNREACH_NOPORT 4 + if icmp6.code != 4: + return False + # Should we check the payload as well? + # We are running in a very isolated environment and nothing else + # should trigger an ICMPv6 Dest Unreach / Port Unreach 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 fragmented packet with upper layer data in multiple segments + # to pass fragmentation. + # We need to do a bit of a dance to get the UDP checksum right. + # + # A: 1 reassembled packet + # R: Statistics and ICMPv6 error (non-fragmentation) as no port open. + # + data = "6" * 1280 + dataall = data * 30 + ip6f01 = \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.UDP(dport=3456, sport=6543) / \ + dataall + ip6fd = sp.IPv6(sp.raw(ip6f01)) + + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=0, m=1, id=16) / \ + sp.UDP(dport=3456, sport=6543, len=ip6fd.len, chksum=ip6fd.chksum) / \ + data + if args.debug : + ip6f01.display() + sp.sendp(ip6f01, iface=args.sendif[0], verbose=False) + + foffset=(int)(1288/8) + mbit=1 + for i in range(1,30): + if i is 29: + mbit=0 + ip6f0n = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, m=mbit, id=16, nh=socket.IPPROTO_UDP) / \ + data + if args.debug : + ip6f0n.display() + sp.sendp(ip6f0n, iface=args.sendif[0], verbose=False) + foffset += (int)(1280/8) + + sleep(0.10) + sniffer.setEnd() + sniffer.join() + if not sniffer.foundCorrectPacket: + sys.exit(1) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_16.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_17.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_17.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_17.py (revision 356491) @@ -0,0 +1,90 @@ +#!/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 random as random +import scapy.all as sp +import socket +import sys + +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 a sample of pseudo-random fragments into the system in order + # to test vnet teardown. + # + # A: Cleaned up and freed + # R: No panic (ignoring everything else) + # + + random.seed() + packets = []; + + for i in range(0,127): + fid=random.randint(0,0xffff) + foffset=random.randint(0,0xffff) + fm=random.randint(0,1) + fsrc=sp.RandIP6() + ip6f01 = sp.Ether() / \ + sp.IPv6(src=fsrc, dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, m=fm, id=fid) / \ + sp.UDP(dport=3456, sport=6543) + if args.debug: + ip6f01.display() + packets.append(ip6f01) + + for p in packets: + sp.sendp(p, iface=args.sendif[0], verbose=False) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_17.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_17.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_17.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_17.sh (revision 356491) @@ -0,0 +1,47 @@ +# $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)/frag6.subr + +atf_test_case "frag6_17" "cleanup" +frag6_17_head() { + frag6_head 17 +} + +frag6_17_body() { + frag6_body 17 +} + +frag6_17_cleanup() { + frag6_cleanup 17 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_17" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_17.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_18.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_18.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_18.py (revision 356491) @@ -0,0 +1,90 @@ +#!/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 random as random +import scapy.all as sp +import socket +import sys + +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 a sample of pseudo-random fragments into the system in order + # to test vnet teardown. + # + # A: Cleaned up and freed + # R: No panic (ignoring everything else) + # + + random.seed() + packets = []; + + for i in range(0,127): + fid=random.randint(0,0xffff) + foffset=random.randint(0,0xffff) + fm=random.randint(0,1) + fsrc=sp.RandIP6() + ip6f01 = sp.Ether() / \ + sp.IPv6(src=fsrc, dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=foffset, m=fm, id=fid) / \ + sp.UDP(dport=3456, sport=6543) + if args.debug: + ip6f01.display() + packets.append(ip6f01) + + for p in packets: + sp.sendp(p, iface=args.sendif[0], verbose=False) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_18.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_18.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_18.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_18.sh (revision 356491) @@ -0,0 +1,64 @@ +# $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)/frag6.subr + +frag6_18_delif() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Invalidate the ifp from the packets in the reassembly queue. + ifconfig ${ifname} -vnet ${jname} +} + +atf_test_case "frag6_18" "cleanup" +frag6_18_head() { + frag6_head 18 +} + +frag6_18_body() { + frag6_body 18 frag6_18_delif +} + +frag6_18_cleanup() { + frag6_cleanup 18 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_18" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_18.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_19.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_19.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_19.py (revision 356491) @@ -0,0 +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 scapy.all as sp +import socket +import sys + +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 a sample of sequeneced ID fragments into the system in order + # to test bucket distribution. + # + # A: No overflow at V_ip6_maxfragsperpacket == 64. + # R: Stats only, timeout and no ICMPv6 (all ignored). + # + packets = []; + data = "66666666" + for i in range(0,127): + ip6f01 = sp.Ether() / \ + sp.IPv6(src=args.src[0], dst=args.to[0]) / \ + sp.IPv6ExtHdrFragment(offset=1, m=1, id=i) / \ + data + if args.debug: + ip6f01.display() + packets.append(ip6f01) + + for p in packets: + sp.sendp(p, iface=args.sendif[0], verbose=False) + + sys.exit(0) + +if __name__ == '__main__': + main() Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_19.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/frag6_19.sh =================================================================== --- stable/12/tests/sys/netinet6/frag6/frag6_19.sh (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/frag6_19.sh (revision 356491) @@ -0,0 +1,221 @@ +# $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)/frag6.subr + +frag6_19_check_stats() { + + local jname ifname + jname=$1 + ifname=$2 + + case "${jname}" in + "") echo "ERROR: jname is empty"; return ;; + esac + case "${ifname}" in + "") echo "ERROR: ifname is empty"; return ;; + esac + + # Defaults are: IPV6_FRAGTTL 120 slowtimo ticks. + # pfslowtimo() is run at hz/2. So this takes 60s. + # This is awefully long for a test case. + # The Python script has to wait for this already to get the ICMPv6 + # hence we do not sleep here anymore. + + # + # Check selection of global UDP stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p udp --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 9) ;; + *) jexec ${jname} netstat -s -p udp --libxo xml,pretty + atf_fail "Global UDP statistics do not match: ${count} != 9" ;; + esac + + + # + # Check selection of global IPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 127 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 20) ;; + *) jexec ${jname} netstat -s -p ip6 --libxo xml,pretty + atf_fail "Global IPv6 statistics do not match: ${count} != 20" ;; + esac + + # + # Check selection of global ICMPv6 stats. + # XXX-TODO check output histogram (just too hard to parse [no multi-line-grep]) + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 22) ;; + *) jexec ${jname} netstat -s -p icmp6 --libxo xml,pretty + atf_fail "Global ICMPv6 statistics do not match: ${count} != 22" ;; + esac + + # + # Check selection of interface IPv6 stats. + # XXX-BZ no reassembly failed stats.# + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 127 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 14) ;; + *) jexec ${jname} netstat -s -p ip6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface IPv6 statistics do not match: ${count} != 14" ;; + esac + + # + # Check selection of interface ICMPv6 stats. + # + cat < ${HOME}/filter-${jname}.txt + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 +EOF + count=`jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty | grep -E -x -c -f ${HOME}/filter-${jname}.txt` + rm -f ${HOME}/filter-${jname}.txt + case ${count} in + 21) ;; + *) jexec ${jname} netstat -s -p icmp6 -I ${ifname} --libxo xml,pretty + atf_fail "Interface ICMPv6 statistics do not match: ${count} != 21" ;; + esac +} + +atf_test_case "frag6_19" "cleanup" +frag6_19_head() { + frag6_head 19 +} + +frag6_19_body() { + frag6_body 19 frag6_19_check_stats +} + +frag6_19_cleanup() { + frag6_cleanup 19 +} + +atf_init_test_cases() +{ + atf_add_test_case "frag6_19" +} Property changes on: stable/12/tests/sys/netinet6/frag6/frag6_19.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/frag6/sniffer.py =================================================================== --- stable/12/tests/sys/netinet6/frag6/sniffer.py (nonexistent) +++ stable/12/tests/sys/netinet6/frag6/sniffer.py (revision 356491) @@ -0,0 +1,40 @@ +# $FreeBSD$ + +import threading +import scapy.all as sp + +class Sniffer(threading.Thread): + def __init__(self, args, check_function): + threading.Thread.__init__(self) + + self._args = args + self._recvif = args.recvif[0] + self._check_function = check_function + self.foundCorrectPacket = False + self._endme = False + + self.start() + + def _checkPacket(self, packet): + ret = self._check_function(self._args, packet) + if ret: + self.foundCorrectPacket = True + return ret + + def setEnd(self): + self._endme = True + + def stopFilter(self, pkt): + if pkt is not None: + self._checkPacket(pkt) + if self.foundCorrectPacket or self._endme: + return True + else: + return False + + def run(self): + while True: + self.packets = sp.sniff(iface=self._recvif, store=False, + stop_filter=self.stopFilter, timeout=90) + if self.stopFilter(None): + break Property changes on: stable/12/tests/sys/netinet6/frag6/sniffer.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12/tests/sys/netinet6/Makefile =================================================================== --- stable/12/tests/sys/netinet6/Makefile (nonexistent) +++ stable/12/tests/sys/netinet6/Makefile (revision 356491) @@ -0,0 +1,7 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/netinet6 + +TESTS_SUBDIRS+= frag6 + +.include Property changes on: stable/12/tests/sys/netinet6/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/12 =================================================================== --- stable/12 (revision 356490) +++ stable/12 (revision 356491) Property changes on: stable/12 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r350748,353792-353794,353963,353965-353966,354016-354017,354019-354020,354037,354040,354042,354045-354046,354053,354081,354084