OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <arpa/inet.h> | |
6 #include <errno.h> | |
7 #include <netinet/in.h> | |
8 #include <signal.h> | |
9 #include <stdio.h> | |
10 #include <stdlib.h> | |
11 #include <string.h> | |
12 #include <sys/socket.h> | |
13 #include <sys/types.h> | |
14 #include <unistd.h> | |
15 | |
16 #include <string> | |
17 | |
18 #include "base/basictypes.h" | |
19 #include "base/command_line.h" | |
20 #include "base/logging.h" | |
21 #include "base/posix/eintr_wrapper.h" | |
22 #include "base/safe_strerror_posix.h" | |
23 #include "net/base/big_endian.h" | |
24 #include "net/base/net_util.h" | |
25 #include "net/dns/dns_protocol.h" | |
26 #include "tools/android/common/daemon.h" | |
27 #include "tools/android/common/net.h" | |
28 | |
29 namespace { | |
30 | |
31 // Mininum request size: 1 question containing 1 QNAME, 1 TYPE and 1 CLASS. | |
32 const size_t kMinRequestSize = sizeof(net::dns_protocol::Header) + 6; | |
33 | |
34 // The name reference in the answer pointing to the name in the query. | |
35 // Its format is: highest two bits set to 1, then the offset of the name | |
36 // which just follows the header. | |
37 const uint16 kPointerToQueryName = | |
38 static_cast<uint16>(0xc000 | sizeof(net::dns_protocol::Header)); | |
39 | |
40 const uint32 kTTL = 86400; // One day. | |
41 | |
42 void PError(const char* msg) { | |
43 int current_errno = errno; | |
44 LOG(ERROR) << "ERROR: " << msg << ": " << safe_strerror(current_errno); | |
45 } | |
46 | |
47 void SendTo(int sockfd, const void* buf, size_t len, int flags, | |
48 const sockaddr* dest_addr, socklen_t addrlen) { | |
49 if (HANDLE_EINTR(sendto(sockfd, buf, len, flags, dest_addr, addrlen)) == -1) | |
50 PError("sendto()"); | |
51 } | |
52 | |
53 void CloseFileDescriptor(int fd) { | |
54 int old_errno = errno; | |
55 (void) HANDLE_EINTR(close(fd)); | |
56 errno = old_errno; | |
57 } | |
58 | |
59 void SendRefusedResponse(int sock, const sockaddr_in& client_addr, uint16 id) { | |
60 net::dns_protocol::Header response; | |
61 response.id = htons(id); | |
62 response.flags = htons(net::dns_protocol::kFlagResponse | | |
63 net::dns_protocol::kFlagAA | | |
64 net::dns_protocol::kFlagRD | | |
65 net::dns_protocol::kFlagRA | | |
66 net::dns_protocol::kRcodeREFUSED); | |
67 response.qdcount = 0; | |
68 response.ancount = 0; | |
69 response.nscount = 0; | |
70 response.arcount = 0; | |
71 SendTo(sock, &response, sizeof(response), 0, | |
72 reinterpret_cast<const sockaddr*>(&client_addr), sizeof(client_addr)); | |
73 } | |
74 | |
75 void SendResponse(int sock, const sockaddr_in& client_addr, uint16 id, | |
76 uint16 qtype, const char* question, size_t question_length) { | |
77 net::dns_protocol::Header header; | |
78 header.id = htons(id); | |
79 header.flags = htons(net::dns_protocol::kFlagResponse | | |
80 net::dns_protocol::kFlagAA | | |
81 net::dns_protocol::kFlagRD | | |
82 net::dns_protocol::kFlagRA | | |
83 net::dns_protocol::kRcodeNOERROR); | |
84 header.qdcount = htons(1); | |
85 header.ancount = htons(1); | |
86 header.nscount = 0; | |
87 header.arcount = 0; | |
88 | |
89 // Size of RDATA which is a IPv4 or IPv6 address. | |
90 size_t rdata_size = qtype == net::dns_protocol::kTypeA ? | |
91 net::kIPv4AddressSize : net::kIPv6AddressSize; | |
92 | |
93 // Size of the whole response which contains the header, the question and | |
94 // the answer. 12 is the sum of sizes of the compressed name reference, TYPE, | |
95 // CLASS, TTL and RDLENGTH. | |
96 size_t response_size = sizeof(header) + question_length + 12 + rdata_size; | |
97 | |
98 if (response_size > net::dns_protocol::kMaxUDPSize) { | |
99 LOG(ERROR) << "Response is too large: " << response_size; | |
100 SendRefusedResponse(sock, client_addr, id); | |
101 return; | |
102 } | |
103 | |
104 char response[net::dns_protocol::kMaxUDPSize]; | |
105 net::BigEndianWriter writer(response, arraysize(response)); | |
106 writer.WriteBytes(&header, sizeof(header)); | |
107 | |
108 // Repeat the question in the response. Some clients (e.g. ping) needs this. | |
109 writer.WriteBytes(question, question_length); | |
110 | |
111 // Construct the answer. | |
112 writer.WriteU16(kPointerToQueryName); | |
113 writer.WriteU16(qtype); | |
114 writer.WriteU16(net::dns_protocol::kClassIN); | |
115 writer.WriteU32(kTTL); | |
116 writer.WriteU16(rdata_size); | |
117 if (qtype == net::dns_protocol::kTypeA) | |
118 writer.WriteU32(INADDR_LOOPBACK); | |
119 else | |
120 writer.WriteBytes(&in6addr_loopback, sizeof(in6_addr)); | |
121 DCHECK(writer.ptr() - response == response_size); | |
122 | |
123 SendTo(sock, response, response_size, 0, | |
124 reinterpret_cast<const sockaddr*>(&client_addr), sizeof(client_addr)); | |
125 } | |
126 | |
127 void HandleRequest(int sock, const char* request, size_t size, | |
128 const sockaddr_in& client_addr) { | |
129 if (size < kMinRequestSize) { | |
130 LOG(ERROR) << "Request is too small " << size | |
131 << "\n" << tools::DumpBinary(request, size); | |
132 return; | |
133 } | |
134 | |
135 net::BigEndianReader reader(request, size); | |
136 net::dns_protocol::Header header; | |
137 reader.ReadBytes(&header, sizeof(header)); | |
138 uint16 id = ntohs(header.id); | |
139 uint16 flags = ntohs(header.flags); | |
140 uint16 qdcount = ntohs(header.qdcount); | |
141 uint16 ancount = ntohs(header.ancount); | |
142 uint16 nscount = ntohs(header.nscount); | |
143 uint16 arcount = ntohs(header.arcount); | |
144 | |
145 const uint16 kAllowedFlags = 0x07ff; | |
146 if ((flags & ~kAllowedFlags) || | |
147 qdcount != 1 || ancount || nscount || arcount) { | |
148 LOG(ERROR) << "Unsupported request: FLAGS=" << flags | |
149 << " QDCOUNT=" << qdcount | |
150 << " ANCOUNT=" << ancount | |
151 << " NSCOUNT=" << nscount | |
152 << " ARCOUNT=" << arcount | |
153 << "\n" << tools::DumpBinary(request, size); | |
154 SendRefusedResponse(sock, client_addr, id); | |
155 return; | |
156 } | |
157 | |
158 // request[size - 5] should be the end of the QNAME (a zero byte). | |
159 // We don't care about the validity of QNAME because we don't parse it. | |
160 const char* qname_end = &request[size - 5]; | |
161 if (*qname_end) { | |
162 LOG(ERROR) << "Error parsing QNAME\n" << tools::DumpBinary(request, size); | |
163 SendRefusedResponse(sock, client_addr, id); | |
164 return; | |
165 } | |
166 | |
167 reader.Skip(qname_end - reader.ptr() + 1); | |
168 | |
169 uint16 qtype; | |
170 uint16 qclass; | |
171 reader.ReadU16(&qtype); | |
172 reader.ReadU16(&qclass); | |
173 if ((qtype != net::dns_protocol::kTypeA && | |
174 qtype != net::dns_protocol::kTypeAAAA) || | |
175 qclass != net::dns_protocol::kClassIN) { | |
176 LOG(ERROR) << "Unsupported query: QTYPE=" << qtype << " QCLASS=" << qclass | |
177 << "\n" << tools::DumpBinary(request, size); | |
178 SendRefusedResponse(sock, client_addr, id); | |
179 return; | |
180 } | |
181 | |
182 SendResponse(sock, client_addr, id, qtype, | |
183 request + sizeof(header), size - sizeof(header)); | |
184 } | |
185 | |
186 } // namespace | |
187 | |
188 int main(int argc, char** argv) { | |
189 printf("Fake DNS server\n"); | |
190 | |
191 CommandLine command_line(argc, argv); | |
192 if (tools::HasHelpSwitch(command_line) || command_line.GetArgs().size()) { | |
193 tools::ShowHelp(argv[0], "", ""); | |
194 return 0; | |
195 } | |
196 | |
197 int sock = socket(AF_INET, SOCK_DGRAM, 0); | |
198 if (sock < 0) { | |
199 PError("create socket"); | |
200 return 1; | |
201 } | |
202 | |
203 sockaddr_in addr; | |
204 memset(&addr, 0, sizeof(addr)); | |
205 addr.sin_family = AF_INET; | |
206 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
207 addr.sin_port = htons(53); | |
208 int reuse_addr = 1; | |
209 if (HANDLE_EINTR(bind(sock, reinterpret_cast<sockaddr*>(&addr), | |
210 sizeof(addr))) < 0) { | |
211 PError("server bind"); | |
212 CloseFileDescriptor(sock); | |
213 return 1; | |
214 } | |
215 | |
216 if (!tools::HasNoSpawnDaemonSwitch(command_line)) | |
217 tools::SpawnDaemon(0); | |
218 | |
219 while (true) { | |
220 sockaddr_in client_addr; | |
221 socklen_t client_addr_len = sizeof(client_addr); | |
222 char request[net::dns_protocol::kMaxUDPSize]; | |
223 int size = HANDLE_EINTR(recvfrom(sock, request, sizeof(request), | |
224 MSG_WAITALL, | |
225 reinterpret_cast<sockaddr*>(&client_addr), | |
226 &client_addr_len)); | |
227 if (size < 0) { | |
228 // Unrecoverable error, can only exit. | |
229 LOG(ERROR) << "Failed to receive a request: " << strerror(errno); | |
230 CloseFileDescriptor(sock); | |
231 return 1; | |
232 } | |
233 | |
234 if (size > 0) | |
235 HandleRequest(sock, request, size, client_addr); | |
236 } | |
237 } | |
238 | |
OLD | NEW |