Coverage Report

Created: 2026-09-14 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/libsystemd-network/network-internal.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <stdio.h>
4
5
#include "sd-dhcp-lease.h"
6
7
#include "alloc-util.h"
8
#include "dns-resolver-internal.h"
9
#include "extract-word.h"
10
#include "in-addr-util.h"
11
#include "network-internal.h"
12
#include "string-util.h"
13
#include "strv.h"
14
15
size_t serialize_in_addrs(FILE *f,
16
                          const struct in_addr *addresses,
17
                          size_t size,
18
                          bool *with_leading_space,
19
0
                          bool (*predicate)(const struct in_addr *addr)) {
20
0
        assert(f);
21
0
        assert(addresses);
22
23
0
        size_t count = 0;
24
0
        bool _space = false;
25
0
        if (!with_leading_space)
26
0
                with_leading_space = &_space;
27
28
0
        for (size_t i = 0; i < size; i++) {
29
0
                if (predicate && !predicate(&addresses[i]))
30
0
                        continue;
31
32
0
                if (*with_leading_space)
33
0
                        fputc(' ', f);
34
0
                fputs(IN4_ADDR_TO_STRING(&addresses[i]), f);
35
0
                count++;
36
0
                *with_leading_space = true;
37
0
        }
38
39
0
        return count;
40
0
}
41
42
0
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
43
0
        _cleanup_free_ struct in_addr *addresses = NULL;
44
0
        int size = 0;
45
46
0
        assert(ret);
47
0
        assert(string);
48
49
0
        for (;;) {
50
0
                _cleanup_free_ char *word = NULL;
51
0
                union in_addr_union a;
52
0
                int r;
53
54
0
                r = extract_first_word(&string, &word, NULL, 0);
55
0
                if (r < 0)
56
0
                        return r;
57
0
                if (r == 0)
58
0
                        break;
59
60
0
                if (in_addr_from_string(AF_INET, word, &a) < 0)
61
0
                        continue;
62
63
0
                if (!GREEDY_REALLOC(addresses, size + 1))
64
0
                        return -ENOMEM;
65
66
0
                addresses[size++] = a.in;
67
0
        }
68
69
0
        *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
70
71
0
        return size;
72
0
}
73
74
0
void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) {
75
0
        assert(f);
76
0
        assert(addresses);
77
0
        assert(size);
78
79
0
        bool _space = false;
80
0
        if (!with_leading_space)
81
0
                with_leading_space = &_space;
82
83
0
        for (size_t i = 0; i < size; i++) {
84
0
                if (*with_leading_space)
85
0
                        fputc(' ', f);
86
0
                fputs(IN6_ADDR_TO_STRING(&addresses[i]), f);
87
0
                *with_leading_space = true;
88
0
        }
89
0
}
90
91
0
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
92
0
        _cleanup_free_ struct in6_addr *addresses = NULL;
93
0
        int size = 0;
94
95
0
        assert(ret);
96
0
        assert(string);
97
98
0
        for (;;) {
99
0
                _cleanup_free_ char *word = NULL;
100
0
                union in_addr_union a;
101
0
                int r;
102
103
0
                r = extract_first_word(&string, &word, NULL, 0);
104
0
                if (r < 0)
105
0
                        return r;
106
0
                if (r == 0)
107
0
                        break;
108
109
0
                if (in_addr_from_string(AF_INET6, word, &a) < 0)
110
0
                        continue;
111
112
0
                if (!GREEDY_REALLOC(addresses, size + 1))
113
0
                        return -ENOMEM;
114
115
0
                addresses[size++] = a.in6;
116
0
        }
117
118
0
        *ret = TAKE_PTR(addresses);
119
120
0
        return size;
121
0
}
122
123
0
int serialize_dnr(FILE *f, const sd_dns_resolver *dnr, size_t n_dnr, bool *with_leading_space) {
124
0
        int r;
125
126
0
        bool _space = false;
127
0
        if (!with_leading_space)
128
0
                with_leading_space = &_space;
129
130
0
        int n = 0;
131
0
        _cleanup_strv_free_ char **names = NULL;
132
0
        r = dns_resolvers_to_dot_strv(dnr, n_dnr, &names);
133
0
        if (r < 0)
134
0
                return r;
135
0
        if (r > 0)
136
0
                fputstrv(f, names, NULL, with_leading_space);
137
0
        n += r;
138
0
        return n;
139
0
}
140
141
static int coalesce_dnr(sd_dns_resolver *dnr, size_t n_dnr, int family, const char *auth_name,
142
0
                union in_addr_union *addr) {
143
0
        assert(dnr || n_dnr == 0);
144
0
        assert(auth_name);
145
0
        assert(addr);
146
147
        /* Look through list of DNR for matching resolvers to add our addr to. Since DoT is assumed, no need
148
         * to compare transports/dohpath/etc. */
149
0
        FOREACH_ARRAY(res, dnr, n_dnr) {
150
0
                if (family == res->family && streq(auth_name, res->auth_name)) {
151
0
                        if (!GREEDY_REALLOC(res->addrs, res->n_addrs + 1))
152
0
                                return -ENOMEM;
153
0
                        res->addrs[res->n_addrs++] = *addr;
154
0
                        return true;
155
0
                }
156
0
        }
157
158
0
        return false;
159
0
}
160
161
/* Deserialized resolvers are assumed to offer DoT service. */
162
0
int deserialize_dnr(sd_dns_resolver **ret, const char *string) {
163
0
        int r;
164
165
0
        assert(ret);
166
0
        assert(string);
167
168
0
        sd_dns_resolver *dnr = NULL;
169
0
        size_t n = 0;
170
0
        CLEANUP_ARRAY(dnr, n, dns_resolver_free_array);
171
0
        int priority = 0;
172
173
0
        for (;;) {
174
0
                _cleanup_free_ char *word = NULL;
175
176
0
                r = extract_first_word(&string, &word, NULL, 0);
177
0
                if (r < 0)
178
0
                        return r;
179
0
                if (r == 0)
180
0
                        break;
181
182
0
                uint16_t port;
183
0
                int family;
184
0
                _cleanup_free_ union in_addr_union *addr = new(union in_addr_union, 1);
185
0
                _cleanup_free_ char *auth_name = NULL;
186
187
0
                r = in_addr_port_ifindex_name_from_string_auto(word, &family, addr, &port, NULL, &auth_name);
188
0
                if (r < 0)
189
0
                        return r;
190
191
0
                r = coalesce_dnr(dnr, n, family, auth_name, addr);
192
0
                if (r < 0)
193
0
                        return r;
194
0
                if (r > 0)
195
0
                        continue;
196
197
0
                if (!GREEDY_REALLOC(dnr, n+1))
198
0
                        return -ENOMEM;
199
200
0
                priority = n+1;
201
0
                dnr[n++] = (sd_dns_resolver) {
202
0
                        .priority = priority, /* not serialized, but this will preserve the order */
203
0
                        .auth_name = TAKE_PTR(auth_name),
204
0
                        .family = family,
205
0
                        .addrs = TAKE_PTR(addr),
206
0
                        .n_addrs = 1,
207
0
                        .transports = SD_DNS_ALPN_DOT,
208
0
                        .port = port,
209
0
                };
210
0
        }
211
212
0
        *ret = TAKE_PTR(dnr);
213
0
        return n;
214
0
}