1*070d9e35SGleb Smirnoff /*- 2*070d9e35SGleb Smirnoff * SPDX-License-Identifier: BSD-2-Clause 3*070d9e35SGleb Smirnoff * 4*070d9e35SGleb Smirnoff * Copyright (c) 2023 Gleb Smirnoff <glebius@FreeBSD.org> 5*070d9e35SGleb Smirnoff * 6*070d9e35SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 7*070d9e35SGleb Smirnoff * modification, are permitted provided that the following conditions 8*070d9e35SGleb Smirnoff * are met: 9*070d9e35SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 10*070d9e35SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 11*070d9e35SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 12*070d9e35SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 13*070d9e35SGleb Smirnoff * documentation and/or other materials provided with the distribution. 14*070d9e35SGleb Smirnoff * 15*070d9e35SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*070d9e35SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*070d9e35SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*070d9e35SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*070d9e35SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*070d9e35SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*070d9e35SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*070d9e35SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*070d9e35SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*070d9e35SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*070d9e35SGleb Smirnoff * SUCH DAMAGE. 26*070d9e35SGleb Smirnoff */ 27*070d9e35SGleb Smirnoff 28*070d9e35SGleb Smirnoff #include <sys/socket.h> 29*070d9e35SGleb Smirnoff #include <netinet/in.h> 30*070d9e35SGleb Smirnoff #include <errno.h> 31*070d9e35SGleb Smirnoff #include <fcntl.h> 32*070d9e35SGleb Smirnoff #include <string.h> 33*070d9e35SGleb Smirnoff 34*070d9e35SGleb Smirnoff #include <atf-c.h> 35*070d9e35SGleb Smirnoff 36*070d9e35SGleb Smirnoff static int 37*070d9e35SGleb Smirnoff tcp4_listensock(struct sockaddr_in *sin) 38*070d9e35SGleb Smirnoff { 39*070d9e35SGleb Smirnoff int l; 40*070d9e35SGleb Smirnoff 41*070d9e35SGleb Smirnoff ATF_REQUIRE((l = socket(PF_INET, SOCK_STREAM, 0)) > 0); 42*070d9e35SGleb Smirnoff ATF_REQUIRE(setsockopt(l, SOL_SOCKET, SO_REUSEADDR, &(socklen_t){1}, 43*070d9e35SGleb Smirnoff sizeof(int)) == 0); 44*070d9e35SGleb Smirnoff *sin = (struct sockaddr_in){ 45*070d9e35SGleb Smirnoff .sin_len = sizeof(sin), 46*070d9e35SGleb Smirnoff .sin_family = AF_INET, 47*070d9e35SGleb Smirnoff .sin_addr.s_addr = htonl(INADDR_LOOPBACK), 48*070d9e35SGleb Smirnoff }; 49*070d9e35SGleb Smirnoff ATF_REQUIRE(bind(l, (struct sockaddr *)sin, sizeof(*sin)) == 0); 50*070d9e35SGleb Smirnoff ATF_REQUIRE(getsockname(l, (struct sockaddr *)sin, 51*070d9e35SGleb Smirnoff &(socklen_t){ sizeof(*sin) }) == 0); 52*070d9e35SGleb Smirnoff ATF_REQUIRE(listen(l, -1) == 0); 53*070d9e35SGleb Smirnoff 54*070d9e35SGleb Smirnoff return (l); 55*070d9e35SGleb Smirnoff } 56*070d9e35SGleb Smirnoff 57*070d9e35SGleb Smirnoff static int 58*070d9e35SGleb Smirnoff tcp4_clientsock(struct sockaddr_in *sin) 59*070d9e35SGleb Smirnoff { 60*070d9e35SGleb Smirnoff int s; 61*070d9e35SGleb Smirnoff 62*070d9e35SGleb Smirnoff ATF_REQUIRE((s = socket(PF_INET, SOCK_STREAM, 0)) > 0); 63*070d9e35SGleb Smirnoff ATF_REQUIRE(connect(s, (struct sockaddr *)sin, sizeof(*sin)) == 0); 64*070d9e35SGleb Smirnoff 65*070d9e35SGleb Smirnoff return (s); 66*070d9e35SGleb Smirnoff } 67*070d9e35SGleb Smirnoff 68*070d9e35SGleb Smirnoff ATF_TC_WITHOUT_HEAD(tcp4_zerolen); 69*070d9e35SGleb Smirnoff ATF_TC_BODY(tcp4_zerolen, tc) 70*070d9e35SGleb Smirnoff { 71*070d9e35SGleb Smirnoff static char canary[sizeof(struct sockaddr_in)] = 72*070d9e35SGleb Smirnoff { [0 ... sizeof(struct sockaddr_in) - 1] = 0xa }; 73*070d9e35SGleb Smirnoff struct sockaddr_in sin, ret; 74*070d9e35SGleb Smirnoff socklen_t salen; 75*070d9e35SGleb Smirnoff int l; 76*070d9e35SGleb Smirnoff 77*070d9e35SGleb Smirnoff l = tcp4_listensock(&sin); 78*070d9e35SGleb Smirnoff (void )tcp4_clientsock(&sin); 79*070d9e35SGleb Smirnoff 80*070d9e35SGleb Smirnoff memcpy(&ret, &canary, sizeof(ret)); 81*070d9e35SGleb Smirnoff salen = 0; 82*070d9e35SGleb Smirnoff ATF_REQUIRE(accept(l, (struct sockaddr *)&ret, &salen) > 0); 83*070d9e35SGleb Smirnoff ATF_REQUIRE(memcmp(&ret, &canary, sizeof(ret)) == 0); 84*070d9e35SGleb Smirnoff #if 0 85*070d9e35SGleb Smirnoff /* Linux behavior. Matches my reading of accept(2) and POSIX. */ 86*070d9e35SGleb Smirnoff ATF_REQUIRE(salen == sizeof(struct sockaddr_in)); 87*070d9e35SGleb Smirnoff #endif 88*070d9e35SGleb Smirnoff /* Note: Linux will block for connection here, we fail immediately. */ 89*070d9e35SGleb Smirnoff ATF_REQUIRE(accept(l, (struct sockaddr *)&ret, NULL) == -1); 90*070d9e35SGleb Smirnoff ATF_REQUIRE(errno == EFAULT); 91*070d9e35SGleb Smirnoff } 92*070d9e35SGleb Smirnoff 93*070d9e35SGleb Smirnoff ATF_TC_WITHOUT_HEAD(tcp4); 94*070d9e35SGleb Smirnoff ATF_TC_BODY(tcp4, tc) 95*070d9e35SGleb Smirnoff { 96*070d9e35SGleb Smirnoff struct sockaddr_in sin, ret; 97*070d9e35SGleb Smirnoff socklen_t salen; 98*070d9e35SGleb Smirnoff int l, s; 99*070d9e35SGleb Smirnoff 100*070d9e35SGleb Smirnoff l = tcp4_listensock(&sin); 101*070d9e35SGleb Smirnoff s = tcp4_clientsock(&sin); 102*070d9e35SGleb Smirnoff 103*070d9e35SGleb Smirnoff salen = sizeof(struct sockaddr_in) + 2; 104*070d9e35SGleb Smirnoff ATF_REQUIRE(accept(l, (struct sockaddr *)&ret, &salen) > 0); 105*070d9e35SGleb Smirnoff ATF_REQUIRE(salen == sizeof(struct sockaddr_in)); 106*070d9e35SGleb Smirnoff ATF_REQUIRE(getsockname(s, (struct sockaddr *)&sin, 107*070d9e35SGleb Smirnoff &(socklen_t){ sizeof(sin) }) == 0); 108*070d9e35SGleb Smirnoff ATF_REQUIRE(memcmp(&ret, &sin, sizeof(sin)) == 0); 109*070d9e35SGleb Smirnoff } 110*070d9e35SGleb Smirnoff 111*070d9e35SGleb Smirnoff ATF_TC_WITHOUT_HEAD(tcp4_noaddr); 112*070d9e35SGleb Smirnoff ATF_TC_BODY(tcp4_noaddr, tc) 113*070d9e35SGleb Smirnoff { 114*070d9e35SGleb Smirnoff struct sockaddr_in sin; 115*070d9e35SGleb Smirnoff int l; 116*070d9e35SGleb Smirnoff 117*070d9e35SGleb Smirnoff l = tcp4_listensock(&sin); 118*070d9e35SGleb Smirnoff (void )tcp4_clientsock(&sin); 119*070d9e35SGleb Smirnoff 120*070d9e35SGleb Smirnoff ATF_REQUIRE(accept(l, NULL, NULL) > 0); 121*070d9e35SGleb Smirnoff } 122*070d9e35SGleb Smirnoff 123*070d9e35SGleb Smirnoff ATF_TP_ADD_TCS(tp) 124*070d9e35SGleb Smirnoff { 125*070d9e35SGleb Smirnoff ATF_TP_ADD_TC(tp, tcp4); 126*070d9e35SGleb Smirnoff ATF_TP_ADD_TC(tp, tcp4_noaddr); 127*070d9e35SGleb Smirnoff ATF_TP_ADD_TC(tp, tcp4_zerolen); 128*070d9e35SGleb Smirnoff 129*070d9e35SGleb Smirnoff return (atf_no_error()); 130*070d9e35SGleb Smirnoff } 131