1 /*
2  * Test network address functions for IPv4.
3  *
4  * The canonical version of this file is maintained in the rra-c-util package,
5  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
6  *
7  * Written by Russ Allbery <eagle@eyrie.org>
8  * Copyright 2005, 2013, 2016, 2020 Russ Allbery <eagle@eyrie.org>
9  * Copyright 2009-2013
10  *     The Board of Trustees of the Leland Stanford Junior University
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  *
30  * SPDX-License-Identifier: MIT
31  */
32 
33 #define LIBTEST_NEW_FORMAT 1
34 
35 #include "config.h"
36 #include "portable/socket.h"
37 #include "portable/system.h"
38 
39 #include "inn/network.h"
40 #include "tap/basic.h"
41 
42 
43 /*
44  * Tests network_addr_compare.  Takes the expected result, the two addresses,
45  * and the mask.
46  */
47 static void
is_addr_compare(bool expected,const char * a,const char * b,const char * mask)48 is_addr_compare(bool expected, const char *a, const char *b, const char *mask)
49 {
50     const char *smask = (mask == NULL) ? "(null)" : mask;
51 
52     if (expected)
53         ok(network_addr_match(a, b, mask), "compare %s %s %s", a, b, smask);
54     else
55         ok(!network_addr_match(a, b, mask), "compare %s %s %s", a, b, smask);
56 }
57 
58 
59 int
main(void)60 main(void)
61 {
62 #ifdef SO_REUSEADDR
63     int flag;
64     socklen_t flaglen;
65 #endif
66     int status;
67     struct addrinfo *ai, *ai2;
68     struct addrinfo hints;
69     char addr[INET6_ADDRSTRLEN];
70     socket_type fd;
71     static const char *port = "119";
72 
73     /* Set up the plan. */
74     plan(31);
75 
76     /* Get a sockaddr to use for subsequent tests. */
77     memset(&hints, 0, sizeof(hints));
78     hints.ai_flags = AI_NUMERICHOST;
79     hints.ai_socktype = SOCK_STREAM;
80     status = getaddrinfo("127.0.0.1", port, &hints, &ai);
81     if (status != 0)
82         bail("getaddrinfo on 127.0.0.1 failed: %s", gai_strerror(status));
83 
84     /* Test network_sockaddr_sprint. */
85     ok(network_sockaddr_sprint(addr, sizeof(addr), ai->ai_addr),
86        "sprint of 127.0.0.1");
87     is_string("127.0.0.1", addr, "...with right results");
88 
89     /* Test network_sockaddr_port. */
90     is_int(119, network_sockaddr_port(ai->ai_addr), "sockaddr_port");
91 
92     /* Test network_sockaddr_equal. */
93     ok(network_sockaddr_equal(ai->ai_addr, ai->ai_addr), "sockaddr_equal");
94     status = getaddrinfo("127.0.0.2", NULL, &hints, &ai2);
95     if (status != 0)
96         bail("getaddrinfo on 127.0.0.2 failed: %s", gai_strerror(status));
97     ok(!network_sockaddr_equal(ai->ai_addr, ai2->ai_addr),
98        "sockaddr_equal of unequal addresses");
99     ok(!network_sockaddr_equal(ai2->ai_addr, ai->ai_addr),
100        "...and the other way around");
101     freeaddrinfo(ai2);
102 
103     /* Check the domains of functions and their error handling. */
104     ai->ai_addr->sa_family = AF_UNIX;
105     ok(!network_sockaddr_equal(ai->ai_addr, ai->ai_addr),
106        "network_sockaddr_equal returns false for equal AF_UNIX addresses");
107     is_int(0, network_sockaddr_port(ai->ai_addr),
108            "port meaningless for AF_UNIX");
109     freeaddrinfo(ai);
110 
111     /* Tests for network_addr_compare. */
112     /* clang-format off */
113     is_addr_compare(1, "127.0.0.1", "127.0.0.1",   NULL);
114     is_addr_compare(0, "127.0.0.1", "127.0.0.2",   NULL);
115     is_addr_compare(1, "127.0.0.1", "127.0.0.0",   "31");
116     is_addr_compare(0, "127.0.0.1", "127.0.0.0",   "32");
117     is_addr_compare(0, "127.0.0.1", "127.0.0.0",   "255.255.255.255");
118     is_addr_compare(1, "127.0.0.1", "127.0.0.0",   "255.255.255.254");
119     is_addr_compare(1, "10.10.4.5", "10.10.4.255", "24");
120     is_addr_compare(0, "10.10.4.5", "10.10.4.255", "25");
121     is_addr_compare(1, "10.10.4.5", "10.10.4.255", "255.255.255.0");
122     is_addr_compare(0, "10.10.4.5", "10.10.4.255", "255.255.255.128");
123     is_addr_compare(0, "129.0.0.0", "1.0.0.0",     "1");
124     is_addr_compare(1, "129.0.0.0", "1.0.0.0",     "0");
125     is_addr_compare(1, "129.0.0.0", "1.0.0.0",     "0.0.0.0");
126     /* clang-format on */
127 
128     /* Test some invalid addresses. */
129     /* clang-format off */
130     is_addr_compare(0, "fred",      "fred",        NULL);
131     is_addr_compare(0, "",          "",            NULL);
132     is_addr_compare(0, "",          "",            "0");
133     is_addr_compare(0, "127.0.0.1", "127.0.0.1",   "pete");
134     is_addr_compare(0, "127.0.0.1", "127.0.0.1",   "1p");
135     is_addr_compare(0, "127.0.0.1", "127.0.0.1",   "1p");
136     is_addr_compare(0, "127.0.0.1", "127.0.0.1",   "-1");
137     is_addr_compare(0, "127.0.0.1", "127.0.0.1",   "33");
138     /* clang-format on */
139 
140     /* Test setting various socket options. */
141     fd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
142     if (fd == INVALID_SOCKET)
143         sysbail("cannot create socket");
144     network_set_reuseaddr(fd);
145 #ifdef SO_REUSEADDR
146     flag = 0;
147     flaglen = sizeof(flag);
148     is_int(0, getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, &flaglen),
149            "Getting SO_REUSEADDR works");
150     ok(flag, "...and it is set");
151 #else
152     skip_block(2, "SO_REUSEADDR not supported");
153 #endif
154     close(fd);
155     return 0;
156 }
157