Skip to content

Commit 89c60ce

Browse files
committed
testing
in this testing, a socket is crafted in kernel to listen on any address( all interfaces) and port 65000 which is ideal for testing to test, run : npfctl debug -c $dir_to_npftest.conf -o ./npf.plist npftest -c ./npf.plist -T guid -v
1 parent 308d994 commit 89c60ce

File tree

10 files changed

+298
-8
lines changed

10 files changed

+298
-8
lines changed

sys/net/npf/npf_handler.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ npfk_packet_handler(npf_t *npf, struct mbuf **mp, ifnet_t *ifp, int di)
251251
error = npf_rule_reverse(&npc, &mi, error);
252252
}
253253

254-
if (error) {
254+
/* reject packets whose addr-port pair matches no sockets */
255+
if (id_match == ENOTCONN || error) {
255256
npf_stats_inc(npf, NPF_STAT_BLOCK_RULESET);
256257
goto block;
257258
}

sys/net/npf/npf_ruleset.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,7 +1013,7 @@ int
10131013
npf_rule_match_rid(npf_rule_t *rl, npf_cache_t *npc, int dir)
10141014
{
10151015
uint32_t sock_gid, sock_uid;
1016-
int matched = 0;
1016+
bool uid_matched = false, gid_matched = false;
10171017

10181018
if (rl->gid.op == NPF_OP_NONE && rl->uid.op == NPF_OP_NONE)
10191019
return -1; /* quickly return if packet has nothing to do with rids */
@@ -1025,16 +1025,20 @@ npf_rule_match_rid(npf_rule_t *rl, npf_cache_t *npc, int dir)
10251025
if (npf_socket_lookup_rid(npc, kauth_cred_getegid, &sock_gid, dir) == -1)
10261026
return ENOTCONN;
10271027

1028-
matched |= npf_match_rid(&rl->gid, sock_gid);
1028+
gid_matched = npf_match_rid(&rl->gid, sock_gid);
10291029
}
10301030
if (rl->uid.op != NPF_OP_NONE) {
10311031
if (npf_socket_lookup_rid(npc, kauth_cred_geteuid, &sock_uid, dir) == -1)
10321032
return ENOTCONN;
10331033

1034-
matched |= npf_match_rid(&rl->uid, sock_uid);
1034+
uid_matched = npf_match_rid(&rl->uid, sock_uid);
10351035
}
10361036

1037-
return matched;
1037+
/* if both uid and gid are set on rule, both must be matching to agree */
1038+
if (rl->gid.op && rl->uid.op)
1039+
return gid_matched && uid_matched;
1040+
else
1041+
return gid_matched || uid_matched;
10381042
}
10391043

10401044
/*

usr.sbin/npf/npftest/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ DPADD+= ${LIBNPFTEST}/libnpftest.a
1818
LDADD+= -L${LIBNPFTEST} -lnpftest
1919

2020
LDADD+= -lrump -lrumpvfs_nofifofs -lrumpvfs -lrumpuser
21-
LDADD+= -lrumpnet -lrumpnet_net -lrumpdev_bpf
21+
LDADD+= -lrumpnet -lrumpnet_net -lrumpdev_bpf -lrumpnet_netinet
2222

2323
.if ${RUMP_SANITIZE:Uno} != "no"
2424
LDADD+= -fsanitize=${RUMP_SANITIZE}

usr.sbin/npf/npftest/libnpftest/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SRCS+= npf_gc_test.c
1818
SRCS+= npf_state_test.c
1919
SRCS+= npf_rule_test.c
2020
SRCS+= npf_nat_test.c
21+
SRCS+= npf_rid_test.c
2122

2223
SRCS+= npf_perf_test.c
2324

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

usr.sbin/npf/npftest/libnpftest/npf_rule_test.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ static const struct test_case {
190190
.ifname = IFNAME_INT, .di = PFIL_OUT,
191191
.stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK
192192
},
193-
194193
};
195194

196195
static int

usr.sbin/npf/npftest/libnpftest/npf_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ bool npf_table_test(bool, void *, size_t);
121121
bool npf_state_test(bool);
122122

123123
bool npf_rule_test(bool);
124+
bool npf_guid_test(bool);
124125
bool npf_nat_test(bool);
125126
bool npf_gc_test(bool);
126127

usr.sbin/npf/npftest/npftest.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ describe_tests(void)
6666
"state\tstate handling and processing\n"
6767
"gc\tconnection G/C\n"
6868
"rule\trule processing\n"
69-
"nat\tNAT rule processing\n");
69+
"nat\tNAT rule processing\n"
70+
"guid\tUser/group filtering\n");
7071
exit(EXIT_SUCCESS);
7172
}
7273

@@ -323,6 +324,12 @@ main(int argc, char **argv)
323324
tname_matched = true;
324325
}
325326

327+
if (!testname || strcmp("guid", testname) == 0) {
328+
ok = rumpns_npf_guid_test(verbose);
329+
fail |= result("guid", ok);
330+
tname_matched = true;
331+
}
332+
326333
if (!testname || strcmp("nat", testname) == 0) {
327334
srandom(1);
328335
ok = rumpns_npf_nat_test(verbose);

usr.sbin/npf/npftest/npftest.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ $local_ip1 = 10.1.1.1
1818
$local_ip2 = 10.1.1.2
1919
$local_ip3 = 10.1.1.3
2020
$local_ip4 = 10.1.1.4
21+
$Kojo = 1001
22+
$wheel = 20
2123

2224
$local_net = { 10.1.1.0/24 }
2325
$ports = { 8000, 9000 }
@@ -44,6 +46,8 @@ map ruleset "map:some-daemon" on $ext_if
4446
group "ext" on $ext_if {
4547
pass out final from $local_ip3
4648
pass in final to $pub_ip3
49+
pass in final from $local_ip4 user $Kojo group $wheel
50+
block out final to 127.0.0.1 user > $Kojo group 1 >< $wheel
4751

4852
pass out final from $net6_inner
4953
pass in final to $net6_outer

0 commit comments

Comments
 (0)