Skip to content

Commit 7ae56f4

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 7ae56f4

File tree

10 files changed

+297
-8
lines changed

10 files changed

+297
-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+
/* sidewaysh handling of rejecting 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+
int uid_matched = 0, gid_matched = 0;
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+
/* make sure if both uid and gid is set on rule, both must be mtching 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: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
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)
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+
printf("id match is ...%d\n", id_match);
128+
if (id_match != -1 && !id_match) {
129+
error = npf_rule_reverse(npc, &mi, error);
130+
}
131+
132+
} else {
133+
error = ENOENT;
134+
}
135+
npf_config_read_exit(npf, slock);
136+
137+
put_cached_pkt(npc);
138+
return error;
139+
}
140+
141+
static int
142+
run_handler_testcase(unsigned i)
143+
{
144+
const struct test_case *t = &test_cases[i];
145+
ifnet_t *ifp = npf_test_getif(t->ifname);
146+
npf_t *npf = npf_getkernctx();
147+
struct mbuf *m;
148+
int error;
149+
150+
m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, t->sport, t->dport);
151+
error = npfk_packet_handler(npf, &m, ifp, t->di);
152+
if (m) {
153+
m_freem(m);
154+
}
155+
return error;
156+
}
157+
158+
/*
159+
* we create our specific server socket here which listens on
160+
* any interface(address) and port 65000. easier to test pcb lookup here since
161+
* it will be loaded into the protocol table.
162+
*/
163+
static struct socket *
164+
test_socket(int dir, uid_t uid, gid_t gid)
165+
{
166+
struct sockaddr_in Server;
167+
struct lwp *cur = curlwp;
168+
void *p, *rp;
169+
170+
memset(&Server, 0, sizeof(Server));
171+
172+
Server.sin_len = sizeof(Server);
173+
Server.sin_family = AF_INET;
174+
p = &Server.sin_addr.s_addr;
175+
npf_inet_pton(AF_INET, LOCAL_IP, p); /* we bind to 127.0.0.1 */
176+
Server.sin_port = htons(LOCAL_PORT);
177+
178+
struct socket *so;
179+
int error = socreate(AF_INET, &so, SOCK_DGRAM, 0, cur, NULL);
180+
if(error) {
181+
printf("socket creation failed: error is %d\n", error);
182+
return NULL;
183+
}
184+
185+
solock(so);
186+
187+
kauth_cred_t cred = kauth_cred_alloc();
188+
kauth_cred_seteuid(cred, uid);
189+
kauth_cred_setegid(cred, gid);
190+
191+
kauth_cred_t old = so->so_cred;
192+
so->so_cred = kauth_cred_dup(cred);
193+
kauth_cred_free(old);
194+
195+
sounlock(so);
196+
197+
if((error = sobind(so, (struct sockaddr *)&Server, cur)) != 0) {
198+
printf("bind failed %d\n", error);
199+
return NULL;
200+
}
201+
202+
if (dir == PFIL_OUT) {
203+
/* connect to an additional remote address to set the 4 tuple addr-port state */
204+
struct sockaddr_in Remote;
205+
memset(&Remote, 0, sizeof(Remote));
206+
207+
Remote.sin_len = sizeof(Remote);
208+
Remote.sin_family = AF_INET;
209+
rp = &Remote.sin_addr.s_addr;
210+
npf_inet_pton(AF_INET, REMOTE_IP, rp); /* we connect to 127.0.0.1 */
211+
Remote.sin_port = htons(REMOTE_PORT);
212+
213+
solock(so);
214+
if ((error = soconnect(so, (struct sockaddr *)&Remote, cur)) != 0) {
215+
printf("connect failed :%d\n", error);
216+
return NULL;
217+
}
218+
sounlock(so);
219+
}
220+
221+
return so;
222+
}
223+
224+
static bool
225+
test_static(bool verbose)
226+
{
227+
for (unsigned i = 0; i < __arraycount(test_cases); i++) {
228+
const struct test_case *t = &test_cases[i];
229+
int error, serror;
230+
struct socket *so;
231+
232+
so = test_socket(t->di, t->uid, t->gid);
233+
if (so == NULL) {
234+
printf("socket:\n");
235+
return false;
236+
}
237+
238+
if (npf_test_getif(t->ifname) == NULL) {
239+
printf("Interface %s is not configured.\n", t->ifname);
240+
return false;
241+
}
242+
243+
error = run_raw_testcase(i);
244+
serror = run_handler_testcase(i);
245+
246+
if (verbose) {
247+
printf("rule test %d:\texpected %d (stateful) and %d\n"
248+
"\t\t-> returned %d and %d\n",
249+
i + 1, t->stateful_ret, t->ret, serror, error);
250+
}
251+
CHECK_TRUE(error == t->ret);
252+
CHECK_TRUE(serror == t->stateful_ret)
253+
254+
soclose(so);
255+
}
256+
return true;
257+
}
258+
259+
bool
260+
npf_guid_test(bool verbose)
261+
{
262+
soinit1();
263+
264+
bool ok;
265+
266+
ok = test_static(verbose);
267+
CHECK_TRUE(ok);
268+
269+
return true;
270+
}

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)