1 1.1 joe /* 2 1.3 joe * NPF socket User/group id tests. 3 1.3 joe * 4 1.3 joe * Public Domain. 5 1.3 joe */ 6 1.1 joe 7 1.1 joe #ifdef _KERNEL 8 1.1 joe #include <sys/types.h> 9 1.1 joe #include <sys/cdefs.h> 10 1.3 joe __KERNEL_RCSID(0, "$NetBSD: npf_rid_test.c,v 1.3 2025/07/01 20:19:30 joe Exp $"); 11 1.1 joe #endif 12 1.1 joe 13 1.1 joe #include "npf_impl.h" 14 1.1 joe #include "npf_test.h" 15 1.1 joe 16 1.1 joe #include <netinet/in.h> 17 1.1 joe #include <sys/socket.h> 18 1.1 joe #include <sys/kauth.h> 19 1.1 joe #include <sys/socketvar.h> 20 1.1 joe #include <sys/lwp.h> 21 1.1 joe #include <sys/cpu.h> 22 1.1 joe 23 1.1 joe #define RESULT_PASS 0 24 1.1 joe #define RESULT_BLOCK ENETUNREACH 25 1.1 joe 26 1.1 joe /* this port number suitable for testing */ 27 1.1 joe #define REMOTE_PORT 65500 28 1.1 joe #define LOCAL_PORT 65000 29 1.1 joe #define LOCAL_IP "127.0.0.1" 30 1.1 joe #define REMOTE_IP LOCAL_IP 31 1.1 joe 32 1.1 joe static const struct test_case { 33 1.1 joe int af; 34 1.1 joe const char * src; 35 1.1 joe uint16_t sport; 36 1.1 joe const char * dst; 37 1.1 joe uint16_t dport; 38 1.1 joe uint32_t uid; 39 1.1 joe uint32_t gid; 40 1.1 joe const char * ifname; 41 1.1 joe int di; 42 1.1 joe int ret; 43 1.1 joe int stateful_ret; 44 1.1 joe } test_cases[] = { 45 1.1 joe { 46 1.1 joe /* pass in final from $local_ip4 user $Kojo = 1001 group $wheel = 20 */ 47 1.1 joe .af = AF_INET, 48 1.1 joe .src = "10.1.1.4", .sport = 9000, 49 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT, 50 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN, 51 1.1 joe .uid = 1001, .gid = 20, /* matches so pass it */ 52 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS 53 1.1 joe }, 54 1.1 joe { 55 1.1 joe /* connect on different UID and block */ 56 1.1 joe .af = AF_INET, 57 1.1 joe .src = "10.1.1.4", .sport = 9000, 58 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT, 59 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN, 60 1.1 joe .uid = 1001, .gid = 10, /* mismatch gid so block it */ 61 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK 62 1.1 joe }, 63 1.1 joe { 64 1.1 joe .af = AF_INET, 65 1.1 joe .src = "10.1.1.4", .sport = 9000, 66 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT, 67 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN, 68 1.1 joe .uid = 100, .gid = 20, /* mismatch uid so block it */ 69 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK 70 1.1 joe }, 71 1.1 joe 72 1.1 joe 73 1.1 joe /* block out final to 127.0.0.1 user > $Kojo( > 1001) group 1 >< $wheel( IRG 1 >< 20) */ 74 1.1 joe { 75 1.1 joe .af = AF_INET, 76 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT, 77 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT, 78 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT, 79 1.1 joe .uid = 1005, .gid = 14, /* matches so blocks it */ 80 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK 81 1.1 joe }, 82 1.1 joe { 83 1.1 joe .af = AF_INET, 84 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT, 85 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT, 86 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT, 87 1.1 joe .uid = 1005, .gid = 30, /* mismatch gid so pass it */ 88 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS 89 1.1 joe }, 90 1.1 joe { 91 1.1 joe .af = AF_INET, 92 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT, 93 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT, 94 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT, 95 1.1 joe .uid = 100, .gid = 15, /* mismatch uid so pass it */ 96 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS 97 1.1 joe }, 98 1.1 joe { 99 1.1 joe .af = AF_INET, 100 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT, 101 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT, 102 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT, 103 1.1 joe .uid = 1010, .gid = 11, /* matches so blocks it */ 104 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK 105 1.1 joe }, 106 1.1 joe }; 107 1.1 joe 108 1.1 joe static int 109 1.1 joe run_raw_testcase(unsigned i, bool verbose) 110 1.1 joe { 111 1.1 joe const struct test_case *t = &test_cases[i]; 112 1.1 joe npf_t *npf = npf_getkernctx(); 113 1.1 joe npf_cache_t *npc; 114 1.1 joe struct mbuf *m; 115 1.1 joe npf_rule_t *rl; 116 1.1 joe int slock, error; 117 1.1 joe 118 1.1 joe m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, t->sport, t->dport); 119 1.3 joe npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_3); 120 1.1 joe 121 1.1 joe slock = npf_config_read_enter(npf); 122 1.3 joe rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_3); 123 1.1 joe if (rl) { 124 1.1 joe npf_match_info_t mi; 125 1.1 joe int id_match; 126 1.1 joe 127 1.1 joe id_match = npf_rule_match_rid(rl, npc, t->di); 128 1.1 joe error = npf_rule_conclude(rl, &mi); 129 1.1 joe if (verbose) 130 1.1 joe printf("id match is ...%d\n", id_match); 131 1.1 joe if (id_match != -1 && !id_match) { 132 1.1 joe error = npf_rule_reverse(npc, &mi, error); 133 1.1 joe } 134 1.1 joe 135 1.1 joe } else { 136 1.1 joe error = ENOENT; 137 1.1 joe } 138 1.1 joe npf_config_read_exit(npf, slock); 139 1.1 joe 140 1.1 joe put_cached_pkt(npc); 141 1.1 joe return error; 142 1.1 joe } 143 1.1 joe 144 1.1 joe static int 145 1.1 joe run_handler_testcase(unsigned i) 146 1.1 joe { 147 1.1 joe const struct test_case *t = &test_cases[i]; 148 1.1 joe ifnet_t *ifp = npf_test_getif(t->ifname); 149 1.1 joe npf_t *npf = npf_getkernctx(); 150 1.1 joe struct mbuf *m; 151 1.1 joe int error; 152 1.1 joe 153 1.1 joe m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, t->sport, t->dport); 154 1.1 joe error = npfk_packet_handler(npf, &m, ifp, t->di); 155 1.1 joe if (m) { 156 1.1 joe m_freem(m); 157 1.1 joe } 158 1.1 joe return error; 159 1.1 joe } 160 1.1 joe 161 1.1 joe /* 162 1.1 joe * we create our specific server socket here which listens on 163 1.1 joe * loopback address and port 65000. easier to test pcb lookup here since 164 1.1 joe * it will be loaded into the protocol table. 165 1.1 joe */ 166 1.1 joe static struct socket * 167 1.1 joe test_socket(int dir, uid_t uid, gid_t gid) 168 1.1 joe { 169 1.1 joe struct sockaddr_in server; 170 1.1 joe struct lwp *cur = curlwp; 171 1.1 joe void *p, *rp; 172 1.1 joe 173 1.2 skrll memset(&server, 0, sizeof(server)); 174 1.1 joe 175 1.1 joe server.sin_len = sizeof(server); 176 1.1 joe server.sin_family = AF_INET; 177 1.1 joe p = &server.sin_addr.s_addr; 178 1.1 joe npf_inet_pton(AF_INET, LOCAL_IP, p); /* we bind to 127.0.0.1 */ 179 1.1 joe server.sin_port = htons(LOCAL_PORT); 180 1.1 joe 181 1.1 joe struct socket *so; 182 1.1 joe int error = socreate(AF_INET, &so, SOCK_DGRAM, 0, cur, NULL); 183 1.1 joe if (error) { 184 1.1 joe printf("socket creation failed: error is %d\n", error); 185 1.1 joe return NULL; 186 1.1 joe } 187 1.1 joe 188 1.1 joe solock(so); 189 1.1 joe 190 1.1 joe kauth_cred_t cred = kauth_cred_alloc(); 191 1.1 joe kauth_cred_seteuid(cred, uid); 192 1.1 joe kauth_cred_setegid(cred, gid); 193 1.1 joe 194 1.1 joe kauth_cred_t old = so->so_cred; 195 1.1 joe so->so_cred = kauth_cred_dup(cred); 196 1.1 joe kauth_cred_free(old); 197 1.1 joe 198 1.1 joe sounlock(so); 199 1.1 joe 200 1.1 joe if ((error = sobind(so, (struct sockaddr *)&server, cur)) != 0) { 201 1.1 joe printf("bind failed %d\n", error); 202 1.1 joe return NULL; 203 1.1 joe } 204 1.1 joe 205 1.1 joe if (dir == PFIL_OUT) { 206 1.1 joe /* connect to an additional remote address to set the 4 tuple addr-port state */ 207 1.1 joe struct sockaddr_in remote; 208 1.2 skrll memset(&remote, 0, sizeof(remote)); 209 1.1 joe 210 1.1 joe remote.sin_len = sizeof(remote); 211 1.1 joe remote.sin_family = AF_INET; 212 1.1 joe rp = &remote.sin_addr.s_addr; 213 1.1 joe npf_inet_pton(AF_INET, REMOTE_IP, rp); /* we connect to 127.0.0.1 */ 214 1.1 joe remote.sin_port = htons(REMOTE_PORT); 215 1.1 joe 216 1.1 joe solock(so); 217 1.1 joe if ((error = soconnect(so, (struct sockaddr *)&remote, cur)) != 0) { 218 1.1 joe printf("connect failed :%d\n", error); 219 1.1 joe return NULL; 220 1.1 joe } 221 1.1 joe sounlock(so); 222 1.1 joe } 223 1.1 joe 224 1.1 joe return so; 225 1.1 joe } 226 1.1 joe 227 1.1 joe static bool 228 1.1 joe test_static(bool verbose) 229 1.1 joe { 230 1.1 joe for (size_t i = 0; i < __arraycount(test_cases); i++) { 231 1.1 joe const struct test_case *t = &test_cases[i]; 232 1.1 joe int error, serror; 233 1.1 joe struct socket *so; 234 1.1 joe 235 1.1 joe so = test_socket(t->di, t->uid, t->gid); 236 1.1 joe if (so == NULL) { 237 1.1 joe printf("socket:\n"); 238 1.1 joe return false; 239 1.1 joe } 240 1.1 joe 241 1.1 joe if (npf_test_getif(t->ifname) == NULL) { 242 1.1 joe printf("Interface %s is not configured.\n", t->ifname); 243 1.1 joe return false; 244 1.1 joe } 245 1.1 joe 246 1.1 joe error = run_raw_testcase(i, verbose); 247 1.1 joe serror = run_handler_testcase(i); 248 1.1 joe 249 1.1 joe if (verbose) { 250 1.2 skrll printf("rule test %zu:\texpected %d (stateful) and %d\n" 251 1.1 joe "\t\t-> returned %d and %d\n", 252 1.1 joe i + 1, t->stateful_ret, t->ret, serror, error); 253 1.1 joe } 254 1.1 joe CHECK_TRUE(error == t->ret); 255 1.1 joe CHECK_TRUE(serror == t->stateful_ret) 256 1.1 joe 257 1.1 joe soclose(so); 258 1.1 joe } 259 1.1 joe return true; 260 1.1 joe } 261 1.1 joe 262 1.1 joe bool 263 1.1 joe npf_guid_test(bool verbose) 264 1.1 joe { 265 1.1 joe soinit1(); 266 1.1 joe 267 1.1 joe bool ok; 268 1.1 joe 269 1.1 joe ok = test_static(verbose); 270 1.1 joe CHECK_TRUE(ok); 271 1.1 joe 272 1.1 joe return true; 273 1.2 skrll } 274