chiark / gitweb /
0a70cb1f0f6486ff9e79fcc91069d305b09cb0e0
[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         }
106
107         if (srv->family == AF_INET)
108                 r = manager_dns_ipv4_send(s->manager, srv, ifindex, p);
109         else if (srv->family == AF_INET6)
110                 r = manager_dns_ipv6_send(s->manager, srv, ifindex, p);
111         else
112                 return -EAFNOSUPPORT;
113
114         if (r < 0)
115                 return r;
116
117         return 1;
118 }
119
120 int dns_scope_tcp_socket(DnsScope *s) {
121         _cleanup_close_ int fd = -1;
122         union sockaddr_union sa = {};
123         socklen_t salen;
124         int one, ifindex, ret;
125         DnsServer *srv;
126         int r;
127
128         assert(s);
129
130         srv = dns_scope_get_server(s);
131         if (!srv)
132                 return -ESRCH;
133
134         if (s->link)
135                 ifindex = s->link->ifindex;
136
137         sa.sa.sa_family = srv->family;
138         if (srv->family == AF_INET) {
139                 sa.in.sin_port = htobe16(53);
140                 sa.in.sin_addr = srv->address.in;
141                 salen = sizeof(sa.in);
142         } else if (srv->family == AF_INET6) {
143                 sa.in6.sin6_port = htobe16(53);
144                 sa.in6.sin6_addr = srv->address.in6;
145                 sa.in6.sin6_scope_id = ifindex;
146                 salen = sizeof(sa.in6);
147         } else
148                 return -EAFNOSUPPORT;
149
150         fd = socket(srv->family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
151         if (fd < 0)
152                 return -errno;
153
154         one = 1;
155         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
156
157         r = connect(fd, &sa.sa, salen);
158         if (r < 0 && errno != EINPROGRESS)
159                 return -errno;
160
161         ret = fd;
162         fd = -1;
163         return ret;
164 }
165
166 DnsScopeMatch dns_scope_test(DnsScope *s, const char *domain) {
167         char **i;
168
169         assert(s);
170         assert(domain);
171
172         STRV_FOREACH(i, s->domains)
173                 if (dns_name_endswith(domain, *i))
174                         return DNS_SCOPE_YES;
175
176         if (dns_name_root(domain))
177                 return DNS_SCOPE_NO;
178
179         if (s->type == DNS_SCOPE_MDNS) {
180                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
181                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa"))
182                         return DNS_SCOPE_YES;
183                 else if (dns_name_endswith(domain, "local") ||
184                          !dns_name_single_label(domain))
185                         return DNS_SCOPE_MAYBE;
186
187                 return DNS_SCOPE_NO;
188         }
189
190         if (s->type == DNS_SCOPE_DNS) {
191                 if (dns_name_endswith(domain, "254.169.in-addr.arpa") ||
192                     dns_name_endswith(domain, "0.8.e.f.ip6.arpa") ||
193                     dns_name_single_label(domain))
194                         return DNS_SCOPE_NO;
195
196                 return DNS_SCOPE_MAYBE;
197         }
198
199         assert_not_reached("Unknown scope type");
200 }