• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15232239991

24 May 2025 08:01PM UTC coverage: 72.053% (-0.02%) from 72.07%
15232239991

push

github

web-flow
docs: add man pages for sd_device_enumerator_[new,ref,unref,unrefp] (#37586)

For #20929.

299160 of 415197 relevant lines covered (72.05%)

703671.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.72
/src/shared/socket-netlink.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/net_namespace.h>
4
#include <linux/unix_diag.h>
5
#include <string.h>
6
#include <sys/stat.h>
7

8
#include "sd-netlink.h"
9

10
#include "alloc-util.h"
11
#include "extract-word.h"
12
#include "fd-util.h"
13
#include "log.h"
14
#include "namespace-util.h"
15
#include "netlink-sock-diag.h"
16
#include "netlink-util.h"
17
#include "parse-util.h"
18
#include "socket-netlink.h"
19
#include "socket-util.h"
20
#include "string-util.h"
21

22
int socket_address_parse(SocketAddress *a, const char *s) {
6,451✔
23
        uint16_t port;
6,451✔
24
        int r;
6,451✔
25

26
        assert(a);
6,451✔
27
        assert(s);
6,451✔
28

29
        r = socket_address_parse_unix(a, s);
6,451✔
30
        if (r == -EPROTO)
6,451✔
31
                r = socket_address_parse_vsock(a, s);
121✔
32
        if (r != -EPROTO)
121✔
33
                return r;
6,385✔
34

35
        r = parse_ip_port(s, &port);
66✔
36
        if (r == -ERANGE)
66✔
37
                return r; /* Valid port syntax, but the numerical value is wrong for a port. */
38
        if (r >= 0) {
65✔
39
                /* Just a port */
40
                if (socket_ipv6_is_supported())
6✔
41
                        *a = (SocketAddress) {
6✔
42
                                .sockaddr.in6 = {
43
                                        .sin6_family = AF_INET6,
44
                                        .sin6_port = htobe16(port),
6✔
45
                                        .sin6_addr = in6addr_any,
46
                                },
47
                                .size = sizeof(struct sockaddr_in6),
48
                        };
49
                else
50
                        *a = (SocketAddress) {
×
51
                                .sockaddr.in = {
52
                                        .sin_family = AF_INET,
53
                                        .sin_port = htobe16(port),
×
54
                                        .sin_addr.s_addr = INADDR_ANY,
55
                                },
56
                                .size = sizeof(struct sockaddr_in),
57
                        };
58

59
        } else {
60
                union in_addr_union address;
59✔
61
                int family, ifindex;
59✔
62

63
                r = in_addr_port_ifindex_name_from_string_auto(s, &family, &address, &port, &ifindex, NULL);
59✔
64
                if (r < 0)
59✔
65
                        return r;
35✔
66

67
                if (port == 0) /* No port, no go. */
26✔
68
                        return -EINVAL;
69

70
                if (family == AF_INET)
24✔
71
                        *a = (SocketAddress) {
17✔
72
                                .sockaddr.in = {
73
                                        .sin_family = AF_INET,
74
                                        .sin_addr = address.in,
75
                                        .sin_port = htobe16(port),
17✔
76
                                },
77
                                .size = sizeof(struct sockaddr_in),
78
                        };
79
                else if (family == AF_INET6)
7✔
80
                        *a = (SocketAddress) {
7✔
81
                                .sockaddr.in6 = {
82
                                        .sin6_family = AF_INET6,
83
                                        .sin6_addr = address.in6,
84
                                        .sin6_port = htobe16(port),
7✔
85
                                        .sin6_scope_id = ifindex,
86
                                },
87
                                .size = sizeof(struct sockaddr_in6),
88
                        };
89
                else
90
                        assert_not_reached();
×
91
        }
92

93
        return 0;
94
}
95

96
int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
5,146✔
97
        SocketAddress b;
5,146✔
98
        int r;
5,146✔
99

100
        /* Similar to socket_address_parse() but warns for IPv6 sockets when we don't support them. */
101

102
        r = socket_address_parse(&b, s);
5,146✔
103
        if (r < 0)
5,146✔
104
                return r;
5,146✔
105

106
        if (!socket_ipv6_is_supported() && b.sockaddr.sa.sa_family == AF_INET6) {
5,146✔
107
                log_warning("Binding to IPv6 address not available since kernel does not support IPv6.");
×
108
                return -EAFNOSUPPORT;
×
109
        }
110

111
        *a = b;
5,146✔
112
        return 0;
5,146✔
113
}
114

115
int socket_address_parse_netlink(SocketAddress *a, const char *s) {
429✔
116
        _cleanup_free_ char *word = NULL;
429✔
117
        unsigned group = 0;
429✔
118
        int family, r;
429✔
119

120
        assert(a);
429✔
121
        assert(s);
429✔
122

123
        r = extract_first_word(&s, &word, NULL, 0);
429✔
124
        if (r < 0)
429✔
125
                return r;
126
        if (r == 0)
429✔
127
                return -EINVAL;
128

129
        family = netlink_family_from_string(word);
428✔
130
        if (family < 0)
428✔
131
                return -EINVAL;
132

133
        if (!isempty(s)) {
425✔
134
                r = safe_atou(s, &group);
420✔
135
                if (r < 0)
420✔
136
                        return r;
137
        }
138

139
        *a = (SocketAddress) {
423✔
140
                .type = SOCK_RAW,
141
                .sockaddr.nl.nl_family = AF_NETLINK,
142
                .sockaddr.nl.nl_groups = group,
143
                .protocol = family,
144
                .size = sizeof(struct sockaddr_nl),
145
        };
146

147
        return 0;
423✔
148
}
149

150
bool socket_address_is(const SocketAddress *a, const char *s, int type) {
1,194✔
151
        struct SocketAddress b;
1,194✔
152

153
        assert(a);
1,194✔
154
        assert(s);
1,194✔
155

156
        if (socket_address_parse(&b, s) < 0)
1,194✔
157
                return false;
1,194✔
158

159
        b.type = type;
1,192✔
160

161
        return socket_address_equal(a, &b);
1,192✔
162
}
163

164
bool socket_address_is_netlink(const SocketAddress *a, const char *s) {
90✔
165
        struct SocketAddress b;
90✔
166

167
        assert(a);
90✔
168
        assert(s);
90✔
169

170
        if (socket_address_parse_netlink(&b, s) < 0)
90✔
171
                return false;
90✔
172

173
        return socket_address_equal(a, &b);
89✔
174
}
175

176
int make_socket_fd(int log_level, const char* address, int type, int flags) {
2✔
177
        SocketAddress a;
2✔
178
        int fd, r;
2✔
179

180
        r = socket_address_parse(&a, address);
2✔
181
        if (r < 0)
2✔
182
                return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
2✔
183

184
        a.type = type;
2✔
185

186
        fd = socket_address_listen(&a, type | flags, SOMAXCONN_DELUXE, SOCKET_ADDRESS_DEFAULT,
2✔
187
                                   NULL, false, false, false, 0755, 0644, NULL);
188
        if (fd < 0 || log_get_max_level() >= log_level) {
2✔
189
                _cleanup_free_ char *p = NULL;
1✔
190

191
                r = socket_address_print(&a, &p);
1✔
192
                if (r < 0)
1✔
193
                        return log_error_errno(r, "socket_address_print(): %m");
×
194

195
                if (fd < 0)
1✔
196
                        log_error_errno(fd, "Failed to listen on %s: %m", p);
1✔
197
                else
198
                        log_full(log_level, "Listening on %s", p);
1✔
199
        }
200

201
        return fd;
202
}
203

204
int in_addr_port_ifindex_name_from_string_auto(
4,105✔
205
                const char *s,
206
                int *ret_family,
207
                union in_addr_union *ret_address,
208
                uint16_t *ret_port,
209
                int *ret_ifindex,
210
                char **ret_server_name) {
211

212
        _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *name = NULL;
4,105✔
213
        int family, ifindex = 0, r;
4,105✔
214
        union in_addr_union a;
4,105✔
215
        uint16_t port = 0;
4,105✔
216
        const char *m;
4,105✔
217

218
        assert(s);
4,105✔
219

220
        /* This accepts the following:
221
         * 192.168.0.1:53#example.com
222
         * [2001:4860:4860::8888]:53%eth0#example.com
223
         *
224
         * If ret_port is NULL, then the port cannot be specified.
225
         * If ret_ifindex is NULL, then the interface index cannot be specified.
226
         * If ret_server_name is NULL, then server_name cannot be specified.
227
         *
228
         * ret_family is always AF_INET or AF_INET6.
229
         */
230

231
        m = strchr(s, '#');
4,105✔
232
        if (m) {
4,105✔
233
                if (!ret_server_name)
1,159✔
234
                        return -EINVAL;
235

236
                if (isempty(m + 1))
1,152✔
237
                        return -EINVAL;
238

239
                name = strdup(m + 1);
1,152✔
240
                if (!name)
1,152✔
241
                        return -ENOMEM;
242

243
                s = buf1 = strndup(s, m - s);
1,152✔
244
                if (!buf1)
1,152✔
245
                        return -ENOMEM;
246
        }
247

248
        m = strchr(s, '%');
4,098✔
249
        if (m) {
4,098✔
250
                if (!ret_ifindex)
50✔
251
                        return -EINVAL;
252

253
                if (isempty(m + 1))
4,146✔
254
                        return -EINVAL;
255

256
                if (!ifname_valid_full(m + 1, IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC))
41✔
257
                        return -EINVAL; /* We want to return -EINVAL for syntactically invalid names,
258
                                         * and -ENODEV for valid but nonexistent interfaces. */
259

260
                ifindex = rtnl_resolve_interface(NULL, m + 1);
36✔
261
                if (ifindex < 0)
36✔
262
                        return ifindex;
263

264
                s = buf2 = strndup(s, m - s);
34✔
265
                if (!buf2)
34✔
266
                        return -ENOMEM;
267
        }
268

269
        m = strrchr(s, ':');
4,082✔
270
        if (m) {
4,082✔
271
                if (*s == '[') {
918✔
272
                        _cleanup_free_ char *ip_str = NULL;
48✔
273

274
                        if (!ret_port)
48✔
275
                                return -EINVAL;
276

277
                        if (*(m - 1) != ']')
40✔
278
                                return -EINVAL;
279

280
                        family = AF_INET6;
36✔
281

282
                        r = parse_ip_port(m + 1, &port);
36✔
283
                        if (r < 0)
36✔
284
                                return r;
285

286
                        ip_str = strndup(s + 1, m - s - 2);
31✔
287
                        if (!ip_str)
31✔
288
                                return -ENOMEM;
289

290
                        r = in_addr_from_string(family, ip_str, &a);
31✔
291
                        if (r < 0)
31✔
292
                                return r;
293
                } else {
294
                        /* First try to parse the string as IPv6 address without port number */
295
                        r = in_addr_from_string(AF_INET6, s, &a);
870✔
296
                        if (r < 0) {
870✔
297
                                /* Then the input should be IPv4 address with port number */
298
                                _cleanup_free_ char *ip_str = NULL;
40✔
299

300
                                if (!ret_port)
40✔
301
                                        return -EINVAL;
302

303
                                family = AF_INET;
37✔
304

305
                                ip_str = strndup(s, m - s);
37✔
306
                                if (!ip_str)
37✔
307
                                        return -ENOMEM;
308

309
                                r = in_addr_from_string(family, ip_str, &a);
37✔
310
                                if (r < 0)
37✔
311
                                        return r;
312

313
                                r = parse_ip_port(m + 1, &port);
35✔
314
                                if (r < 0)
35✔
315
                                        return r;
316
                        } else
317
                                family = AF_INET6;
318
                }
319
        } else {
320
                family = AF_INET;
3,164✔
321
                r = in_addr_from_string(family, s, &a);
3,164✔
322
                if (r < 0)
3,164✔
323
                        return r;
324
        }
325

326
        if (ret_family)
1,810✔
327
                *ret_family = family;
1,810✔
328
        if (ret_address)
1,810✔
329
                *ret_address = a;
1,810✔
330
        if (ret_port)
1,810✔
331
                *ret_port = port;
1,557✔
332
        if (ret_ifindex)
1,810✔
333
                *ret_ifindex = ifindex;
1,584✔
334
        if (ret_server_name)
1,810✔
335
                *ret_server_name = TAKE_PTR(name);
1,548✔
336

337
        return r;
338
}
339

340
struct in_addr_full *in_addr_full_free(struct in_addr_full *a) {
178✔
341
        if (!a)
178✔
342
                return NULL;
343

344
        free(a->server_name);
178✔
345
        free(a->cached_server_string);
178✔
346
        return mfree(a);
178✔
347
}
348

349
void in_addr_full_array_free(struct in_addr_full *addrs[], size_t n) {
51✔
350
        assert(addrs || n == 0);
51✔
351

352
        FOREACH_ARRAY(a, addrs, n)
188✔
353
                in_addr_full_freep(a);
137✔
354

355
        free(addrs);
51✔
356
}
51✔
357

358
int in_addr_full_new(
41✔
359
                int family,
360
                const union in_addr_union *a,
361
                uint16_t port,
362
                int ifindex,
363
                const char *server_name,
364
                struct in_addr_full **ret) {
365

366
        _cleanup_free_ char *name = NULL;
82✔
367
        struct in_addr_full *x;
41✔
368

369
        assert(ret);
41✔
370

371
        if (!isempty(server_name)) {
41✔
372
                name = strdup(server_name);
4✔
373
                if (!name)
4✔
374
                        return -ENOMEM;
375
        }
376

377
        x = new(struct in_addr_full, 1);
41✔
378
        if (!x)
41✔
379
                return -ENOMEM;
380

381
        *x = (struct in_addr_full) {
41✔
382
                .family = family,
383
                .address = *a,
41✔
384
                .port = port,
385
                .ifindex = ifindex,
386
                .server_name = TAKE_PTR(name),
41✔
387
        };
388

389
        *ret = x;
41✔
390
        return 0;
41✔
391
}
392

393
int in_addr_full_new_from_string(const char *s, struct in_addr_full **ret) {
9✔
394
        _cleanup_free_ char *server_name = NULL;
9✔
395
        int family, ifindex, r;
9✔
396
        union in_addr_union a;
9✔
397
        uint16_t port;
9✔
398

399
        assert(s);
9✔
400

401
        r = in_addr_port_ifindex_name_from_string_auto(s, &family, &a, &port, &ifindex, &server_name);
9✔
402
        if (r < 0)
9✔
403
                return r;
404

405
        return in_addr_full_new(family, &a, port, ifindex, server_name, ret);
9✔
406
}
407

408
const char* in_addr_full_to_string(struct in_addr_full *a) {
484✔
409
        assert(a);
484✔
410

411
        if (!a->cached_server_string)
484✔
412
                (void) in_addr_port_ifindex_name_to_string(
178✔
413
                                a->family,
414
                                &a->address,
178✔
415
                                a->port,
178✔
416
                                a->ifindex,
417
                                a->server_name,
178✔
418
                                &a->cached_server_string);
419

420
        return a->cached_server_string;
484✔
421
}
422

423
int netns_get_nsid(int netnsfd, uint32_t *ret) {
3,479✔
424
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
6,958✔
425
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
3,479✔
426
        _cleanup_close_ int _netns_fd = -EBADF;
3,479✔
427
        int r;
3,479✔
428

429
        if (netnsfd < 0) {
3,479✔
430
                _netns_fd = namespace_open_by_type(NAMESPACE_NET);
3,479✔
431
                if (_netns_fd < 0)
3,479✔
432
                        return _netns_fd;
433

434
                netnsfd = _netns_fd;
435
        }
436

437
        r = sd_netlink_open(&rtnl);
3,479✔
438
        if (r < 0)
3,479✔
439
                return r;
440

441
        r = sd_rtnl_message_new_nsid(rtnl, &req, RTM_GETNSID);
3,479✔
442
        if (r < 0)
3,479✔
443
                return r;
444

445
        r = sd_netlink_message_append_s32(req, NETNSA_FD, netnsfd);
3,479✔
446
        if (r < 0)
3,479✔
447
                return r;
448

449
        r = sd_netlink_call(rtnl, req, 0, &reply);
3,479✔
450
        if (r < 0)
3,479✔
451
                return r;
452

453
        for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
3,479✔
454
                uint16_t type;
3,479✔
455

456
                r = sd_netlink_message_get_errno(m);
3,479✔
457
                if (r < 0)
3,479✔
458
                        return r;
3,479✔
459

460
                r = sd_netlink_message_get_type(m, &type);
3,479✔
461
                if (r < 0)
3,479✔
462
                        return r;
463
                if (type != RTM_NEWNSID)
3,479✔
464
                        continue;
×
465

466
                uint32_t u;
3,479✔
467
                r = sd_netlink_message_read_u32(m, NETNSA_NSID, &u);
3,479✔
468
                if (r < 0)
3,479✔
469
                        return r;
470

471
                if (u == (uint32_t) NETNSA_NSID_NOT_ASSIGNED) /* no NSID assigned yet */
3,479✔
472
                        return -ENODATA;
473

474
                if (ret)
×
475
                        *ret = u;
×
476

477
                return 0;
478
        }
479

480
        return -ENXIO;
481
}
482

483
int af_unix_get_qlen(int fd, uint32_t *ret) {
126✔
484
        int r;
126✔
485

486
        assert(fd >= 0);
126✔
487
        assert(ret);
126✔
488

489
        /* Returns the current queue length for an AF_UNIX listening socket */
490

491
        struct stat st;
126✔
492
        if (fstat(fd, &st) < 0)
126✔
493
                return -errno;
×
494
        if (!S_ISSOCK(st.st_mode))
126✔
495
                return -ENOTSOCK;
496

497
        _cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL;
126✔
498
        r = sd_sock_diag_socket_open(&nl);
125✔
499
        if (r < 0)
125✔
500
                return r;
501

502
        uint64_t cookie;
125✔
503
        r = socket_get_cookie(fd, &cookie);
125✔
504
        if (r < 0)
125✔
505
                return r;
506

507
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
125✔
508
        r = sd_sock_diag_message_new_unix(nl, &message, st.st_ino, cookie, UDIAG_SHOW_RQLEN);
125✔
509
        if (r < 0)
125✔
510
                return r;
511

512
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
125✔
513
        r = sd_netlink_call(nl, message, /* usec= */ 0, &reply);
125✔
514
        if (r < 0)
125✔
515
                return r;
516

517
        for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
125✔
518
                r = sd_netlink_message_get_errno(m);
125✔
519
                if (r < 0)
125✔
520
                        return r;
125✔
521

522
                _cleanup_free_ void *data = NULL;
125✔
523
                size_t size = 0;
125✔
524

525
                r = sd_netlink_message_read_data(m, UNIX_DIAG_RQLEN, &size, &data);
125✔
526
                if (r == -ENODATA)
125✔
527
                        continue;
×
528
                if (r < 0)
125✔
529
                        return r;
530

531
                assert(size == sizeof(struct unix_diag_rqlen));
125✔
532
                const struct unix_diag_rqlen *udrql = ASSERT_PTR(data);
125✔
533

534
                *ret = udrql->udiag_rqueue;
125✔
535
                return 0;
125✔
536
        }
537

538
        return -ENODATA;
539
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc