]>
Commit | Line | Data |
---|---|---|
5c3fa98d ZJS |
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | ||
3 | #include "alloc-util.h" | |
4 | #include "tests.h" | |
5 | #include "socket-netlink.h" | |
6 | #include "string-util.h" | |
7 | ||
8 | static void test_socket_address_parse_one(const char *in, int ret, int family, const char *expected) { | |
9 | SocketAddress a; | |
10 | _cleanup_free_ char *out = NULL; | |
11 | int r; | |
12 | ||
13 | r = socket_address_parse(&a, in); | |
14 | if (r >= 0) | |
15 | assert_se(socket_address_print(&a, &out) >= 0); | |
16 | ||
17 | log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in, | |
18 | r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); | |
19 | assert_se(r == ret); | |
20 | if (r >= 0) { | |
21 | assert_se(a.sockaddr.sa.sa_family == family); | |
22 | assert_se(streq(out, expected ?: in)); | |
23 | } | |
24 | } | |
25 | ||
26 | static void test_socket_address_parse(void) { | |
27 | log_info("/* %s */", __func__); | |
28 | ||
29 | test_socket_address_parse_one("junk", -EINVAL, 0, NULL); | |
30 | test_socket_address_parse_one("192.168.1.1", -EINVAL, 0, NULL); | |
31 | test_socket_address_parse_one(".168.1.1", -EINVAL, 0, NULL); | |
32 | test_socket_address_parse_one("989.168.1.1", -EINVAL, 0, NULL); | |
33 | test_socket_address_parse_one("192.168.1.1:65536", -ERANGE, 0, NULL); | |
34 | test_socket_address_parse_one("192.168.1.1:0", -EINVAL, 0, NULL); | |
35 | test_socket_address_parse_one("0", -EINVAL, 0, NULL); | |
36 | test_socket_address_parse_one("65536", -ERANGE, 0, NULL); | |
37 | ||
38 | const int default_family = socket_ipv6_is_supported() ? AF_INET6 : AF_INET; | |
39 | ||
40 | test_socket_address_parse_one("65535", 0, default_family, "[::]:65535"); | |
41 | ||
42 | /* The checks below will pass even if ipv6 is disabled in | |
43 | * kernel. The underlying glibc's inet_pton() is just a string | |
44 | * parser and doesn't make any syscalls. */ | |
45 | ||
46 | test_socket_address_parse_one("[::1]", -EINVAL, 0, NULL); | |
47 | test_socket_address_parse_one("[::1]8888", -EINVAL, 0, NULL); | |
48 | test_socket_address_parse_one("::1", -EINVAL, 0, NULL); | |
49 | test_socket_address_parse_one("[::1]:0", -EINVAL, 0, NULL); | |
50 | test_socket_address_parse_one("[::1]:65536", -ERANGE, 0, NULL); | |
51 | test_socket_address_parse_one("[a:b:1]:8888", -EINVAL, 0, NULL); | |
52 | ||
53 | test_socket_address_parse_one("8888", 0, default_family, "[::]:8888"); | |
54 | test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6, | |
55 | "[2001:db8:0:85a3::ac1f:8001]:8888"); | |
56 | test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL); | |
57 | test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL); | |
58 | test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL); | |
59 | test_socket_address_parse_one("/", 0, AF_UNIX, NULL); | |
60 | test_socket_address_parse_one("@abstract", 0, AF_UNIX, NULL); | |
61 | ||
62 | { | |
63 | char aaa[SUN_PATH_LEN + 1] = "@"; | |
64 | ||
65 | memset(aaa + 1, 'a', SUN_PATH_LEN - 1); | |
66 | char_array_0(aaa); | |
67 | ||
68 | test_socket_address_parse_one(aaa, -EINVAL, 0, NULL); | |
69 | ||
70 | aaa[SUN_PATH_LEN - 1] = '\0'; | |
71 | test_socket_address_parse_one(aaa, 0, AF_UNIX, NULL); | |
72 | } | |
73 | ||
74 | test_socket_address_parse_one("vsock:2:1234", 0, AF_VSOCK, NULL); | |
75 | test_socket_address_parse_one("vsock::1234", 0, AF_VSOCK, NULL); | |
76 | test_socket_address_parse_one("vsock:2:1234x", -EINVAL, 0, NULL); | |
77 | test_socket_address_parse_one("vsock:2x:1234", -EINVAL, 0, NULL); | |
78 | test_socket_address_parse_one("vsock:2", -EINVAL, 0, NULL); | |
79 | } | |
80 | ||
81 | static void test_socket_address_parse_netlink(void) { | |
82 | SocketAddress a; | |
83 | ||
84 | log_info("/* %s */", __func__); | |
85 | ||
86 | assert_se(socket_address_parse_netlink(&a, "junk") < 0); | |
87 | assert_se(socket_address_parse_netlink(&a, "") < 0); | |
88 | ||
89 | assert_se(socket_address_parse_netlink(&a, "route") >= 0); | |
90 | assert_se(a.sockaddr.nl.nl_family == AF_NETLINK); | |
91 | assert_se(a.sockaddr.nl.nl_groups == 0); | |
92 | assert_se(a.protocol == NETLINK_ROUTE); | |
93 | assert_se(socket_address_parse_netlink(&a, "route") >= 0); | |
94 | assert_se(socket_address_parse_netlink(&a, "route 10") >= 0); | |
95 | assert_se(a.sockaddr.nl.nl_family == AF_NETLINK); | |
96 | assert_se(a.sockaddr.nl.nl_groups == 10); | |
97 | assert_se(a.protocol == NETLINK_ROUTE); | |
98 | ||
99 | /* With spaces and tabs */ | |
100 | assert_se(socket_address_parse_netlink(&a, " kobject-uevent ") >= 0); | |
101 | assert_se(a.sockaddr.nl.nl_family == AF_NETLINK); | |
102 | assert_se(a.sockaddr.nl.nl_groups == 0); | |
103 | assert_se(a.protocol == NETLINK_KOBJECT_UEVENT); | |
104 | assert_se(socket_address_parse_netlink(&a, " \t kobject-uevent \t 10") >= 0); | |
105 | assert_se(a.sockaddr.nl.nl_family == AF_NETLINK); | |
106 | assert_se(a.sockaddr.nl.nl_groups == 10); | |
107 | assert_se(a.protocol == NETLINK_KOBJECT_UEVENT); | |
108 | assert_se(socket_address_parse_netlink(&a, "kobject-uevent\t10") >= 0); | |
109 | assert_se(a.sockaddr.nl.nl_family == AF_NETLINK); | |
110 | assert_se(a.sockaddr.nl.nl_groups == 10); | |
111 | assert_se(a.protocol == NETLINK_KOBJECT_UEVENT); | |
112 | ||
113 | /* trailing space is not supported */ | |
114 | assert_se(socket_address_parse_netlink(&a, "kobject-uevent\t10 ") < 0); | |
115 | ||
116 | /* Group must be unsigned */ | |
117 | assert_se(socket_address_parse_netlink(&a, "kobject-uevent -1") < 0); | |
118 | ||
119 | /* oss-fuzz #6884 */ | |
120 | assert_se(socket_address_parse_netlink(&a, "\xff") < 0); | |
121 | } | |
122 | ||
123 | static void test_socket_address_equal(void) { | |
124 | SocketAddress a, b; | |
125 | ||
126 | log_info("/* %s */", __func__); | |
127 | ||
128 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
129 | assert_se(socket_address_parse(&b, "192.168.1.1:888") >= 0); | |
130 | assert_se(!socket_address_equal(&a, &b)); | |
131 | ||
132 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
133 | assert_se(socket_address_parse(&b, "192.16.1.1:8888") >= 0); | |
134 | assert_se(!socket_address_equal(&a, &b)); | |
135 | ||
136 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
137 | assert_se(socket_address_parse(&b, "8888") >= 0); | |
138 | assert_se(!socket_address_equal(&a, &b)); | |
139 | ||
140 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
141 | assert_se(socket_address_parse(&b, "/foo/bar/") >= 0); | |
142 | assert_se(!socket_address_equal(&a, &b)); | |
143 | ||
144 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
145 | assert_se(socket_address_parse(&b, "192.168.1.1:8888") >= 0); | |
146 | assert_se(socket_address_equal(&a, &b)); | |
147 | ||
148 | assert_se(socket_address_parse(&a, "/foo/bar") >= 0); | |
149 | assert_se(socket_address_parse(&b, "/foo/bar") >= 0); | |
150 | assert_se(socket_address_equal(&a, &b)); | |
151 | ||
152 | assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); | |
153 | assert_se(socket_address_parse(&b, "[::1]:8888") >= 0); | |
154 | assert_se(socket_address_equal(&a, &b)); | |
155 | ||
156 | assert_se(socket_address_parse(&a, "@abstract") >= 0); | |
157 | assert_se(socket_address_parse(&b, "@abstract") >= 0); | |
158 | assert_se(socket_address_equal(&a, &b)); | |
159 | ||
160 | assert_se(socket_address_parse_netlink(&a, "firewall") >= 0); | |
161 | assert_se(socket_address_parse_netlink(&b, "firewall") >= 0); | |
162 | assert_se(socket_address_equal(&a, &b)); | |
163 | ||
164 | assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0); | |
165 | assert_se(socket_address_parse(&b, "vsock:2:1234") >= 0); | |
166 | assert_se(socket_address_equal(&a, &b)); | |
167 | assert_se(socket_address_parse(&b, "vsock:2:1235") >= 0); | |
168 | assert_se(!socket_address_equal(&a, &b)); | |
169 | assert_se(socket_address_parse(&b, "vsock:3:1234") >= 0); | |
170 | assert_se(!socket_address_equal(&a, &b)); | |
171 | } | |
172 | ||
173 | static void test_socket_address_get_path(void) { | |
174 | SocketAddress a; | |
175 | ||
176 | log_info("/* %s */", __func__); | |
177 | ||
178 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
179 | assert_se(!socket_address_get_path(&a)); | |
180 | ||
181 | assert_se(socket_address_parse(&a, "@abstract") >= 0); | |
182 | assert_se(!socket_address_get_path(&a)); | |
183 | ||
184 | assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); | |
185 | assert_se(!socket_address_get_path(&a)); | |
186 | ||
187 | assert_se(socket_address_parse(&a, "/foo/bar") >= 0); | |
188 | assert_se(streq(socket_address_get_path(&a), "/foo/bar")); | |
189 | ||
190 | assert_se(socket_address_parse(&a, "vsock:2:1234") >= 0); | |
191 | assert_se(!socket_address_get_path(&a)); | |
192 | } | |
193 | ||
194 | static void test_socket_address_is(void) { | |
195 | SocketAddress a; | |
196 | ||
197 | log_info("/* %s */", __func__); | |
198 | ||
199 | assert_se(socket_address_parse(&a, "192.168.1.1:8888") >= 0); | |
200 | assert_se(socket_address_is(&a, "192.168.1.1:8888", SOCK_STREAM)); | |
201 | assert_se(!socket_address_is(&a, "route", SOCK_STREAM)); | |
202 | assert_se(!socket_address_is(&a, "192.168.1.1:8888", SOCK_RAW)); | |
203 | } | |
204 | ||
205 | static void test_socket_address_is_netlink(void) { | |
206 | SocketAddress a; | |
207 | ||
208 | log_info("/* %s */", __func__); | |
209 | ||
210 | assert_se(socket_address_parse_netlink(&a, "route 10") >= 0); | |
211 | assert_se(socket_address_is_netlink(&a, "route 10")); | |
212 | assert_se(!socket_address_is_netlink(&a, "192.168.1.1:8888")); | |
213 | assert_se(!socket_address_is_netlink(&a, "route 1")); | |
214 | } | |
215 | ||
1f1f3210 SS |
216 | static void test_socket_addr_port_from_string_auto_one(const char *in, uint16_t port, int ret, int family, const char *expected) { |
217 | _cleanup_free_ char *out = NULL; | |
218 | SocketAddress a; | |
219 | int r; | |
220 | ||
221 | r = socket_addr_port_from_string_auto(in, port, &a); | |
222 | if (r >= 0) | |
223 | assert_se(sockaddr_pretty(&a.sockaddr.sa, a.size, false, true, &out) >= 0); | |
224 | ||
225 | log_info("\"%s\" → %s → \"%s\" (expect \"%s\")", in, | |
226 | r >= 0 ? "✓" : "✗", empty_to_dash(out), r >= 0 ? expected ?: in : "-"); | |
227 | assert_se(r == ret); | |
228 | if (r >= 0) { | |
229 | assert_se(a.sockaddr.sa.sa_family == family); | |
230 | assert_se(streq(out, expected ?: in)); | |
231 | } | |
232 | } | |
233 | ||
234 | static void test_socket_addr_port_from_string_auto(void) { | |
235 | log_info("/* %s */", __func__); | |
236 | ||
237 | test_socket_addr_port_from_string_auto_one("junk", 51, -EINVAL, 0, NULL); | |
238 | test_socket_addr_port_from_string_auto_one("192.168.1.1", 53, 0, AF_INET, "192.168.1.1:53"); | |
239 | test_socket_addr_port_from_string_auto_one(".168.1.1", 53, -EINVAL, 0, NULL); | |
240 | test_socket_addr_port_from_string_auto_one("989.168.1.1", 53, -EINVAL, 0, NULL); | |
241 | ||
242 | test_socket_addr_port_from_string_auto_one("[::1]", 53, -EINVAL, 0, NULL); | |
243 | test_socket_addr_port_from_string_auto_one("[::1]8888", 53, -EINVAL, 0, NULL); | |
244 | test_socket_addr_port_from_string_auto_one("2001:db8:3c4d:15::1a2f:1a2b", 53, 0, AF_INET6, "[2001:db8:3c4d:15::1a2f:1a2b]:53"); | |
245 | test_socket_addr_port_from_string_auto_one("[2001:db8:3c4d:15::1a2f:1a2b]:2001", 53, 0, AF_INET6, "[2001:db8:3c4d:15::1a2f:1a2b]:2001"); | |
246 | test_socket_addr_port_from_string_auto_one("[::1]:0", 53, -EINVAL, 0, NULL); | |
247 | test_socket_addr_port_from_string_auto_one("[::1]:65536", 53, -ERANGE, 0, NULL); | |
248 | test_socket_addr_port_from_string_auto_one("[a:b:1]:8888", 53, -EINVAL, 0, NULL); | |
249 | } | |
250 | ||
5c3fa98d ZJS |
251 | int main(int argc, char *argv[]) { |
252 | test_setup_logging(LOG_DEBUG); | |
253 | ||
254 | test_socket_address_parse(); | |
255 | test_socket_address_parse_netlink(); | |
256 | test_socket_address_equal(); | |
257 | test_socket_address_get_path(); | |
258 | test_socket_address_is(); | |
259 | test_socket_address_is_netlink(); | |
1f1f3210 | 260 | test_socket_addr_port_from_string_auto(); |
5c3fa98d ZJS |
261 | |
262 | return 0; | |
263 | } |