1 /* $NetBSD: t_bpfilter.c,v 1.6 2012/09/03 21:27:14 alnsn Exp $ */
4 * Copyright (c) 2012 The NetBSD Foundation, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __RCSID("$NetBSD: t_bpfilter.c,v 1.6 2012/09/03 21:27:14 alnsn Exp $");
30 #include <sys/param.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
34 #include <sys/sysctl.h>
40 #include <net/if_ether.h>
48 #include <rump/rump.h>
49 #include <rump/rump_syscalls.h>
51 /* XXX: atf-c.h has collisions with mbuf */
56 #include "../../h_macros.h"
57 #include "../config/netconfig.c"
60 #define SNAPLEN UINT32_MAX
62 #define BMAGIC UINT32_C(0x37)
63 #define HMAGIC UINT32_C(0xc2c2)
64 #define WMAGIC UINT32_C(0x7d7d7d7d)
66 static const char magic_echo_reply_tail
[7] = {
77 * Match ICMP_ECHOREPLY packet with 7 magic bytes at the end.
79 static struct bpf_insn magic_echo_reply_prog
[] = {
80 BPF_STMT(BPF_LD
+BPF_ABS
+BPF_B
,
81 sizeof(struct ip
) + offsetof(struct icmp
, icmp_type
)),
82 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, ICMP_ECHOREPLY
, 1, 0),
83 BPF_STMT(BPF_RET
+BPF_K
, 0),
85 BPF_STMT(BPF_LD
+BPF_W
+BPF_LEN
, 0), /* A <- len */
86 BPF_STMT(BPF_ALU
+BPF_SUB
+BPF_K
, 7), /* A <- A - 7 */
87 BPF_STMT(BPF_MISC
+BPF_TAX
, 0), /* X <- A */
89 BPF_STMT(BPF_LD
+BPF_IND
+BPF_B
, 0),
90 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, BMAGIC
, 1, 0),
91 BPF_STMT(BPF_RET
+BPF_K
, 0),
93 BPF_STMT(BPF_LD
+BPF_IND
+BPF_H
, 1),
94 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, HMAGIC
, 1, 0),
95 BPF_STMT(BPF_RET
+BPF_K
, 0),
97 BPF_STMT(BPF_LD
+BPF_IND
+BPF_W
, 3),
98 BPF_JUMP(BPF_JMP
+BPF_JEQ
+BPF_K
, WMAGIC
, 1, 0),
99 BPF_STMT(BPF_RET
+BPF_K
, 0),
101 BPF_STMT(BPF_RET
+BPF_K
, SNAPLEN
)
105 in_cksum(void *data
, size_t len
)
107 uint16_t *buf
= data
;
110 for (sum
= 0; len
> 1; len
-= 2)
113 sum
+= *(uint8_t *)buf
;
115 sum
= (sum
>> 16) + (sum
& 0xffff);
122 * Based on netcfg_rump_pingtest().
125 pingtest(const char *dst
, unsigned int wirelen
, const char tail
[7])
128 struct sockaddr_in sin
;
131 unsigned int pktsize
;
136 if (wirelen
< ETHER_HDR_LEN
+ sizeof(struct ip
))
139 pktsize
= wirelen
- ETHER_HDR_LEN
- sizeof(struct ip
);
140 if (pktsize
< sizeof(struct icmp
) + 7)
143 s
= rump_sys_socket(PF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
151 if (rump_sys_setsockopt(s
, SOL_SOCKET
, SO_RCVTIMEO
,
152 &tv
, sizeof(tv
)) == -1)
155 memset(&sin
, 0, sizeof(sin
));
156 sin
.sin_len
= sizeof(sin
);
157 sin
.sin_family
= AF_INET
;
158 sin
.sin_addr
.s_addr
= inet_addr(dst
);
160 pkt
= calloc(1, pktsize
);
161 icmp
= (struct icmp
*)pkt
;
165 memcpy(pkt
+ pktsize
- 7, tail
, 7);
166 icmp
->icmp_type
= ICMP_ECHO
;
167 icmp
->icmp_id
= htons(37);
168 icmp
->icmp_seq
= htons(1);
169 icmp
->icmp_cksum
= in_cksum(pkt
, pktsize
);
172 if (rump_sys_sendto(s
, pkt
, pktsize
, 0,
173 (struct sockaddr
*)&sin
, slen
) == -1) {
177 if (rump_sys_recvfrom(s
, pkt
, pktsize
, 0,
178 (struct sockaddr
*)&sin
, &slen
) == -1)
190 magic_ping_test(const char *name
, unsigned int wirelen
)
192 struct bpf_program prog
;
193 struct bpf_stat bstat
;
196 unsigned int bufsize
;
209 prog
.bf_len
= __arraycount(magic_echo_reply_prog
);
210 prog
.bf_insns
= magic_echo_reply_prog
;
214 netcfg_rump_makeshmif(name
, ifr
.ifr_name
);
218 atf_tc_fail_errno("fork failed");
220 netcfg_rump_if(ifr
.ifr_name
, "10.1.1.10", "255.0.0.0");
222 ATF_CHECK(write(channel
[1], "U", 1) == 1);
230 netcfg_rump_if(ifr
.ifr_name
, "10.1.1.20", "255.0.0.0");
232 RL(bpfd
= rump_sys_open("/dev/bpf", O_RDONLY
));
236 RL(rump_sys_ioctl(bpfd
, BIOCSRTIMEOUT
, &tv
));
238 RL(rump_sys_ioctl(bpfd
, BIOCGBLEN
, &bufsize
));
239 RL(rump_sys_ioctl(bpfd
, BIOCSETF
, &prog
));
240 RL(rump_sys_ioctl(bpfd
, BIOCSETIF
, &ifr
));
243 ATF_CHECK(read(channel
[0], &token
, 1) == 1 && token
== 'U');
245 pinged
= pingtest("10.1.1.10", wirelen
, magic_echo_reply_tail
);
248 buf
= malloc(bufsize
);
249 hdr
= (struct bpf_hdr
*)buf
;
250 ATF_REQUIRE(buf
!= NULL
);
251 ATF_REQUIRE(bufsize
> sizeof(struct bpf_hdr
));
253 n
= rump_sys_read(bpfd
, buf
, bufsize
);
255 ATF_CHECK(n
> (int)sizeof(struct bpf_hdr
));
256 ATF_CHECK(hdr
->bh_caplen
== MIN(SNAPLEN
, wirelen
));
258 RL(rump_sys_ioctl(bpfd
, BIOCGSTATS
, &bstat
));
259 ATF_CHECK(bstat
.bs_capt
>= 1); /* XXX == 1 */
261 rump_sys_close(bpfd
);
266 kill(child
, SIGKILL
);
269 ATF_TC(bpfiltercontig
);
270 ATF_TC_HEAD(bpfiltercontig
, tc
)
273 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program "
274 "can read bytes from contiguous buffer.");
275 atf_tc_set_md_var(tc
, "timeout", "30");
278 ATF_TC_BODY(bpfiltercontig
, tc
)
281 magic_ping_test("bpfiltercontig", 128);
285 ATF_TC(bpfiltermchain
);
286 ATF_TC_HEAD(bpfiltermchain
, tc
)
289 atf_tc_set_md_var(tc
, "descr", "Checks that bpf program "
290 "can read bytes from mbuf chain.");
291 atf_tc_set_md_var(tc
, "timeout", "30");
294 ATF_TC_BODY(bpfiltermchain
, tc
)
297 magic_ping_test("bpfiltermchain", MINCLSIZE
+ 1);
304 ATF_TP_ADD_TC(tp
, bpfiltercontig
);
305 ATF_TP_ADD_TC(tp
, bpfiltermchain
);
307 return atf_no_error();