Home | History | Annotate | Line # | Download | only in libnpftest
npf_ext_test.c revision 1.2
      1 
      2 /*-
      3  * Copyright (c) 2026 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Emmanuel Nyarko.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /*
     32  * NPF tests of extension.
     33  */
     34 
     35 #ifdef _KERNEL
     36 #include <sys/types.h>
     37 #endif
     38 
     39 #include "npf_impl.h"
     40 #include "npf_test.h"
     41 
     42 static const struct test_case {
     43 	const char *	src;
     44 	in_port_t	sport;
     45 	const char *	dst;
     46 	in_port_t	dport;
     47 	const char *	ifname;
     48 	int		di;
     49 	int		af;
     50 } test_cases[] = {
     51 	{
     52 		LOCAL_IP60,	15000,		LOCAL_IP70,	7000,
     53 		IFNAME_EXT,	PFIL_OUT,	AF_INET
     54 	},
     55 	{
     56 		LOCAL_IP60,	15040,		LOCAL_IP70,	6000,
     57 		IFNAME_EXT,	PFIL_OUT,	AF_INET
     58 	},
     59 
     60 };
     61 
     62 #define TCP_OPT_LEN 4
     63 static struct mbuf *
     64 mbuf_get_pkt_with_option(int af, int proto, const char *src, const char *dst,
     65     int sport, int dport)
     66 {
     67 	struct mbuf *m;
     68 	struct ip *ip;
     69 	struct tcphdr *th;
     70 	void *ipsrc, *ipdst;
     71 	int size = 0;
     72 	uint8_t *opt;
     73 	uint16_t mss = 1400;
     74 
     75 	m = m_gethdr(M_WAITOK, MT_HEADER);
     76 	ip = mtod(m, struct ip *);
     77 
     78 	ip->ip_v = IPVERSION;
     79 	ip->ip_hl = sizeof(struct ip) >> 2;
     80 	ip->ip_off = 0;
     81 	ip->ip_ttl = 64;
     82 	ip->ip_p = proto;
     83 
     84 	ipsrc = &ip->ip_src.s_addr;
     85 	ipdst = &ip->ip_dst.s_addr;
     86 
     87 	npf_inet_pton(af, src, ipsrc);
     88 	npf_inet_pton(af, dst, ipdst);
     89 
     90 	th = mbuf_return_hdrs(m, false, &ip);
     91 	size = sizeof(struct ip) + sizeof(struct tcphdr) + TCP_OPT_LEN;
     92 	th->th_flags |= TH_SYN;
     93 	th->th_off = (sizeof(struct tcphdr) + TCP_OPT_LEN)  >> 2;
     94 	th->th_sport = htons(sport);
     95 	th->th_dport = htons(dport);
     96 
     97 	opt = (uint8_t *)th + sizeof(struct tcphdr);
     98 	opt[0] = TCPOPT_MAXSEG;         /* Kind = 2 */
     99 	opt[1] = TCPOLEN_MAXSEG;        /* Length = 4 */
    100 	opt[2] = (mss >> 8) & 0xff;    /* 0x05 */
    101 	opt[3] = mss & 0xff;           /* 0x29 */
    102 
    103 	ip->ip_len = htons(size);
    104 
    105 	m->m_pkthdr.len = size;
    106 	m->m_len = size;
    107 	m->m_next = NULL;
    108 	return m;
    109 }
    110 
    111 static int
    112 run_raw_testcase(npf_cache_t *npc, unsigned i, bool verbose)
    113 {
    114 	const struct test_case *t = &test_cases[i];
    115 	npf_t *npf = npf_getkernctx();
    116 	int slock, error;
    117 	npf_rproc_t *rp;
    118 	npf_rule_t *rl;
    119 	npf_match_info_t mi;
    120 	int decision = 1;
    121 
    122 	slock = npf_config_read_enter(npf);
    123 	rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_3);
    124 	if (rl) {
    125 		error = npf_rule_conclude(rl, &mi);
    126 	} else {
    127 		error = ENOENT;
    128 	}
    129 	npf_config_read_exit(npf, slock);
    130 
    131 	if (error)
    132 		return error;
    133 
    134 	rp = npf_rule_getrproc(rl);
    135 	assert(rp != NULL);
    136 
    137 	error = npf_rproc_run(npc, rp, &mi, &decision);
    138 
    139 	if (error == 1) {
    140 		npf_rproc_release(rp);
    141 	}
    142 
    143 	return error;
    144 }
    145 
    146 static void
    147 npf_get_normalize_params(npf_cache_t *npc, uint16_t *ip_ttl, uint8_t *ip_id, int *df, uint16_t *maxmss)
    148 {
    149     int wscale;
    150     struct ip *ip = npc->npc_ip.v4;
    151     *ip_id = ip->ip_id;
    152     *ip_ttl = ip->ip_ttl;
    153     *df = ip->ip_off & IP_DF;
    154     npf_fetch_tcpopts(npc, maxmss, &wscale);
    155 }
    156 
    157 bool
    158 npf_procedure_test(bool verbose)
    159 {
    160 	int ret;
    161 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
    162 		const struct test_case *t = &test_cases[i];
    163 		npf_cache_t *npc;
    164 		struct mbuf *m;
    165 		uint16_t ip_ttl;
    166     	uint8_t ip_id;
    167     	int df;
    168     	uint16_t maxmss;
    169 
    170 		if (npf_test_getif(t->ifname) == NULL) {
    171 			printf("Interface %s is not configured.\n", t->ifname);
    172 			return false;
    173 		}
    174 
    175 		m = mbuf_get_pkt_with_option(t->af, IPPROTO_TCP, t->src, t->dst, 9000, 9000);
    176 		npc = get_cached_pkt(m, t->ifname,  NPF_RULE_LAYER_3);
    177 
    178 		ret = run_raw_testcase(npc, i, verbose);
    179 		if (verbose) {
    180 			printf("%s: expected return in raw testcase 1, returned %d\n", __func__, ret);
    181 		}
    182 		CHECK_TRUE(ret == 1);
    183 
    184 		npf_get_normalize_params(npc, &ip_ttl, &ip_id, &df, &maxmss);
    185 		maxmss = ntohs(maxmss);
    186 
    187 		if (verbose) {
    188 			printf("Normalization:\texpected 164 ttl but got %u\n", ip_ttl);
    189 			printf("Normalization:\texpected 1321 maxmss but got %u\n", maxmss);
    190 		}
    191 		CHECK_TRUE((df & IP_DF) == 0);
    192     	CHECK_TRUE(maxmss == 1321);
    193 		CHECK_TRUE(ip_ttl == 164);
    194 		put_cached_pkt(npc);
    195 	}
    196 
    197 	return true;
    198 }
    199