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