1132649Srwatson/*-
2132649Srwatson * Copyright (c) 2004 Robert N. M. Watson
3132649Srwatson * All rights reserved.
4132649Srwatson *
5132649Srwatson * Redistribution and use in source and binary forms, with or without
6132649Srwatson * modification, are permitted provided that the following conditions
7132649Srwatson * are met:
8132649Srwatson * 1. Redistributions of source code must retain the above copyright
9132649Srwatson *    notice, this list of conditions and the following disclaimer.
10132649Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11132649Srwatson *    notice, this list of conditions and the following disclaimer in the
12132649Srwatson *    documentation and/or other materials provided with the distribution.
13132649Srwatson *
14132649Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132649Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132649Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132649Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132649Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132649Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132649Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132649Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132649Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132649Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132649Srwatson * SUCH DAMAGE.
25132649Srwatson *
26132649Srwatson * $FreeBSD$
27132649Srwatson */
28132649Srwatson
29132649Srwatson#include <sys/types.h>
30294103Sngie#include <sys/module.h>
31132649Srwatson#include <sys/socket.h>
32132649Srwatson
33132649Srwatson#include <netinet/in.h>
34132649Srwatson
35132649Srwatson#include <err.h>
36132649Srwatson#include <errno.h>
37132649Srwatson#include <stdio.h>
38132649Srwatson#include <stdlib.h>
39132649Srwatson#include <string.h>
40132649Srwatson#include <unistd.h>
41132649Srwatson
42132649Srwatson#define	ACCF_NAME	"dataready"
43132649Srwatson
44132649Srwatson/*
45132649Srwatson * A number of small tests to confirm that attaching ACCF_DATA accept filters
46132649Srwatson * to inet4 ports works as expected.  We test:
47132649Srwatson *
48132649Srwatson * - That no accept filter is attached on a newly created socket.
49132649Srwatson * - That bind() has no affect on the accept filter state.
50132649Srwatson * - That we can't attach an accept filter to a socket that isn't in the
51132649Srwatson *   listen state.
52132649Srwatson * - That after we fail to attach the filter, querying the kernel shows no
53132649Srwatson *   filter attached.
54132649Srwatson * - That we can attach an accept filter to a socket that is in the listen
55132649Srwatson *   state.
56132649Srwatson * - That once an accept filter is attached, we can query to make sure it is
57132649Srwatson *   attached.
58147300Smaxim * - That once an accept filter is attached, we can remove it and query to
59147300Smaxim *   make sure it is removed.
60132649Srwatson */
61132649Srwatsonint
62281355Sngiemain(void)
63132649Srwatson{
64132649Srwatson	struct accept_filter_arg afa;
65132649Srwatson	struct sockaddr_in sin;
66132649Srwatson	socklen_t len;
67132649Srwatson	int lso, ret;
68132649Srwatson
69294103Sngie	/* XXX: PLAIN_TEST_REQUIRE_MODULE "backport" for stable/9 */
70294103Sngie	const char *_mod_name = "accf_data";
71294103Sngie
72294103Sngie	if (modfind(_mod_name) == -1) {
73294103Sngie		printf("1..0 # SKIP - module %s could not be resolved: %s\n",
74294103Sngie		    _mod_name, strerror(errno));
75294103Sngie		_exit(0);
76294103Sngie	}
77294103Sngie	/* XXX: PLAIN_TEST_REQUIRE_MODULE for stable/9 */
78294103Sngie
79147300Smaxim	printf("1..11\n");
80137587Snik
81132649Srwatson	/*
82132649Srwatson	 * Step 0. Open socket().
83132649Srwatson	 */
84132649Srwatson	lso = socket(PF_INET, SOCK_STREAM, 0);
85132649Srwatson	if (lso == -1)
86137587Snik		errx(-1, "not ok 1 - socket: %s", strerror(errno));
87137587Snik	printf("ok 1 - socket\n");
88132649Srwatson
89132649Srwatson	/*
90132649Srwatson	 * Step 1. After socket().  Should return EINVAL, since no accept
91132649Srwatson	 * filter should be attached.
92132649Srwatson	 */
93132649Srwatson	bzero(&afa, sizeof(afa));
94132649Srwatson	len = sizeof(afa);
95132649Srwatson	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
96136844Srwatson	if (ret != -1)
97137587Snik		errx(-1, "not ok 2 - getsockopt() after socket() succeeded");
98136844Srwatson	if (errno != EINVAL)
99137587Snik		errx(-1, "not ok 2 - getsockopt() after socket() failed with "
100136844Srwatson		    "%d (%s)", errno, strerror(errno));
101137587Snik	printf("ok 2 - getsockopt\n");
102132649Srwatson
103132649Srwatson	/*
104132649Srwatson	 * Step 2. Bind().  Ideally this will succeed.
105132649Srwatson	 */
106132649Srwatson	bzero(&sin, sizeof(sin));
107132649Srwatson	sin.sin_len = sizeof(sin);
108132649Srwatson	sin.sin_family = AF_INET;
109132649Srwatson	sin.sin_port = htons(8080);
110132649Srwatson	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
111132649Srwatson	if (bind(lso, (struct sockaddr *)&sin, sizeof(sin)) < 0)
112137587Snik		errx(-1, "not ok 3 - bind %s", strerror(errno));
113137587Snik	printf("ok 3 - bind\n");
114132649Srwatson
115132649Srwatson	/*
116132649Srwatson	 * Step 3: After bind().  getsockopt() should return EINVAL, since no
117132649Srwatson	 *  accept filter should be attached.
118132649Srwatson	 */
119132649Srwatson	len = sizeof(afa);
120132649Srwatson	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
121136844Srwatson	if (ret != -1)
122137587Snik		errx(-1, "not ok 4 - getsockopt() after bind() succeeded");
123136844Srwatson	if (errno != EINVAL)
124137587Snik		errx(-1, "not ok 4 -  getsockopt() after bind() failed with %d (%s)",
125136844Srwatson		    errno, strerror(errno));
126137587Snik	printf("ok 4 - getsockopt\n");
127132649Srwatson
128132649Srwatson	/*
129132649Srwatson	 * Step 4: Setsockopt() before listen().  Should fail, since it's not
130132649Srwatson	 * yet a listen() socket.
131132649Srwatson	 */
132132649Srwatson	bzero(&afa, sizeof(afa));
133294103Sngie	strncpy(afa.af_name, ACCF_NAME, sizeof(afa.af_name));
134132649Srwatson	ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
135136844Srwatson	if (ret == 0)
136137587Snik		errx(-1, "not ok 5 - setsockopt() before listen() succeeded");
137137587Snik	printf("ok 5 - setsockopt\n");
138132649Srwatson
139132649Srwatson	/*
140132649Srwatson	 * Step 5: Getsockopt() after pre-listen() setsockopt().  Should
141132649Srwatson	 * fail with EINVAL, since setsockopt() should have failed.
142132649Srwatson	 */
143132649Srwatson	len = sizeof(afa);
144132649Srwatson	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
145136844Srwatson	if (ret == 0)
146137587Snik		errx(-1, "not ok 6 - getsockopt() after pre-listen() setsockopt() "
147136844Srwatson		    "succeeded");
148136844Srwatson	if (errno != EINVAL)
149137587Snik		errx(-1, "not ok 6 - pre-listen() getsockopt() failed with %d (%s)",
150136844Srwatson		    errno, strerror(errno));
151137587Snik	printf("ok 6 - getsockopt\n");
152132649Srwatson
153132649Srwatson	/*
154132649Srwatson	 * Step 6: listen().
155132649Srwatson	 */
156132649Srwatson	if (listen(lso, -1) < 0)
157137587Snik		errx(-1, "not ok 7 - listen: %s", strerror(errno));
158137587Snik	printf("ok 7 - listen\n");
159132649Srwatson
160132649Srwatson	/*
161147300Smaxim	 * Step 7: Getsockopt() after listen().  Should fail with EINVAL,
162147300Smaxim	 * since we have not installed accept filter yet.
163132649Srwatson	 */
164147300Smaxim	len = sizeof(afa);
165147300Smaxim	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
166147300Smaxim	if (ret == 0)
167147300Smaxim		errx(-1, "not ok 8 - getsockopt() after listen() but before "
168147300Smaxim		    "setsockopt() succeeded");
169147300Smaxim	if (errno != EINVAL)
170147300Smaxim		errx(-1, "not ok 8 - getsockopt() after listen() but before "
171147300Smaxim		    "setsockopt() failed with %d (%s)", errno, strerror(errno));
172147300Smaxim	printf("ok 8 - getsockopt\n");
173147300Smaxim
174147300Smaxim	/*
175147300Smaxim	 * Step 8: After listen().  This call to setsockopt() should succeed.
176147300Smaxim	 */
177132649Srwatson	bzero(&afa, sizeof(afa));
178294103Sngie	strncpy(afa.af_name, ACCF_NAME, sizeof(afa.af_name));
179132649Srwatson	ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa));
180136844Srwatson	if (ret != 0)
181147300Smaxim		errx(-1, "not ok 9 - setsockopt() after listen() failed with %d "
182136844Srwatson		    "(%s)", errno, strerror(errno));
183147300Smaxim	printf("ok 9 - setsockopt\n");
184132649Srwatson
185132649Srwatson	/*
186147300Smaxim	 * Step 9: After setsockopt().  Should succeed and identify
187132649Srwatson	 * ACCF_NAME.
188132649Srwatson	 */
189132649Srwatson	bzero(&afa, sizeof(afa));
190132649Srwatson	len = sizeof(afa);
191132649Srwatson	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
192136844Srwatson	if (ret != 0)
193147300Smaxim		errx(-1, "not ok 10 - getsockopt() after listen() setsockopt() "
194136844Srwatson		    "failed with %d (%s)", errno, strerror(errno));
195136844Srwatson	if (len != sizeof(afa))
196147300Smaxim		errx(-1, "not ok 10 - getsockopt() after setsockopet()  after "
197197432Sjhb		    "listen() returned wrong size (got %d expected %zd)", len,
198136844Srwatson		    sizeof(afa));
199136844Srwatson	if (strcmp(afa.af_name, ACCF_NAME) != 0)
200147300Smaxim		errx(-1, "not ok 10 - getsockopt() after setsockopt() after "
201136844Srwatson		    "listen() mismatch (got %s expected %s)", afa.af_name,
202136844Srwatson		    ACCF_NAME);
203147300Smaxim	printf("ok 10 - getsockopt\n");
204132649Srwatson
205147300Smaxim	/*
206147300Smaxim	 * Step 10: Remove accept filter.  After removing the accept filter
207147300Smaxim	 * getsockopt() should fail with EINVAL.
208147300Smaxim	 */
209147300Smaxim	ret = setsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0);
210147300Smaxim	if (ret != 0)
211147300Smaxim		errx(-1, "not ok 11 - setsockopt() after listen() "
212147300Smaxim		    "failed with %d (%s)", errno, strerror(errno));
213147300Smaxim	bzero(&afa, sizeof(afa));
214147300Smaxim	len = sizeof(afa);
215147300Smaxim	ret = getsockopt(lso, SOL_SOCKET, SO_ACCEPTFILTER, &afa, &len);
216147300Smaxim	if (ret == 0)
217147300Smaxim		errx(-1, "not ok 11 - getsockopt() after removing "
218147300Smaxim		    "the accept filter returns valid accept filter %s",
219147300Smaxim		    afa.af_name);
220147300Smaxim	if (errno != EINVAL)
221147300Smaxim		errx(-1, "not ok 11 - getsockopt() after removing the accept"
222147300Smaxim		    "filter failed with %d (%s)", errno, strerror(errno));
223147300Smaxim	printf("ok 11 - setsockopt\n");
224147300Smaxim
225132649Srwatson	close(lso);
226132649Srwatson	return (0);
227132649Srwatson}
228