Bug Summary

File:build-scan/../src/resolve/resolved-dns-stream.c
Warning:line 552, column 24
Potential leak of memory pointed to by 's'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name resolved-dns-stream.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-resolved.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I /usr/include/p11-kit-1 -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/resolve/resolved-dns-stream.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <netinet/tcp.h>
4
5#include "alloc-util.h"
6#include "fd-util.h"
7#include "io-util.h"
8#include "missing.h"
9#include "resolved-dns-stream.h"
10
11#define DNS_STREAM_TIMEOUT_USEC(10 * ((usec_t) 1000000ULL)) (10 * USEC_PER_SEC((usec_t) 1000000ULL))
12#define DNS_STREAMS_MAX128 128
13
14#define WRITE_TLS_DATA1 1
15
16static void dns_stream_stop(DnsStream *s) {
17 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 17, __PRETTY_FUNCTION__); } while (0)
;
18
19 s->io_event_source = sd_event_source_unref(s->io_event_source);
20 s->timeout_event_source = sd_event_source_unref(s->timeout_event_source);
21 s->fd = safe_close(s->fd);
22}
23
24static int dns_stream_update_io(DnsStream *s) {
25 int f = 0;
26
27 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 27, __PRETTY_FUNCTION__); } while (0)
;
28
29 if (s->write_packet && s->n_written < sizeof(s->write_size) + s->write_packet->size)
30 f |= EPOLLOUTEPOLLOUT;
31 else if (!ordered_set_isempty(s->write_queue)) {
32 dns_packet_unref(s->write_packet);
33 s->write_packet = ordered_set_steal_first(s->write_queue);
34 s->write_size = htobe16(s->write_packet->size);
35 s->n_written = 0;
36 f |= EPOLLOUTEPOLLOUT;
37 }
38 if (!s->read_packet || s->n_read < sizeof(s->read_size) + s->read_packet->size)
39 f |= EPOLLINEPOLLIN;
40
41 return sd_event_source_set_io_events(s->io_event_source, f);
42}
43
44static int dns_stream_complete(DnsStream *s, int error) {
45 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 45, __PRETTY_FUNCTION__); } while (0)
;
46
47#if ENABLE_DNS_OVER_TLS1
48 if (s->tls_session && IN_SET(error, ETIMEDOUT, 0)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){110, 0})/sizeof(int)]; switch(error) { case
110: case 0: _found = 1; break; default: break; } _found; })
) {
49 int r;
50
51 r = gnutls_bye(s->tls_session, GNUTLS_SHUT_RDWR);
52 if (r == GNUTLS_E_AGAIN-28 && !s->tls_bye) {
53 dns_stream_ref(s); /* keep reference for closing TLS session */
54 s->tls_bye = true1;
55 } else
56 dns_stream_stop(s);
57 } else
58#endif
59 dns_stream_stop(s);
60
61 if (s->complete)
62 s->complete(s, error);
63 else /* the default action if no completion function is set is to close the stream */
64 dns_stream_unref(s);
65
66 return 0;
67}
68
69static int dns_stream_identify(DnsStream *s) {
70 union {
71 struct cmsghdr header; /* For alignment */
72 uint8_t buffer[CMSG_SPACE(MAXSIZE(struct in_pktinfo, struct in6_pktinfo))(((((sizeof(union __attribute__ ((packed)) { typeof(struct in_pktinfo
) a; typeof(struct in6_pktinfo) b; }))) + sizeof (size_t) - 1
) & (size_t) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr
)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1
)))
73 + CMSG_SPACE(int)((((int) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t
) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) &
(size_t) ~(sizeof (size_t) - 1)))
+ /* for the TTL */
74 + EXTRA_CMSG_SPACE1024 /* kernel appears to require extra space */];
75 } control;
76 struct msghdr mh = {};
77 struct cmsghdr *cmsg;
78 socklen_t sl;
79 int r;
80
81 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 81, __PRETTY_FUNCTION__); } while (0)
;
82
83 if (s->identified)
84 return 0;
85
86 /* Query the local side */
87 s->local_salen = sizeof(s->local);
88 r = getsockname(s->fd, &s->local.sa, &s->local_salen);
89 if (r < 0)
90 return -errno(*__errno_location ());
91 if (s->local.sa.sa_family == AF_INET610 && s->ifindex <= 0)
92 s->ifindex = s->local.in6.sin6_scope_id;
93
94 /* Query the remote side */
95 s->peer_salen = sizeof(s->peer);
96 r = getpeername(s->fd, &s->peer.sa, &s->peer_salen);
97 if (r < 0)
98 return -errno(*__errno_location ());
99 if (s->peer.sa.sa_family == AF_INET610 && s->ifindex <= 0)
100 s->ifindex = s->peer.in6.sin6_scope_id;
101
102 /* Check consistency */
103 assert(s->peer.sa.sa_family == s->local.sa.sa_family)do { if ((__builtin_expect(!!(!(s->peer.sa.sa_family == s->
local.sa.sa_family)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("s->peer.sa.sa_family == s->local.sa.sa_family"), "../src/resolve/resolved-dns-stream.c"
, 103, __PRETTY_FUNCTION__); } while (0)
;
104 assert(IN_SET(s->peer.sa.sa_family, AF_INET, AF_INET6))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__
((unused)) char _static_assert__macros_need_to_be_extended[20
- sizeof((int[]){2, 10})/sizeof(int)]; switch(s->peer.sa.
sa_family) { case 2: case 10: _found = 1; break; default: break
; } _found; }))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("IN_SET(s->peer.sa.sa_family, AF_INET, AF_INET6)"), "../src/resolve/resolved-dns-stream.c"
, 104, __PRETTY_FUNCTION__); } while (0)
;
105
106 /* Query connection meta information */
107 sl = sizeof(control);
108 if (s->peer.sa.sa_family == AF_INET2) {
109 r = getsockopt(s->fd, IPPROTO_IPIPPROTO_IP, IP_PKTOPTIONS9, &control, &sl);
110 if (r < 0)
111 return -errno(*__errno_location ());
112 } else if (s->peer.sa.sa_family == AF_INET610) {
113
114 r = getsockopt(s->fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_2292PKTOPTIONS6, &control, &sl);
115 if (r < 0)
116 return -errno(*__errno_location ());
117 } else
118 return -EAFNOSUPPORT97;
119
120 mh.msg_control = &control;
121 mh.msg_controllen = sl;
122
123 CMSG_FOREACH(cmsg, &mh)for ((cmsg) = ((size_t) (&mh)->msg_controllen >= sizeof
(struct cmsghdr) ? (struct cmsghdr *) (&mh)->msg_control
: (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((&
mh), (cmsg)))
{
124
125 if (cmsg->cmsg_level == IPPROTO_IPV6IPPROTO_IPV6) {
126 assert(s->peer.sa.sa_family == AF_INET6)do { if ((__builtin_expect(!!(!(s->peer.sa.sa_family == 10
)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("s->peer.sa.sa_family == AF_INET6"
), "../src/resolve/resolved-dns-stream.c", 126, __PRETTY_FUNCTION__
); } while (0)
;
127
128 switch (cmsg->cmsg_type) {
129
130 case IPV6_PKTINFO50: {
131 struct in6_pktinfo *i = (struct in6_pktinfo*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data);
132
133 if (s->ifindex <= 0)
134 s->ifindex = i->ipi6_ifindex;
135 break;
136 }
137
138 case IPV6_HOPLIMIT52:
139 s->ttl = *(int *) CMSG_DATA(cmsg)((cmsg)->__cmsg_data);
140 break;
141 }
142
143 } else if (cmsg->cmsg_level == IPPROTO_IPIPPROTO_IP) {
144 assert(s->peer.sa.sa_family == AF_INET)do { if ((__builtin_expect(!!(!(s->peer.sa.sa_family == 2)
),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("s->peer.sa.sa_family == AF_INET"
), "../src/resolve/resolved-dns-stream.c", 144, __PRETTY_FUNCTION__
); } while (0)
;
145
146 switch (cmsg->cmsg_type) {
147
148 case IP_PKTINFO8: {
149 struct in_pktinfo *i = (struct in_pktinfo*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data);
150
151 if (s->ifindex <= 0)
152 s->ifindex = i->ipi_ifindex;
153 break;
154 }
155
156 case IP_TTL2:
157 s->ttl = *(int *) CMSG_DATA(cmsg)((cmsg)->__cmsg_data);
158 break;
159 }
160 }
161 }
162
163 /* The Linux kernel sets the interface index to the loopback
164 * device if the connection came from the local host since it
165 * avoids the routing table in such a case. Let's unset the
166 * interface index in such a case. */
167 if (s->ifindex == LOOPBACK_IFINDEX1)
168 s->ifindex = 0;
169
170 /* If we don't know the interface index still, we look for the
171 * first local interface with a matching address. Yuck! */
172 if (s->ifindex <= 0)
173 s->ifindex = manager_find_ifindex(s->manager, s->local.sa.sa_family, s->local.sa.sa_family == AF_INET2 ? (union in_addr_union*) &s->local.in.sin_addr : (union in_addr_union*) &s->local.in6.sin6_addr);
174
175 if (s->protocol == DNS_PROTOCOL_LLMNR && s->ifindex > 0) {
176 uint32_t ifindex = htobe32(s->ifindex);
177
178 /* Make sure all packets for this connection are sent on the same interface */
179 if (s->local.sa.sa_family == AF_INET2) {
180 r = setsockopt(s->fd, IPPROTO_IPIPPROTO_IP, IP_UNICAST_IF50, &ifindex, sizeof(ifindex));
181 if (r < 0)
182 log_debug_errno(errno, "Failed to invoke IP_UNICAST_IF: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/resolve/resolved-dns-stream.c", 182
, __func__, "Failed to invoke IP_UNICAST_IF: %m") : -abs(_e);
})
;
183 } else if (s->local.sa.sa_family == AF_INET610) {
184 r = setsockopt(s->fd, IPPROTO_IPV6IPPROTO_IPV6, IPV6_UNICAST_IF76, &ifindex, sizeof(ifindex));
185 if (r < 0)
186 log_debug_errno(errno, "Failed to invoke IPV6_UNICAST_IF: %m")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm
= (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >=
((_level) & 0x07)) ? log_internal_realm(((_realm) <<
10 | (_level)), _e, "../src/resolve/resolved-dns-stream.c", 186
, __func__, "Failed to invoke IPV6_UNICAST_IF: %m") : -abs(_e
); })
;
187 }
188 }
189
190 s->identified = true1;
191
192 return 0;
193}
194
195static ssize_t dns_stream_writev(DnsStream *s, const struct iovec *iov, size_t iovcnt, int flags) {
196 ssize_t r;
197
198 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 198, __PRETTY_FUNCTION__); } while (0)
;
199 assert(iov)do { if ((__builtin_expect(!!(!(iov)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("iov"), "../src/resolve/resolved-dns-stream.c"
, 199, __PRETTY_FUNCTION__); } while (0)
;
200
201#if ENABLE_DNS_OVER_TLS1
202 if (s->tls_session && !(flags & WRITE_TLS_DATA1)) {
203 ssize_t ss;
204 size_t i;
205
206 r = 0;
207 for (i = 0; i < iovcnt; i++) {
208 ss = gnutls_record_send(s->tls_session, iov[i].iov_base, iov[i].iov_len);
209 if (ss < 0) {
210 switch(ss) {
211
212 case GNUTLS_E_INTERRUPTED-52:
213 return -EINTR4;
214 case GNUTLS_E_AGAIN-28:
215 return -EAGAIN11;
216 default:
217 log_debug("Failed to invoke gnutls_record_send: %s", gnutls_strerror(ss))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-stream.c", 217, __func__, "Failed to invoke gnutls_record_send: %s"
, gnutls_strerror(ss)) : -abs(_e); })
;
218 return -EIO5;
219 }
220 }
221
222 r += ss;
223 if (ss != (ssize_t) iov[i].iov_len)
224 continue;
225 }
226 } else
227#endif
228 if (s->tfo_salen > 0) {
229 struct msghdr hdr = {
230 .msg_iov = (struct iovec*) iov,
231 .msg_iovlen = iovcnt,
232 .msg_name = &s->tfo_address.sa,
233 .msg_namelen = s->tfo_salen
234 };
235
236 r = sendmsg(s->fd, &hdr, MSG_FASTOPENMSG_FASTOPEN);
237 if (r < 0) {
238 if (errno(*__errno_location ()) == EOPNOTSUPP95) {
239 s->tfo_salen = 0;
240 r = connect(s->fd, &s->tfo_address.sa, s->tfo_salen);
241 if (r < 0)
242 return -errno(*__errno_location ());
243
244 r = -EAGAIN11;
245 } else if (errno(*__errno_location ()) == EINPROGRESS115)
246 r = -EAGAIN11;
247 } else
248 s->tfo_salen = 0; /* connection is made */
249 } else {
250 r = writev(s->fd, iov, iovcnt);
251 if (r < 0)
252 r = -errno(*__errno_location ());
253 }
254
255 return r;
256}
257
258static ssize_t dns_stream_read(DnsStream *s, void *buf, size_t count) {
259 ssize_t ss;
260
261#if ENABLE_DNS_OVER_TLS1
262 if (s->tls_session) {
263 ss = gnutls_record_recv(s->tls_session, buf, count);
264 if (ss < 0) {
265 switch(ss) {
266
267 case GNUTLS_E_INTERRUPTED-52:
268 return -EINTR4;
269 case GNUTLS_E_AGAIN-28:
270 return -EAGAIN11;
271 default:
272 log_debug("Failed to invoke gnutls_record_send: %s", gnutls_strerror(ss))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/resolve/resolved-dns-stream.c", 272, __func__, "Failed to invoke gnutls_record_send: %s"
, gnutls_strerror(ss)) : -abs(_e); })
;
273 return -EIO5;
274 }
275 } else if (s->on_connection) {
276 int r;
277
278 r = s->on_connection(s);
279 s->on_connection = NULL((void*)0); /* only call once */
280 if (r < 0)
281 return r;
282 }
283 } else
284#endif
285 {
286 ss = read(s->fd, buf, count);
287 if (ss < 0)
288 ss = -errno(*__errno_location ());
289 }
290
291 return ss;
292}
293
294#if ENABLE_DNS_OVER_TLS1
295static ssize_t dns_stream_tls_writev(gnutls_transport_ptr_t p, const giovec_t * iov, int iovcnt) {
296 int r;
297
298 assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("p"), "../src/resolve/resolved-dns-stream.c"
, 298, __PRETTY_FUNCTION__); } while (0)
;
299
300 r = dns_stream_writev((DnsStream*) p, (struct iovec*) iov, iovcnt, WRITE_TLS_DATA1);
301 if (r < 0) {
302 errno(*__errno_location ()) = -r;
303 return -1;
304 }
305
306 return r;
307}
308#endif
309
310static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
311 DnsStream *s = userdata;
312
313 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 313, __PRETTY_FUNCTION__); } while (0)
;
314
315 return dns_stream_complete(s, ETIMEDOUT110);
316}
317
318static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
319 DnsStream *s = userdata;
320 int r;
321
322 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 322, __PRETTY_FUNCTION__); } while (0)
;
323
324#if ENABLE_DNS_OVER_TLS1
325 if (s->tls_bye) {
326 assert(s->tls_session)do { if ((__builtin_expect(!!(!(s->tls_session)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s->tls_session"), "../src/resolve/resolved-dns-stream.c"
, 326, __PRETTY_FUNCTION__); } while (0)
;
327
328 r = gnutls_bye(s->tls_session, GNUTLS_SHUT_RDWR);
329 if (r != GNUTLS_E_AGAIN-28) {
330 s->tls_bye = false0;
331 dns_stream_unref(s);
332 }
333
334 return 0;
335 }
336
337 if (s->tls_handshake < 0) {
338 assert(s->tls_session)do { if ((__builtin_expect(!!(!(s->tls_session)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s->tls_session"), "../src/resolve/resolved-dns-stream.c"
, 338, __PRETTY_FUNCTION__); } while (0)
;
339
340 s->tls_handshake = gnutls_handshake(s->tls_session);
341 if (s->tls_handshake >= 0) {
342 if (s->on_connection && !(gnutls_session_get_flags(s->tls_session) & GNUTLS_SFLAGS_FALSE_START)) {
343 r = s->on_connection(s);
344 s->on_connection = NULL((void*)0); /* only call once */
345 if (r < 0)
346 return r;
347 }
348 } else {
349 if (gnutls_error_is_fatal(s->tls_handshake))
350 return dns_stream_complete(s, ECONNREFUSED111);
351 else
352 return 0;
353 }
354
355 }
356#endif
357
358 /* only identify after connecting */
359 if (s->tfo_salen == 0) {
360 r = dns_stream_identify(s);
361 if (r < 0)
362 return dns_stream_complete(s, -r);
363 }
364
365 if ((revents & EPOLLOUTEPOLLOUT) &&
366 s->write_packet &&
367 s->n_written < sizeof(s->write_size) + s->write_packet->size) {
368
369 struct iovec iov[2];
370 ssize_t ss;
371
372 iov[0].iov_base = &s->write_size;
373 iov[0].iov_len = sizeof(s->write_size);
374 iov[1].iov_base = DNS_PACKET_DATA(s->write_packet);
375 iov[1].iov_len = s->write_packet->size;
376
377 IOVEC_INCREMENT(iov, 2, s->n_written);
378
379 ss = dns_stream_writev(s, iov, 2, 0);
380 if (ss < 0) {
381 if (!IN_SET(-ss, EINTR, EAGAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){4, 11})/sizeof(int)]; switch(-ss) { case
4: case 11: _found = 1; break; default: break; } _found; })
)
382 return dns_stream_complete(s, -ss);
383 } else
384 s->n_written += ss;
385
386 /* Are we done? If so, disable the event source for EPOLLOUT */
387 if (s->n_written >= sizeof(s->write_size) + s->write_packet->size) {
388 r = dns_stream_update_io(s);
389 if (r < 0)
390 return dns_stream_complete(s, -r);
391 }
392 }
393
394 if ((revents & (EPOLLINEPOLLIN|EPOLLHUPEPOLLHUP|EPOLLRDHUPEPOLLRDHUP)) &&
395 (!s->read_packet ||
396 s->n_read < sizeof(s->read_size) + s->read_packet->size)) {
397
398 if (s->n_read < sizeof(s->read_size)) {
399 ssize_t ss;
400
401 ss = dns_stream_read(s, (uint8_t*) &s->read_size + s->n_read, sizeof(s->read_size) - s->n_read);
402 if (ss < 0) {
403 if (!IN_SET(-ss, EINTR, EAGAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){4, 11})/sizeof(int)]; switch(-ss) { case
4: case 11: _found = 1; break; default: break; } _found; })
)
404 return dns_stream_complete(s, -ss);
405 } else if (ss == 0)
406 return dns_stream_complete(s, ECONNRESET104);
407 else
408 s->n_read += ss;
409 }
410
411 if (s->n_read >= sizeof(s->read_size)) {
412
413 if (be16toh(s->read_size) < DNS_PACKET_HEADER_SIZEsizeof(DnsPacketHeader))
414 return dns_stream_complete(s, EBADMSG74);
415
416 if (s->n_read < sizeof(s->read_size) + be16toh(s->read_size)) {
417 ssize_t ss;
418
419 if (!s->read_packet) {
420 r = dns_packet_new(&s->read_packet, s->protocol, be16toh(s->read_size), DNS_PACKET_SIZE_MAX0xFFFFu);
421 if (r < 0)
422 return dns_stream_complete(s, -r);
423
424 s->read_packet->size = be16toh(s->read_size);
425 s->read_packet->ipproto = IPPROTO_TCPIPPROTO_TCP;
426 s->read_packet->family = s->peer.sa.sa_family;
427 s->read_packet->ttl = s->ttl;
428 s->read_packet->ifindex = s->ifindex;
429
430 if (s->read_packet->family == AF_INET2) {
431 s->read_packet->sender.in = s->peer.in.sin_addr;
432 s->read_packet->sender_port = be16toh(s->peer.in.sin_port);
433 s->read_packet->destination.in = s->local.in.sin_addr;
434 s->read_packet->destination_port = be16toh(s->local.in.sin_port);
435 } else {
436 assert(s->read_packet->family == AF_INET6)do { if ((__builtin_expect(!!(!(s->read_packet->family ==
10)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("s->read_packet->family == AF_INET6"
), "../src/resolve/resolved-dns-stream.c", 436, __PRETTY_FUNCTION__
); } while (0)
;
437 s->read_packet->sender.in6 = s->peer.in6.sin6_addr;
438 s->read_packet->sender_port = be16toh(s->peer.in6.sin6_port);
439 s->read_packet->destination.in6 = s->local.in6.sin6_addr;
440 s->read_packet->destination_port = be16toh(s->local.in6.sin6_port);
441
442 if (s->read_packet->ifindex == 0)
443 s->read_packet->ifindex = s->peer.in6.sin6_scope_id;
444 if (s->read_packet->ifindex == 0)
445 s->read_packet->ifindex = s->local.in6.sin6_scope_id;
446 }
447 }
448
449 ss = dns_stream_read(s,
450 (uint8_t*) DNS_PACKET_DATA(s->read_packet) + s->n_read - sizeof(s->read_size),
451 sizeof(s->read_size) + be16toh(s->read_size) - s->n_read);
452 if (ss < 0) {
453 if (!IN_SET(errno, EINTR, EAGAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){4, 11})/sizeof(int)]; switch((*__errno_location
())) { case 4: case 11: _found = 1; break; default: break; }
_found; })
)
454 return dns_stream_complete(s, errno(*__errno_location ()));
455 } else if (ss == 0)
456 return dns_stream_complete(s, ECONNRESET104);
457 else
458 s->n_read += ss;
459 }
460
461 /* Are we done? If so, disable the event source for EPOLLIN */
462 if (s->n_read >= sizeof(s->read_size) + be16toh(s->read_size)) {
463 /* If there's a packet handler
464 * installed, call that. Note that
465 * this is optional... */
466 if (s->on_packet) {
467 r = s->on_packet(s);
468 if (r < 0)
469 return r;
470 }
471
472 r = dns_stream_update_io(s);
473 if (r < 0)
474 return dns_stream_complete(s, -r);
475 }
476 }
477 }
478
479 if ((s->write_packet && s->n_written >= sizeof(s->write_size) + s->write_packet->size) &&
480 (s->read_packet && s->n_read >= sizeof(s->read_size) + s->read_packet->size))
481 return dns_stream_complete(s, 0);
482
483 return 0;
484}
485
486DnsStream *dns_stream_unref(DnsStream *s) {
487 DnsPacket *p;
488 Iterator i;
489
490 if (!s)
491 return NULL((void*)0);
492
493 assert(s->n_ref > 0)do { if ((__builtin_expect(!!(!(s->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s->n_ref > 0"), "../src/resolve/resolved-dns-stream.c"
, 493, __PRETTY_FUNCTION__); } while (0)
;
494 s->n_ref--;
495
496 if (s->n_ref > 0)
497 return NULL((void*)0);
498
499 dns_stream_stop(s);
500
501 if (s->server && s->server->stream == s)
502 s->server->stream = NULL((void*)0);
503
504 if (s->manager) {
505 LIST_REMOVE(streams, s->manager->dns_streams, s)do { typeof(*(s->manager->dns_streams)) **_head = &
(s->manager->dns_streams), *_item = (s); do { if ((__builtin_expect
(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD,
("_item"), "../src/resolve/resolved-dns-stream.c", 505, __PRETTY_FUNCTION__
); } while (0); if (_item->streams_next) _item->streams_next
->streams_prev = _item->streams_prev; if (_item->streams_prev
) _item->streams_prev->streams_next = _item->streams_next
; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)
)) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item"
), "../src/resolve/resolved-dns-stream.c", 505, __PRETTY_FUNCTION__
); } while (0); *_head = _item->streams_next; } _item->
streams_next = _item->streams_prev = ((void*)0); } while (
0)
;
506 s->manager->n_dns_streams--;
507 }
508
509#if ENABLE_DNS_OVER_TLS1
510 if (s->tls_session)
511 gnutls_deinit(s->tls_session);
512#endif
513
514 ORDERED_SET_FOREACH(p, s->write_queue, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), .
next_key = ((void*)0) }); ordered_set_iterate((s->write_queue
), &(i), (void**)&(p)); )
515 dns_packet_unref(ordered_set_remove(s->write_queue, p));
516
517 dns_packet_unref(s->write_packet);
518 dns_packet_unref(s->read_packet);
519 dns_server_unref(s->server);
520
521 ordered_set_free(s->write_queue);
522
523 return mfree(s);
524}
525
526DnsStream *dns_stream_ref(DnsStream *s) {
527 if (!s)
528 return NULL((void*)0);
529
530 assert(s->n_ref > 0)do { if ((__builtin_expect(!!(!(s->n_ref > 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s->n_ref > 0"), "../src/resolve/resolved-dns-stream.c"
, 530, __PRETTY_FUNCTION__); } while (0)
;
531 s->n_ref++;
532
533 return s;
534}
535
536int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address) {
537 _cleanup_(dns_stream_unrefp)__attribute__((cleanup(dns_stream_unrefp))) DnsStream *s = NULL((void*)0);
538 int r;
539
540 assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("m"), "../src/resolve/resolved-dns-stream.c"
, 540, __PRETTY_FUNCTION__); } while (0)
;
1
Assuming 'm' is non-null
2
Taking false branch
3
Loop condition is false. Exiting loop
541 assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/resolve/resolved-dns-stream.c"
, 541, __PRETTY_FUNCTION__); } while (0)
;
4
Assuming 'fd' is >= 0
5
Taking false branch
6
Loop condition is false. Exiting loop
542
543 if (m->n_dns_streams > DNS_STREAMS_MAX128)
7
Assuming field 'n_dns_streams' is <= DNS_STREAMS_MAX
8
Taking false branch
544 return -EBUSY16;
545
546 s = new0(DnsStream, 1)((DnsStream*) calloc((1), sizeof(DnsStream)));
9
Memory is allocated
547 if (!s)
10
Assuming 's' is non-null
11
Taking false branch
548 return -ENOMEM12;
549
550 r = ordered_set_ensure_allocated(&s->write_queue, &dns_packet_hash_ops);
551 if (r
11.1
'r' is < 0
< 0)
12
Taking true branch
552 return r;
13
Potential leak of memory pointed to by 's'
553
554 s->n_ref = 1;
555 s->fd = -1;
556 s->protocol = protocol;
557
558 r = sd_event_add_io(m->event, &s->io_event_source, fd, EPOLLINEPOLLIN, on_stream_io, s);
559 if (r < 0)
560 return r;
561
562 (void) sd_event_source_set_description(s->io_event_source, "dns-stream-io");
563
564 r = sd_event_add_time(
565 m->event,
566 &s->timeout_event_source,
567 clock_boottime_or_monotonic(),
568 now(clock_boottime_or_monotonic()) + DNS_STREAM_TIMEOUT_USEC(10 * ((usec_t) 1000000ULL)), 0,
569 on_stream_timeout, s);
570 if (r < 0)
571 return r;
572
573 (void) sd_event_source_set_description(s->timeout_event_source, "dns-stream-timeout");
574
575 LIST_PREPEND(streams, m->dns_streams, s)do { typeof(*(m->dns_streams)) **_head = &(m->dns_streams
), *_item = (s); do { if ((__builtin_expect(!!(!(_item)),0)))
log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/resolve/resolved-dns-stream.c"
, 575, __PRETTY_FUNCTION__); } while (0); if ((_item->streams_next
= *_head)) _item->streams_next->streams_prev = _item; _item
->streams_prev = ((void*)0); *_head = _item; } while (0)
;
576 s->manager = m;
577 s->fd = fd;
578 if (tfo_address) {
579 s->tfo_address = *tfo_address;
580 s->tfo_salen = tfo_address->sa.sa_family == AF_INET610 ? sizeof(tfo_address->in6) : sizeof(tfo_address->in);
581 }
582
583 m->n_dns_streams++;
584
585 *ret = TAKE_PTR(s)({ typeof(s) _ptr_ = (s); (s) = ((void*)0); _ptr_; });
586
587 return 0;
588}
589
590#if ENABLE_DNS_OVER_TLS1
591int dns_stream_connect_tls(DnsStream *s, gnutls_session_t tls_session) {
592 gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr_t) (long) s->fd, s);
593 gnutls_transport_set_vec_push_function(tls_session, &dns_stream_tls_writev);
594
595 s->encrypted = true1;
596 s->tls_session = tls_session;
597 s->tls_handshake = gnutls_handshake(tls_session);
598 if (s->tls_handshake < 0 && gnutls_error_is_fatal(s->tls_handshake))
599 return -ECONNREFUSED111;
600
601 return 0;
602}
603#endif
604
605int dns_stream_write_packet(DnsStream *s, DnsPacket *p) {
606 int r;
607
608 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/resolve/resolved-dns-stream.c"
, 608, __PRETTY_FUNCTION__); } while (0)
;
609
610 r = ordered_set_put(s->write_queue, p);
611 if (r < 0)
612 return r;
613
614 dns_packet_ref(p);
615
616 return dns_stream_update_io(s);
617}