1 1.1 joe /*- 2 1.1 joe * Copyright (c) 2025 Emmanuel Nyarko 3 1.1 joe * 4 1.1 joe * Redistribution and use in source and binary forms, with or without 5 1.1 joe * modification, are permitted provided that the following conditions 6 1.1 joe * are met: 7 1.1 joe * 1. Redistributions of source code must retain the above copyright 8 1.1 joe * notice, this list of conditions and the following disclaimer. 9 1.1 joe * 2. Redistributions in binary form must reproduce the above copyright 10 1.1 joe * notice, this list of conditions and the following disclaimer in the 11 1.1 joe * documentation and/or other materials provided with the distribution. 12 1.1 joe * 13 1.1 joe * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 14 1.1 joe * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 15 1.1 joe * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 1.1 joe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 17 1.1 joe * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 1.1 joe * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 1.1 joe * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 1.1 joe * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 1.1 joe * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 1.1 joe * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 1.1 joe * POSSIBILITY OF SUCH DAMAGE. 24 1.1 joe */ 25 1.1 joe 26 1.2 joe #ifdef _KERNEL 27 1.2 joe #include <sys/cdefs.h> 28 1.3 joe __KERNEL_RCSID(0, "$NetBSD: npf_socket.c,v 1.3 2025/06/02 13:19:27 joe Exp $"); 29 1.2 joe 30 1.2 joe #include <sys/param.h> 31 1.2 joe #include <sys/types.h> 32 1.2 joe 33 1.1 joe #include <netinet/tcp.h> 34 1.1 joe #include <netinet/udp.h> 35 1.1 joe #include <netinet/in_pcb.h> 36 1.1 joe #include <sys/socketvar.h> 37 1.1 joe 38 1.1 joe #include <netinet/ip6.h> 39 1.1 joe #include <netinet6/ip6_var.h> 40 1.1 joe #include <netinet6/in6_pcb.h> 41 1.2 joe #endif 42 1.1 joe 43 1.1 joe #include "npf_impl.h" 44 1.1 joe 45 1.1 joe extern struct inpcbtable tcbtable; /* head of queue of active tcpcb's */ 46 1.1 joe extern struct inpcbtable udbtable; 47 1.1 joe 48 1.3 joe #if defined(INET6) 49 1.1 joe static struct socket * npf_ip6_socket(npf_cache_t *, int); 50 1.3 joe #endif 51 1.1 joe static struct socket * npf_ip_socket(npf_cache_t *, int); 52 1.1 joe static int npf_match(uint8_t, uint32_t, uint32_t, uint32_t); 53 1.1 joe 54 1.1 joe /* 55 1.1 joe * NPF process socket module 56 1.1 joe */ 57 1.1 joe 58 1.1 joe int 59 1.1 joe npf_match_rid(rid_t *rid, uint32_t uid_lookup) 60 1.1 joe { 61 1.1 joe return npf_match(rid->op, rid->id[0], rid->id[1], uid_lookup); 62 1.1 joe } 63 1.1 joe 64 1.1 joe static int 65 1.1 joe npf_match(uint8_t op, uint32_t rid1, uint32_t rid2, uint32_t id_lp) 66 1.1 joe { 67 1.1 joe switch (op) { 68 1.1 joe case NPF_OP_IRG: 69 1.1 joe return id_lp > rid1 && id_lp < rid2; 70 1.1 joe case NPF_OP_XRG: 71 1.1 joe return id_lp < rid1 || id_lp > rid2; 72 1.1 joe case NPF_OP_EQ: 73 1.1 joe return id_lp == rid1; 74 1.1 joe case NPF_OP_NE: 75 1.1 joe return id_lp != rid1; 76 1.1 joe case NPF_OP_LT: 77 1.1 joe return id_lp < rid1; 78 1.1 joe case NPF_OP_LE: 79 1.1 joe return id_lp <= rid1; 80 1.1 joe case NPF_OP_GT: 81 1.1 joe return id_lp > rid1; 82 1.1 joe case NPF_OP_GE: 83 1.1 joe return id_lp >= rid1; 84 1.1 joe } 85 1.1 joe return 0; /* never reached */ 86 1.1 joe } 87 1.1 joe 88 1.1 joe int 89 1.1 joe npf_socket_lookup_rid(npf_cache_t *npc, get_rid_t get_rid, uint32_t *rid, int dir) 90 1.1 joe { 91 1.1 joe struct socket *so = NULL; 92 1.1 joe 93 1.1 joe KASSERT(npf_iscached(npc, NPC_IP46)); 94 1.1 joe 95 1.1 joe if (npf_iscached(npc, NPC_IP4)) { 96 1.1 joe so = npf_ip_socket(npc, dir); 97 1.3 joe #if defined(INET6) 98 1.1 joe } else if (npf_iscached(npc, NPC_IP6)) { 99 1.1 joe so = npf_ip6_socket(npc, dir); 100 1.3 joe #endif 101 1.1 joe } 102 1.1 joe 103 1.1 joe if (so == NULL || so->so_cred == NULL) 104 1.1 joe return -1; 105 1.1 joe 106 1.1 joe *rid = get_rid(so->so_cred); 107 1.1 joe return 0; 108 1.1 joe } 109 1.1 joe 110 1.1 joe static struct socket * 111 1.1 joe npf_ip_socket(npf_cache_t *npc, int dir) 112 1.1 joe { 113 1.1 joe struct inpcbtable *tb = NULL; 114 1.1 joe struct in_addr saddr, daddr; 115 1.1 joe uint16_t sport, dport; 116 1.1 joe struct socket *so = NULL; 117 1.1 joe struct inpcb *inp = NULL; 118 1.1 joe 119 1.1 joe #define in_pcbhashlookup(tbl, saddr, sport, daddr, dport) \ 120 1.1 joe inpcb_lookup(tbl, saddr, sport, daddr, dport, NULL) 121 1.1 joe #define in_pcblookup_listen(tbl, addr, port) \ 122 1.1 joe inpcb_lookup_bound(tbl, addr, port) 123 1.1 joe 124 1.1 joe KASSERT(npf_iscached(npc, NPC_LAYER4)); 125 1.1 joe KASSERT(npf_iscached(npc, NPC_IP4)); 126 1.1 joe 127 1.1 joe struct tcphdr *tcp = npc->npc_l4.tcp; 128 1.1 joe struct udphdr *udp = npc->npc_l4.udp; 129 1.1 joe struct ip *ip = npc->npc_ip.v4; 130 1.1 joe 131 1.1 joe switch(npc->npc_proto) { 132 1.1 joe case IPPROTO_TCP: 133 1.1 joe sport = tcp->th_sport; 134 1.1 joe dport = tcp->th_dport; 135 1.1 joe tb = &tcbtable; 136 1.1 joe break; 137 1.1 joe case IPPROTO_UDP: 138 1.1 joe sport = udp->uh_sport; 139 1.1 joe dport = udp->uh_dport; 140 1.1 joe tb = &udbtable; 141 1.1 joe break; 142 1.1 joe default: 143 1.1 joe return NULL; 144 1.1 joe } 145 1.1 joe 146 1.1 joe if (dir == PFIL_IN) { 147 1.1 joe saddr = ip->ip_src; 148 1.1 joe daddr = ip->ip_dst; 149 1.1 joe } else { 150 1.1 joe uint16_t p_temp; 151 1.1 joe /* swap ports and addresses */ 152 1.1 joe p_temp = sport; 153 1.1 joe sport = dport; 154 1.1 joe dport = p_temp; 155 1.1 joe saddr = ip->ip_dst; 156 1.1 joe daddr = ip->ip_src; 157 1.1 joe } 158 1.1 joe 159 1.1 joe inp = in_pcbhashlookup(tb, saddr, sport, daddr, dport); 160 1.1 joe if (inp == NULL) { 161 1.1 joe inp = in_pcblookup_listen(tb, daddr, dport); 162 1.1 joe if (inp == NULL) { 163 1.1 joe return NULL; 164 1.1 joe } 165 1.1 joe } 166 1.1 joe 167 1.1 joe so = inp->inp_socket; 168 1.1 joe return so; 169 1.1 joe } 170 1.1 joe 171 1.3 joe #if defined(INET6) 172 1.1 joe static struct socket * 173 1.1 joe npf_ip6_socket(npf_cache_t *npc, int dir) 174 1.1 joe { 175 1.1 joe struct inpcbtable *tb = NULL; 176 1.1 joe const struct in6_addr *s6addr, *d6addr; 177 1.1 joe uint16_t sport, dport; 178 1.1 joe struct inpcb *in6p = NULL; 179 1.1 joe struct socket *so = NULL; 180 1.1 joe 181 1.1 joe #define in6_pcbhashlookup(tbl, saddr, sport, daddr, dport) \ 182 1.1 joe in6pcb_lookup(tbl, saddr, sport, daddr, dport, 0, NULL) 183 1.1 joe 184 1.1 joe #define in6_pcblookup_listen(tbl, addr, port) \ 185 1.1 joe in6pcb_lookup_bound(tbl, addr, port, 0) 186 1.1 joe 187 1.1 joe KASSERT(npf_iscached(npc, NPC_LAYER4)); 188 1.1 joe KASSERT(npf_iscached(npc, NPC_IP6)); 189 1.1 joe 190 1.1 joe struct tcphdr *tcp = npc->npc_l4.tcp; 191 1.1 joe struct udphdr *udp = npc->npc_l4.udp; 192 1.1 joe struct ip6_hdr *ip6 = npc->npc_ip.v6; 193 1.1 joe 194 1.1 joe switch(npc->npc_proto) { 195 1.1 joe case IPPROTO_TCP: 196 1.1 joe sport = tcp->th_sport; 197 1.1 joe dport = tcp->th_dport; 198 1.1 joe tb = &tcbtable; 199 1.1 joe break; 200 1.1 joe case IPPROTO_UDP: 201 1.1 joe sport = udp->uh_sport; 202 1.1 joe dport = udp->uh_dport; 203 1.1 joe tb = &udbtable; 204 1.1 joe break; 205 1.1 joe default: 206 1.1 joe return NULL; 207 1.1 joe } 208 1.1 joe 209 1.1 joe if (dir == PFIL_IN) { 210 1.1 joe s6addr = &ip6->ip6_src; 211 1.1 joe d6addr = &ip6->ip6_dst; 212 1.1 joe } else { 213 1.1 joe uint16_t p_temp; 214 1.1 joe /* swap ports and addresses */ 215 1.1 joe p_temp = sport; 216 1.1 joe sport = dport; 217 1.1 joe dport = p_temp; 218 1.1 joe s6addr = &ip6->ip6_dst; 219 1.1 joe d6addr = &ip6->ip6_src; 220 1.1 joe } 221 1.1 joe in6p = in6_pcbhashlookup(tb, s6addr, sport, d6addr, 222 1.1 joe dport); 223 1.1 joe if (in6p == NULL) { 224 1.1 joe in6p = in6_pcblookup_listen(tb, d6addr, dport); 225 1.1 joe if (in6p == NULL) 226 1.1 joe return NULL; 227 1.1 joe } 228 1.1 joe so = in6p->inp_socket; 229 1.1 joe return so; 230 1.1 joe } 231 1.3 joe #endif 232