chiark / gitweb /
7b5580ffcc2f92d8cd94c9a3805030808a1b6c9e
[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         LIST_REMOVE(scopes, s->manager->dns_scopes, s);
64         strv_free(s->domains);
65         free(s);
66
67         return NULL;
68 }
69
70 DnsServer *dns_scope_get_server(DnsScope *s) {
71         assert(s);
72
73         if (s->link)
74                 return link_get_dns_server(s->link);
75         else
76                 return manager_get_dns_server(s->manager);
77 }
78
79 void dns_scope_next_dns_server(DnsScope *s) {
80         assert(s);
81
82         if (s->link)
83                 link_next_dns_server(s->link);
84         else
85                 manager_next_dns_server(s->manager);
86 }
87
88 int dns_scope_send(DnsScope *s, DnsPacket *p) {
89         int ifindex = 0;
90         DnsServer *srv;
91         int r;
92
93         assert(s);
94         assert(p);
95
96         srv = dns_scope_get_server(s);
97         if (!srv)
98                 return -ESRCH;
99
100         if (s->link) {
101                 if (p->size > s->link->mtu)
102                         return -EMSGSIZE;
103
104                 ifindex = s->link->ifindex;
105         } else {
106                 uint32_t mtu;
107
108                 mtu = manager_find_mtu(s->manager);
109                 if (mtu > 0) {
110                         if (p->size > mtu)
111                                 return -EMSGSIZE;
112                 }
113         }
114
115         if (p->size > DNS_PACKET_UNICAST_SIZE_MAX)
116                 return -EMSGSIZE;
117
118         if (srv->family == AF_INET)
119                 r = manager_dns_ipv4_send(s->manager, srv, ifindex, p);
120         else if (srv->family == AF_INET6)
121                 r = manager_dns_ipv6_send(s->manager, srv, ifindex, p);
122         else
123                 return -EAFNOSUPPORT;
124
125         if (r < 0)
126                 return r;
127
128         return 1;
129 }
130
131 int dns_scope_tcp_socket(DnsScope *s) {
132         _cleanup_close_ int fd = -1;
133         union sockaddr_union sa = {};
134         socklen_t salen;
135         int one, ifindex, ret;
136         DnsServer *srv;
137         int r;
138
139         assert(s);
140
141         srv = dns_scope_get_server(s);
142         if (!srv)
143                 return -ESRCH;
144
145         if (s->link)
146                 ifindex = s->link->ifindex;
147
148         sa.sa.sa_family = srv->family;
149         if (srv->family == AF_INET) {
150                 sa.in.sin_port = htobe16(53);
151                 sa.in.sin_addr = srv->address.in;
152                 salen = sizeof(sa.in);
153         } else if (srv->family == AF_INET6) {
154                 sa.in6.sin6_port = htobe16(53);
155                 sa.in6.sin6_addr = srv->address.in6;
156                 sa.in6.sin6_scope_id = ifindex;
157                 salen = sizeof(sa.in6);
158         } else
159                 return -EAFNOSUPPORT;
160
161         fd = socket(srv->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
162         if (fd < 0)
163                 return -errno;
164
165         one = 1;
166         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
167
168         r = connect(fd, &sa.sa, salen);
169         if (r < 0 && errno != EINPROGRESS)
170                 return -errno;
171
172         ret = fd;
173         fd = -1;
174         return ret;
175 }
176
177 DnsScopeMatch dns_scope_test(DnsScope *s, const char *domain) {
178         char **i;
179
180         assert(s);
181         assert(domain);
182
183         STRV_FOREACH(i, s->domains)
184                 if (dns_name_endswith(domain, *i))
185                         return DNS_SCOPE_YES;
186
187         if (dns_name_root(domain))
188                 return DNS_SCOPE_NO;
189
190         if (is_localhost(domain))
191                 return DNS_SCOPE_NO;
192
193         if (s->type == DNS_SCOPE_MDNS) {
194                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
195                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa"))
196                         return DNS_SCOPE_YES;
197                 else if (dns_name_endswith(domain, "local") ||
198                          !dns_name_single_label(domain))
199                         return DNS_SCOPE_MAYBE;
200
201                 return DNS_SCOPE_NO;
202         }
203
204         if (s->type == DNS_SCOPE_DNS) {
205                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
206                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
207                     dns_name_single_label(domain))
208                         return DNS_SCOPE_NO;
209
210                 return DNS_SCOPE_MAYBE;
211         }
212
213         assert_not_reached("Unknown scope type");
214 }