| 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 | 
|---|