15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <arpa/inet.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <netinet/in.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <unistd.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/safe_strerror_posix.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/big_endian.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_util.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_protocol.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/common/daemon.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "tools/android/common/net.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Mininum request size: 1 question containing 1 QNAME, 1 TYPE and 1 CLASS.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMinRequestSize = sizeof(net::dns_protocol::Header) + 6;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The name reference in the answer pointing to the name in the query.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Its format is: highest two bits set to 1, then the offset of the name
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// which just follows the header.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint16 kPointerToQueryName =
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<uint16>(0xc000 | sizeof(net::dns_protocol::Header));
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kTTL = 86400;  // One day.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PError(const char* msg) {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int current_errno = errno;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LOG(ERROR) << "ERROR: " << msg << ": " << safe_strerror(current_errno);
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SendTo(int sockfd, const void* buf, size_t len, int flags,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            const sockaddr* dest_addr, socklen_t addrlen) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(sendto(sockfd, buf, len, flags, dest_addr, addrlen)) == -1)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PError("sendto()");
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CloseFileDescriptor(int fd) {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int old_errno = errno;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (void) HANDLE_EINTR(close(fd));
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  errno = old_errno;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SendRefusedResponse(int sock, const sockaddr_in& client_addr, uint16 id) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::dns_protocol::Header response;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.id = htons(id);
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.flags = htons(net::dns_protocol::kFlagResponse |
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         net::dns_protocol::kFlagAA |
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         net::dns_protocol::kFlagRD |
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         net::dns_protocol::kFlagRA |
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         net::dns_protocol::kRcodeREFUSED);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.qdcount = 0;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.ancount = 0;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.nscount = 0;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  response.arcount = 0;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendTo(sock, &response, sizeof(response), 0,
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         reinterpret_cast<const sockaddr*>(&client_addr), sizeof(client_addr));
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SendResponse(int sock, const sockaddr_in& client_addr, uint16 id,
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  uint16 qtype, const char* question, size_t question_length) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::dns_protocol::Header header;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.id = htons(id);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.flags = htons(net::dns_protocol::kFlagResponse |
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       net::dns_protocol::kFlagAA |
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       net::dns_protocol::kFlagRD |
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       net::dns_protocol::kFlagRA |
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       net::dns_protocol::kRcodeNOERROR);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.qdcount = htons(1);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.ancount = htons(1);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.nscount = 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  header.arcount = 0;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Size of RDATA which is a IPv4 or IPv6 address.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t rdata_size = qtype == net::dns_protocol::kTypeA ?
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      net::kIPv4AddressSize : net::kIPv6AddressSize;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Size of the whole response which contains the header, the question and
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the answer. 12 is the sum of sizes of the compressed name reference, TYPE,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // CLASS, TTL and RDLENGTH.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t response_size = sizeof(header) + question_length + 12 + rdata_size;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (response_size > net::dns_protocol::kMaxUDPSize) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Response is too large: " << response_size;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendRefusedResponse(sock, client_addr, id);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char response[net::dns_protocol::kMaxUDPSize];
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::BigEndianWriter writer(response, arraysize(response));
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteBytes(&header, sizeof(header));
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Repeat the question in the response. Some clients (e.g. ping) needs this.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteBytes(question, question_length);
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Construct the answer.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteU16(kPointerToQueryName);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteU16(qtype);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteU16(net::dns_protocol::kClassIN);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteU32(kTTL);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  writer.WriteU16(rdata_size);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (qtype == net::dns_protocol::kTypeA)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    writer.WriteU32(INADDR_LOOPBACK);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    writer.WriteBytes(&in6addr_loopback, sizeof(in6_addr));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(writer.ptr() - response == response_size);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendTo(sock, response, response_size, 0,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         reinterpret_cast<const sockaddr*>(&client_addr), sizeof(client_addr));
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HandleRequest(int sock, const char* request, size_t size,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const sockaddr_in& client_addr) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (size < kMinRequestSize) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Request is too small " << size
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "\n" << tools::DumpBinary(request, size);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::BigEndianReader reader(request, size);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::dns_protocol::Header header;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader.ReadBytes(&header, sizeof(header));
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 id = ntohs(header.id);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 flags = ntohs(header.flags);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 qdcount = ntohs(header.qdcount);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 ancount = ntohs(header.ancount);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 nscount = ntohs(header.nscount);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 arcount = ntohs(header.arcount);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const uint16 kAllowedFlags = 0x07ff;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((flags & ~kAllowedFlags) ||
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qdcount != 1 || ancount || nscount || arcount) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unsupported request: FLAGS=" << flags
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " QDCOUNT=" << qdcount
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " ANCOUNT=" << ancount
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " NSCOUNT=" << nscount
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << " ARCOUNT=" << arcount
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "\n" << tools::DumpBinary(request, size);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendRefusedResponse(sock, client_addr, id);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // request[size - 5] should be the end of the QNAME (a zero byte).
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't care about the validity of QNAME because we don't parse it.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* qname_end = &request[size - 5];
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (*qname_end) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error parsing QNAME\n" << tools::DumpBinary(request, size);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendRefusedResponse(sock, client_addr, id);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader.Skip(qname_end - reader.ptr() + 1);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 qtype;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint16 qclass;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader.ReadU16(&qtype);
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  reader.ReadU16(&qclass);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((qtype != net::dns_protocol::kTypeA &&
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       qtype != net::dns_protocol::kTypeAAAA) ||
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      qclass != net::dns_protocol::kClassIN) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Unsupported query: QTYPE=" << qtype << " QCLASS=" << qclass
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               << "\n" << tools::DumpBinary(request, size);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SendRefusedResponse(sock, client_addr, id);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SendResponse(sock, client_addr, id, qtype,
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               request + sizeof(header), size - sizeof(header));
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int main(int argc, char** argv) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  printf("Fake DNS server\n");
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine command_line(argc, argv);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tools::HasHelpSwitch(command_line) || command_line.GetArgs().size()) {
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tools::ShowHelp(argv[0], "", "");
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int sock = socket(AF_INET, SOCK_DGRAM, 0);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sock < 0) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PError("create socket");
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sockaddr_in addr;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&addr, 0, sizeof(addr));
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_family = AF_INET;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  addr.sin_port = htons(53);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int reuse_addr = 1;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HANDLE_EINTR(bind(sock, reinterpret_cast<sockaddr*>(&addr),
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        sizeof(addr))) < 0) {
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PError("server bind");
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CloseFileDescriptor(sock);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 1;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!tools::HasNoSpawnDaemonSwitch(command_line))
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tools::SpawnDaemon(0);
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (true) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sockaddr_in client_addr;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socklen_t client_addr_len = sizeof(client_addr);
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char request[net::dns_protocol::kMaxUDPSize];
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int size = HANDLE_EINTR(recvfrom(sock, request, sizeof(request),
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     MSG_WAITALL,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     reinterpret_cast<sockaddr*>(&client_addr),
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     &client_addr_len));
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size < 0) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Unrecoverable error, can only exit.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to receive a request: " << strerror(errno);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseFileDescriptor(sock);
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 1;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (size > 0)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HandleRequest(sock, request, size, client_addr);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
239