chiark / gitweb /
b6884fd0aaf0cff60bbc656ec76a3b0b2b0e276e
[elogind.git] / src / resolve / resolved-dns-scope.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/tcp.h>
23
24 #include "strv.h"
25 #include "socket-util.h"
26 #include "resolved-dns-domain.h"
27 #include "resolved-dns-scope.h"
28
29 #define SEND_TIMEOUT_USEC (2*USEC_PER_SEC)
30
31 int dns_scope_new(Manager *m, DnsScope **ret, DnsScopeType t) {
32         DnsScope *s;
33
34         assert(m);
35         assert(ret);
36
37         s = new0(DnsScope, 1);
38         if (!s)
39                 return -ENOMEM;
40
41         s->manager = m;
42         s->type = t;
43
44         LIST_PREPEND(scopes, m->dns_scopes, s);
45
46         *ret = s;
47         return 0;
48 }
49
50 DnsScope* dns_scope_free(DnsScope *s) {
51         if (!s)
52                 return NULL;
53
54         while (s->transactions) {
55                 DnsQuery *q;
56
57                 q = s->transactions->query;
58                 dns_query_transaction_free(s->transactions);
59
60                 dns_query_finish(q);
61         }
62
63         dns_cache_flush(&s->cache);
64
65         LIST_REMOVE(scopes, s->manager->dns_scopes, s);
66         strv_free(s->domains);
67         free(s);
68
69         return NULL;
70 }
71
72 DnsServer *dns_scope_get_server(DnsScope *s) {
73         assert(s);
74
75         if (s->link)
76                 return link_get_dns_server(s->link);
77         else
78                 return manager_get_dns_server(s->manager);
79 }
80
81 void dns_scope_next_dns_server(DnsScope *s) {
82         assert(s);
83
84         if (s->link)
85                 link_next_dns_server(s->link);
86         else
87                 manager_next_dns_server(s->manager);
88 }
89
90 int dns_scope_send(DnsScope *s, DnsPacket *p) {
91         int ifindex = 0;
92         DnsServer *srv;
93         int r;
94
95         assert(s);
96         assert(p);
97
98         srv = dns_scope_get_server(s);
99         if (!srv)
100                 return -ESRCH;
101
102         if (s->link) {
103                 if (p->size > s->link->mtu)
104                         return -EMSGSIZE;
105
106                 ifindex = s->link->ifindex;
107         } else {
108                 uint32_t mtu;
109
110                 mtu = manager_find_mtu(s->manager);
111                 if (mtu > 0) {
112                         if (p->size > mtu)
113                                 return -EMSGSIZE;
114                 }
115         }
116
117         if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
118                 return -EMSGSIZE;
119
120         if (srv->family == AF_INET)
121                 r = manager_dns_ipv4_send(s->manager, srv, ifindex, p);
122         else if (srv->family == AF_INET6)
123                 r = manager_dns_ipv6_send(s->manager, srv, ifindex, p);
124         else
125                 return -EAFNOSUPPORT;
126
127         if (r < 0)
128                 return r;
129
130         return 1;
131 }
132
133 int dns_scope_tcp_socket(DnsScope *s) {
134         _cleanup_close_ int fd = -1;
135         union sockaddr_union sa = {};
136         socklen_t salen;
137         int one, ifindex, ret;
138         DnsServer *srv;
139         int r;
140
141         assert(s);
142
143         srv = dns_scope_get_server(s);
144         if (!srv)
145                 return -ESRCH;
146
147         if (s->link)
148                 ifindex = s->link->ifindex;
149
150         sa.sa.sa_family = srv->family;
151         if (srv->family == AF_INET) {
152                 sa.in.sin_port = htobe16(53);
153                 sa.in.sin_addr = srv->address.in;
154                 salen = sizeof(sa.in);
155         } else if (srv->family == AF_INET6) {
156                 sa.in6.sin6_port = htobe16(53);
157                 sa.in6.sin6_addr = srv->address.in6;
158                 sa.in6.sin6_scope_id = ifindex;
159                 salen = sizeof(sa.in6);
160         } else
161                 return -EAFNOSUPPORT;
162
163         fd = socket(srv->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
164         if (fd < 0)
165                 return -errno;
166
167         one = 1;
168         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
169
170         r = connect(fd, &sa.sa, salen);
171         if (r < 0 && errno != EINPROGRESS)
172                 return -errno;
173
174         ret = fd;
175         fd = -1;
176         return ret;
177 }
178
179 DnsScopeMatch dns_scope_test(DnsScope *s, const char *domain) {
180         char **i;
181
182         assert(s);
183         assert(domain);
184
185         STRV_FOREACH(i, s->domains)
186                 if (dns_name_endswith(domain, *i))
187                         return DNS_SCOPE_YES;
188
189         if (dns_name_root(domain))
190                 return DNS_SCOPE_NO;
191
192         if (is_localhost(domain))
193                 return DNS_SCOPE_NO;
194
195         if (s->type == DNS_SCOPE_MDNS) {
196                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
197                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa"))
198                         return DNS_SCOPE_YES;
199                 else if (dns_name_endswith(domain, "local") &&
200                          !dns_name_single_label(domain))
201                         return DNS_SCOPE_MAYBE;
202
203                 return DNS_SCOPE_NO;
204         }
205
206         if (s->type == DNS_SCOPE_DNS) {
207                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
208                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
209                     dns_name_single_label(domain))
210                         return DNS_SCOPE_NO;
211
212                 return DNS_SCOPE_MAYBE;
213         }
214
215         assert_not_reached("Unknown scope type");
216 }