1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <arpa/inet.h>
4 #include <errno.h>
5 #include <net/if.h>
6 #include <string.h>
7
8 #include "alloc-util.h"
9 #include "errno-util.h"
10 #include "extract-word.h"
11 #include "log.h"
12 #include "memory-util.h"
13 #include "netlink-util.h"
14 #include "parse-util.h"
15 #include "socket-netlink.h"
16 #include "socket-util.h"
17 #include "string-util.h"
18
socket_address_parse(SocketAddress * a,const char * s)19 int socket_address_parse(SocketAddress *a, const char *s) {
20 _cleanup_free_ char *n = NULL;
21 char *e;
22 int r;
23
24 assert(a);
25 assert(s);
26
27 if (IN_SET(*s, '/', '@')) {
28 /* AF_UNIX socket */
29 struct sockaddr_un un;
30
31 r = sockaddr_un_set_path(&un, s);
32 if (r < 0)
33 return r;
34
35 *a = (SocketAddress) {
36 .sockaddr.un = un,
37 .size = r,
38 };
39
40 } else if (startswith(s, "vsock:")) {
41 /* AF_VSOCK socket in vsock:cid:port notation */
42 const char *cid_start = s + STRLEN("vsock:");
43 unsigned port, cid;
44
45 e = strchr(cid_start, ':');
46 if (!e)
47 return -EINVAL;
48
49 r = safe_atou(e+1, &port);
50 if (r < 0)
51 return r;
52
53 n = strndup(cid_start, e - cid_start);
54 if (!n)
55 return -ENOMEM;
56
57 if (isempty(n))
58 cid = VMADDR_CID_ANY;
59 else {
60 r = safe_atou(n, &cid);
61 if (r < 0)
62 return r;
63 }
64
65 *a = (SocketAddress) {
66 .sockaddr.vm = {
67 .svm_cid = cid,
68 .svm_family = AF_VSOCK,
69 .svm_port = port,
70 },
71 .size = sizeof(struct sockaddr_vm),
72 };
73
74 } else {
75 uint16_t port;
76
77 r = parse_ip_port(s, &port);
78 if (r == -ERANGE)
79 return r; /* Valid port syntax, but the numerical value is wrong for a port. */
80 if (r >= 0) {
81 /* Just a port */
82 if (socket_ipv6_is_supported())
83 *a = (SocketAddress) {
84 .sockaddr.in6 = {
85 .sin6_family = AF_INET6,
86 .sin6_port = htobe16(port),
87 .sin6_addr = in6addr_any,
88 },
89 .size = sizeof(struct sockaddr_in6),
90 };
91 else
92 *a = (SocketAddress) {
93 .sockaddr.in = {
94 .sin_family = AF_INET,
95 .sin_port = htobe16(port),
96 .sin_addr.s_addr = INADDR_ANY,
97 },
98 .size = sizeof(struct sockaddr_in),
99 };
100
101 } else {
102 union in_addr_union address;
103 int family, ifindex;
104
105 r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
106 if (r < 0)
107 return r;
108
109 if (port == 0) /* No port, no go. */
110 return -EINVAL;
111
112 if (family == AF_INET)
113 *a = (SocketAddress) {
114 .sockaddr.in = {
115 .sin_family = AF_INET,
116 .sin_addr = address.in,
117 .sin_port = htobe16(port),
118 },
119 .size = sizeof(struct sockaddr_in),
120 };
121 else if (family == AF_INET6)
122 *a = (SocketAddress) {
123 .sockaddr.in6 = {
124 .sin6_family = AF_INET6,
125 .sin6_addr = address.in6,
126 .sin6_port = htobe16(port),
127 .sin6_scope_id = ifindex,
128 },
129 .size = sizeof(struct sockaddr_in6),
130 };
131 else
132 assert_not_reached();
133 }
134 }
135
136 return 0;
137 }
138
socket_address_parse_and_warn(SocketAddress * a,const char * s)139 int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
140 SocketAddress b;
141 int r;
142
143 /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
144
145 r = socket_address_parse(&b, s);
146 if (r < 0)
147 return r;
148
149 if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
150 log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
151 return -EAFNOSUPPORT;
152 }
153
154 *a = b;
155 return 0;
156 }
157
socket_address_parse_netlink(SocketAddress * a,const char * s)158 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
159 _cleanup_free_ char *word = NULL;
160 unsigned group = 0;
161 int family, r;
162
163 assert(a);
164 assert(s);
165
166 r = extract_first_word(&s, &word, NULL, 0);
167 if (r < 0)
168 return r;
169 if (r == 0)
170 return -EINVAL;
171
172 family = netlink_family_from_string(word);
173 if (family < 0)
174 return -EINVAL;
175
176 if (!isempty(s)) {
177 r = safe_atou(s, &group);
178 if (r < 0)
179 return r;
180 }
181
182 *a = (SocketAddress) {
183 .type = SOCK_RAW,
184 .sockaddr.nl.nl_family = AF_NETLINK,
185 .sockaddr.nl.nl_groups = group,
186 .protocol = family,
187 .size = sizeof(struct sockaddr_nl),
188 };
189
190 return 0;
191 }
192
socket_address_is(const SocketAddress * a,const char * s,int type)193 bool socket_address_is(const SocketAddress *a, const char *s, int type) {
194 struct SocketAddress b;
195
196 assert(a);
197 assert(s);
198
199 if (socket_address_parse(&b, s) < 0)
200 return false;
201
202 b.type = type;
203
204 return socket_address_equal(a, &b);
205 }
206
socket_address_is_netlink(const SocketAddress * a,const char * s)207 bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
208 struct SocketAddress b;
209
210 assert(a);
211 assert(s);
212
213 if (socket_address_parse_netlink(&b, s) < 0)
214 return false;
215
216 return socket_address_equal(a, &b);
217 }
218
make_socket_fd(int log_level,const char * address,int type,int flags)219 int make_socket_fd(int log_level, const char* address, int type, int flags) {
220 SocketAddress a;
221 int fd, r;
222
223 r = socket_address_parse(&a, address);
224 if (r < 0)
225 return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
226
227 a.type = type;
228
229 fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
230 NULL, false, false, false, 0755, 0644, NULL);
231 if (fd < 0 || log_get_max_level() >= log_level) {
232 _cleanup_free_ char *p = NULL;
233
234 r = socket_address_print(&a, &p);
235 if (r < 0)
236 return log_error_errno(r, "socket_address_print(): %m");
237
238 if (fd < 0)
239 log_error_errno(fd, "Failed to listen on %s: %m", p);
240 else
241 log_full(log_level, "Listening on %s", p);
242 }
243
244 return fd;
245 }
246
in_addr_port_ifindex_name_from_string_auto(const char * s,int * ret_family,union in_addr_union * ret_address,uint16_t * ret_port,int * ret_ifindex,char ** ret_server_name)247 int in_addr_port_ifindex_name_from_string_auto(
248 const char *s,
249 int *ret_family,
250 union in_addr_union *ret_address,
251 uint16_t *ret_port,
252 int *ret_ifindex,
253 char **ret_server_name) {
254
255 _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
256 int family, ifindex = 0, r;
257 union in_addr_union a;
258 uint16_t port = 0;
259 const char *m;
260
261 assert(s);
262
263 /* This accepts the following:
264 * 192.168.0.1:53#example.com
265 * [2001:4860:4860::8888]:53%eth0#example.com
266 *
267 * If ret_port is NULL, then the port cannot be specified.
268 * If ret_ifindex is NULL, then the interface index cannot be specified.
269 * If ret_server_name is NULL, then server_name cannot be specified.
270 *
271 * ret_family is always AF_INET or AF_INET6.
272 */
273
274 m = strchr(s, '#');
275 if (m) {
276 if (!ret_server_name)
277 return -EINVAL;
278
279 if (isempty(m + 1))
280 return -EINVAL;
281
282 name = strdup(m + 1);
283 if (!name)
284 return -ENOMEM;
285
286 s = buf1 = strndup(s, m - s);
287 if (!buf1)
288 return -ENOMEM;
289 }
290
291 m = strchr(s, '%');
292 if (m) {
293 if (!ret_ifindex)
294 return -EINVAL;
295
296 if (isempty(m + 1))
297 return -EINVAL;
298
299 if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
300 return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
301 * and -ENODEV for valid but nonexistent interfaces. */
302
303 ifindex = rtnl_resolve_interface(NULL, m + 1);
304 if (ifindex < 0)
305 return ifindex;
306
307 s = buf2 = strndup(s, m - s);
308 if (!buf2)
309 return -ENOMEM;
310 }
311
312 m = strrchr(s, ':');
313 if (m) {
314 if (*s == '[') {
315 _cleanup_free_ char *ip_str = NULL;
316
317 if (!ret_port)
318 return -EINVAL;
319
320 if (*(m - 1) != ']')
321 return -EINVAL;
322
323 family = AF_INET6;
324
325 r = parse_ip_port(m + 1, &port);
326 if (r < 0)
327 return r;
328
329 ip_str = strndup(s + 1, m - s - 2);
330 if (!ip_str)
331 return -ENOMEM;
332
333 r = in_addr_from_string(family, ip_str, &a);
334 if (r < 0)
335 return r;
336 } else {
337 /* First try to parse the string as IPv6 address without port number */
338 r = in_addr_from_string(AF_INET6, s, &a);
339 if (r < 0) {
340 /* Then the input should be IPv4 address with port number */
341 _cleanup_free_ char *ip_str = NULL;
342
343 if (!ret_port)
344 return -EINVAL;
345
346 family = AF_INET;
347
348 ip_str = strndup(s, m - s);
349 if (!ip_str)
350 return -ENOMEM;
351
352 r = in_addr_from_string(family, ip_str, &a);
353 if (r < 0)
354 return r;
355
356 r = parse_ip_port(m + 1, &port);
357 if (r < 0)
358 return r;
359 } else
360 family = AF_INET6;
361 }
362 } else {
363 family = AF_INET;
364 r = in_addr_from_string(family, s, &a);
365 if (r < 0)
366 return r;
367 }
368
369 if (ret_family)
370 *ret_family = family;
371 if (ret_address)
372 *ret_address = a;
373 if (ret_port)
374 *ret_port = port;
375 if (ret_ifindex)
376 *ret_ifindex = ifindex;
377 if (ret_server_name)
378 *ret_server_name = TAKE_PTR(name);
379
380 return r;
381 }
382
in_addr_full_free(struct in_addr_full * a)383 struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
384 if (!a)
385 return NULL;
386
387 free(a->server_name);
388 free(a->cached_server_string);
389 return mfree(a);
390 }
391
in_addr_full_new(int family,const union in_addr_union * a,uint16_t port,int ifindex,const char * server_name,struct in_addr_full ** ret)392 int in_addr_full_new(
393 int family,
394 const union in_addr_union *a,
395 uint16_t port,
396 int ifindex,
397 const char *server_name,
398 struct in_addr_full **ret) {
399
400 _cleanup_free_ char *name = NULL;
401 struct in_addr_full *x;
402
403 assert(ret);
404
405 if (!isempty(server_name)) {
406 name = strdup(server_name);
407 if (!name)
408 return -ENOMEM;
409 }
410
411 x = new(struct in_addr_full, 1);
412 if (!x)
413 return -ENOMEM;
414
415 *x = (struct in_addr_full) {
416 .family = family,
417 .address = *a,
418 .port = port,
419 .ifindex = ifindex,
420 .server_name = TAKE_PTR(name),
421 };
422
423 *ret = x;
424 return 0;
425 }
426
in_addr_full_new_from_string(const char * s,struct in_addr_full ** ret)427 int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
428 _cleanup_free_ char *server_name = NULL;
429 int family, ifindex, r;
430 union in_addr_union a;
431 uint16_t port;
432
433 assert(s);
434
435 r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
436 if (r < 0)
437 return r;
438
439 return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
440 }
441
in_addr_full_to_string(struct in_addr_full * a)442 const char *in_addr_full_to_string(struct in_addr_full *a) {
443 assert(a);
444
445 if (!a->cached_server_string)
446 (void) in_addr_port_ifindex_name_to_string(
447 a->family,
448 &a->address,
449 a->port,
450 a->ifindex,
451 a->server_name,
452 &a->cached_server_string);
453
454 return a->cached_server_string;
455 }
456