aboutsummaryrefslogtreecommitdiff
path: root/resolv_private.h
blob: 31c541f4540c47e8a9a2dca76862e6cb720dfba1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*	$NetBSD: resolv.h,v 1.31 2005/12/26 19:01:47 perry Exp $	*/

/*
 * Copyright (c) 1983, 1987, 1989
 *    The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#pragma once

#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <private/android_filesystem_config.h>  // AID_DNS

#include <net/if.h>
#include <time.h>
#include <span>
#include <string>
#include <vector>

#include "DnsResolver.h"
#include "netd_resolv/resolv.h"
#include "params.h"
#include "stats.pb.h"

// Linux defines MAXHOSTNAMELEN as 64, while the domain name limit in
// RFC 1034 and RFC 1035 is 255 octets.
#ifdef MAXHOSTNAMELEN
#undef MAXHOSTNAMELEN
#endif
#define MAXHOSTNAMELEN 256

/*
 * Global defines and variables for resolver stub.
 */
#define RES_TIMEOUT 5000 /* min. milliseconds between retries */
#define RES_DFLRETRY 2    /* Default #/tries. */

// Flags for ResState::flags
#define RES_F_VC 0x00000001        // socket is TCP
#define RES_F_EDNS0ERR 0x00000004  // EDNS0 caused errors
#define RES_F_MDNS 0x00000008      // MDNS packet

// Holds either a sockaddr_in or a sockaddr_in6.
union sockaddr_union {
    struct sockaddr sa;
    struct sockaddr_in sin;
    struct sockaddr_in6 sin6;
};
constexpr int MAXPACKET = 8 * 1024;

const unsigned C_UNICAST = 0x8000;  // unicast-response bit for MDNS

struct ResState {
    ResState(const android_net_context* netcontext, android::net::NetworkDnsEventReported* dnsEvent)
        : netid(netcontext->dns_netid),
          uid(netcontext->uid),
          pid(netcontext->pid),
          mark(netcontext->dns_mark),
          event(dnsEvent),
          netcontext_flags(netcontext->flags) {}

    ResState clone(android::net::NetworkDnsEventReported* dnsEvent = nullptr) {
        // TODO: Separate non-copyable members to other structures and let default copy
        //       constructor do its work for below copyable members.
        ResState copy;
        copy.netid = netid;
        copy.uid = uid;
        copy.pid = pid;
        copy.search_domains = search_domains;
        copy.nsaddrs = nsaddrs;
        copy.ndots = ndots;
        copy.mark = mark;
        copy.flags = flags;
        copy.event = (dnsEvent == nullptr) ? event : dnsEvent;
        copy.netcontext_flags = netcontext_flags;
        copy.tc_mode = tc_mode;
        copy.enforce_dns_uid = enforce_dns_uid;
        copy.sort_nameservers = sort_nameservers;
        return copy;
    }
    void closeSockets() {
        tcp_nssock.reset();
        flags &= ~RES_F_VC;

        for (auto& sock : udpsocks) {
            sock.reset();
        }
    }

    int nameserverCount() { return nsaddrs.size(); }

    // clang-format off
    unsigned netid;                             // NetId: cache key and socket mark
    uid_t uid;                                  // uid of the app that sent the DNS lookup
    pid_t pid;                                  // pid of the app that sent the DNS lookup
    std::vector<std::string> search_domains{};  // domains to search
    std::vector<android::netdutils::IPSockAddr> nsaddrs;
    android::base::unique_fd udpsocks[MAXNS];   // UDP sockets to nameservers
    unsigned ndots : 4 = 1;                     // threshold for initial abs. query
    unsigned mark;                              // Socket mark to be used by all DNS query sockets
    android::base::unique_fd tcp_nssock;        // TCP socket (but why not one per nameserver?)
    uint32_t flags = 0;                         // See RES_F_* defines below
    android::net::NetworkDnsEventReported* event;
    uint32_t netcontext_flags;
    int tc_mode = 0;
    bool enforce_dns_uid = false;
    bool sort_nameservers = false;              // True if nsaddrs has been sorted.
    // clang-format on

  private:
    ResState() {}
};

/* End of stats related definitions */

/*
 * Error code extending h_errno codes defined in bionic/libc/include/netdb.h.
 *
 * This error code, including legacy h_errno, is returned from res_nquery(), res_nsearch(),
 * res_nquerydomain(), res_queryN(), res_searchN() and res_querydomainN() for DNS metrics.
 *
 * TODO: Consider mapping legacy and extended h_errno into a unified resolver error code mapping.
 */
#define NETD_RESOLV_H_ERRNO_EXT_TIMEOUT RCODE_TIMEOUT

extern const char* const _res_opcodes[];

int res_nameinquery(const char*, int, int, const uint8_t*, const uint8_t*);
int res_queriesmatch(const uint8_t*, const uint8_t*, const uint8_t*, const uint8_t*);

int res_nquery(ResState*, const char*, int, int, std::span<uint8_t>, int*);
int res_nsearch(ResState*, const char*, int, int, std::span<uint8_t>, int*);
int res_nquerydomain(ResState*, const char*, const char*, int, int, std::span<uint8_t>, int*);
int res_nmkquery(int op, const char* qname, int cl, int type, std::span<const uint8_t> data,
                 std::span<uint8_t> msg, int netcontext_flags);
int res_nsend(ResState* statp, std::span<const uint8_t> msg, std::span<uint8_t> ans, int* rcode,
              uint32_t flags, std::chrono::milliseconds sleepTimeMs = {});
int res_nopt(ResState*, int, std::span<uint8_t>, int);

int getaddrinfo_numeric(const char* hostname, const char* servname, addrinfo hints,
                        addrinfo** result);

// Helper function for converting h_errno to the error codes visible to netd
int herrnoToAiErrno(int herrno);

// Helper function to enable MDNS resolution.
void setMdnsFlag(std::string_view hostname, uint32_t* flags);

// Helper function for checking MDNS resolution is enabled or not.
bool isMdnsResolution(uint32_t flags);

// switch resolver log severity
android::base::LogSeverity logSeverityStrToEnum(const std::string& logSeverityStr);

template <typename Dest>
Dest saturate_cast(int64_t x) {
    using DestLimits = std::numeric_limits<Dest>;
    if (x > DestLimits::max()) return DestLimits::max();
    if (x < DestLimits::min()) return DestLimits::min();
    return static_cast<Dest>(x);
}

constexpr bool is_power_of_2(size_t n) {
    return n != 0 && (n & (n - 1)) == 0;
}

// Rounds up a pointer to a char buffer |p| to a multiple of |Alignment| bytes.
// Requirements:
//   |p| must be a pointer to a byte-sized type (e.g.: uint8_t)
//   |Alignment| must be a power of 2
template<uintptr_t Alignment = sizeof(void*), typename T>
        requires (sizeof(T) == 1) && (is_power_of_2(Alignment))
constexpr T* align_ptr(T* const p) {
    // Written this way to sidestep the performance-no-int-to-ptr clang-tidy warning.
    constexpr uintptr_t mask = Alignment - 1;
    const uintptr_t uintptr = reinterpret_cast<uintptr_t>(p);
    const uintptr_t aligned = (uintptr + mask) & ~mask;
    const uintptr_t bias = aligned - uintptr;
    return p + bias;
}

// Testcases for align_ptr()
// TODO: enable when libc++ has std::bit_cast - reinterpret_cast isn't allowed in consteval context
// static_assert(align_ptr((char*)1000) == (char*)1000);
// static_assert(align_ptr((char*)1001) == (char*)1000 + sizeof(void*));
// static_assert(align_ptr((char*)1003) == (char*)1000 + sizeof(void*));
// static_assert(align_ptr<sizeof(uint32_t)>((char*)1004) == (char*)1004);
// static_assert(align_ptr<sizeof(uint64_t)>((char*)1004) == (char*)1008);

android::net::NsType getQueryType(std::span<const uint8_t> msg);

android::net::IpVersion ipFamilyToIPVersion(int ipFamily);

inline void resolv_tag_socket(int sock, uid_t uid, pid_t pid) {
    // This is effectively equivalent to testing for R+
    if (android::net::gResNetdCallbacks.tagSocket != nullptr) {
        if (int err = android::net::gResNetdCallbacks.tagSocket(sock, TAG_SYSTEM_DNS, uid, pid)) {
            LOG(WARNING) << "Failed to tag socket: " << strerror(-err);
        }
    }

    // fchown() apps' uid only in R+, since it's incompatible with Q's ebpf vpn isolation feature.
    if (fchown(sock, (android::net::gApiLevel >= 30) ? uid : AID_DNS, -1) == -1) {
        PLOG(WARNING) << "Failed to chown socket";
    }
}