Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: tools/android/fake_dns/fake_dns.cc

Issue 26402002: [Android] Some clean up in pylib. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove shebang lines Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/android/fake_dns/DEPS ('k') | tools/android/fake_dns/fake_dns.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « tools/android/fake_dns/DEPS ('k') | tools/android/fake_dns/fake_dns.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698