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