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

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

Issue 9401014: fake_dns tool for Android. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 10 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 | « build/all_android.gyp ('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')
Property Changes:
Added: svn:eol-style
+ LF
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/eintr_wrapper.h"
21 #include "base/logging.h"
22 #include "net/base/dns_util.h"
szym 2012/02/15 21:44:04 What is this needed for? If only kClassIN, then re
Xianzhu 2012/02/16 01:19:36 Now use net/dns/dns_protocol.h, net/base/net_util.
23 #include "tools/android/common/daemon.h"
24
25 namespace {
26
27 const size_t kMaxMessageSize = 512;
szym 2012/02/15 21:44:04 net::dns_protocol::kMaxUDPSize
Xianzhu 2012/02/16 01:19:36 Done.
28 const size_t kHeaderSize = 12;
szym 2012/02/15 21:44:04 sizeof(net::dns_protocol::Header)
Xianzhu 2012/02/16 01:19:36 Done.
29
30 // DNS resource record types. See
31 // http://www.iana.org/assignments/dns-parameters
32 const uint16 kDNS_A = 1;
szym 2012/02/15 21:44:04 net::dns_protocol::kTypeA
Xianzhu 2012/02/16 01:19:36 Done.
33 const uint16 kDNS_AAAA = 28;
34
35 // Mininum request size: 1 question containing 1 QNAME, 1 TYPE and 1 CLASS.
36 const size_t kMinRequestSize = kHeaderSize + 6;
37
38 // Sum of sizes of compressed name reference, TYPE, CLASS, TTL, RDLENGTH and
39 // RDATA of the fake answer.
40 const size_t kAnswerSizeV4 = 12 + sizeof(in_addr_t);
41 const size_t kAnswerSizeV6 = 12 + sizeof(in6_addr);
szym 2012/02/15 21:44:04 net::kIPv4AddressSize (in net/base/net_util.h)
Xianzhu 2012/02/16 01:19:36 Done.
42
43 // The name reference in answer, format is: highest two bits set to 1,
44 // then the offset of the qname which just follows the header.
szym 2012/02/15 21:44:04 It would help to specifically say that this is ref
Xianzhu 2012/02/16 01:19:36 Done.
45 const uint16 kNameReference = static_cast<uint16>(0xc000 | kHeaderSize);
46
47 const uint32 kTTL = 86400;
szym 2012/02/15 21:44:04 Comment that this equals 1 day.
Xianzhu 2012/02/16 01:19:36 Done.
48
49 const char* DumpBinary(const char* message, size_t length) {
50 static char buffer[kMaxMessageSize * 3 + 1];
51 for (size_t i = 0; i < length; i++)
52 snprintf(buffer + i * 3, 3, "%02x,", static_cast<uint8>(message[i]));
53 buffer[length * 3 - 1] = 0;
54 return buffer;
55 }
56
57 uint16 getU16(const char* buffer) {
szym 2012/02/15 21:44:04 See "net/base/big_endian.h" for this and the next
Xianzhu 2012/02/16 01:19:36 Done.
58 return static_cast<uint16>(buffer[0]) << 8 | static_cast<uint8>(buffer[1]);
59 }
60
61 void putU16(char* buffer, uint16 data) {
62 buffer[0] = static_cast<char>(data >> 8);
63 buffer[1] = static_cast<char>(data);
64 }
65
66 void putU32(char* buffer, uint32 data) {
67 buffer[0] = static_cast<char>(data >> 24);
68 buffer[1] = static_cast<char>(data >> 16);
69 buffer[2] = static_cast<char>(data >> 8);
70 buffer[3] = static_cast<char>(data);
71 }
72
73 bool SendPacketTo(int sock,
szym 2012/02/15 21:44:04 I think it wouldn't be much effort to make it asyn
Xianzhu 2012/02/16 01:19:36 We don't want to introduce much dependency to Chro
74 const char* data,
75 size_t size,
76 const sockaddr_in& target_addr) {
77 size_t bytes_sent = 0;
78 size_t bytes_remaining = size;
79 while (bytes_remaining > 0) {
szym 2012/02/15 21:44:04 This loop should not be necessary for datagram soc
Xianzhu 2012/02/16 01:19:36 Changed back to non-loop version.
80 ssize_t ret = HANDLE_EINTR(sendto(
81 sock, data + bytes_sent, bytes_remaining, 0,
82 reinterpret_cast<const sockaddr*>(&target_addr),
83 sizeof(target_addr)));
84 if (ret < 0)
85 return false;
86
87 bytes_sent += ret;
88 bytes_remaining -= ret;
89 }
90 return true;
91 }
92
93 void SendEmptyResponse(int sock, const sockaddr_in& client_addr, uint16 id) {
szym 2012/02/15 21:44:04 Rename to SendRefusedResponse. "Empty" suggests it
Xianzhu 2012/02/16 01:19:36 Done.
94 char response[kHeaderSize];
95 memset(response, 0, kHeaderSize);
96 putU16(response, id);
97 putU16(response + 2, 0x8585); // QR:1, AA:1, RD:1, RA:1, RCODE:5 (Refused).
szym 2012/02/15 21:44:04 With dns_protocol this would be kFlagResponse | kF
Xianzhu 2012/02/16 01:19:36 Done.
98 SendPacketTo(sock, response, kHeaderSize, client_addr);
99 }
100
101 void SendResponse(int sock, const sockaddr_in& client_addr, uint16 id,
102 uint16 qtype, const char* question, size_t question_length) {
103 size_t response_size = kHeaderSize + question_length +
104 (qtype == kDNS_A ? kAnswerSizeV4 : kAnswerSizeV6);
105 if (response_size > kMaxMessageSize) {
106 LOG(ERROR) << "Response is too large: " << response_size;
107 SendEmptyResponse(sock, client_addr, id);
108 return;
109 }
110
111 char response[kMaxMessageSize];
112 putU16(response, id);
113 putU16(response + 2, 0x8580); // QR:1, AA:1, RD:1, RA:1, RCODE:0 (No error).
szym 2012/02/15 21:44:04 As above.
Xianzhu 2012/02/16 01:19:36 Done.
114 putU16(response + 4, 1); // QDCOUNT
115 putU16(response + 6, 1); // ANCOUNT
116 putU16(response + 8, 0); // NSCOUNT
117 putU16(response + 10, 0); // ARCOUNT
szym 2012/02/15 21:44:04 See BigEndianWriter in "net/base/big_endian.h".
Xianzhu 2012/02/16 01:19:36 Done.
118
119 // Repeat the question in the response. Some clients (e.g. ping) needs this.
120 memcpy(response + kHeaderSize, question, question_length);
121
122 // Construct the answer.
123 char* answer = response + kHeaderSize + question_length;
124 putU16(answer, kNameReference); // References the QNAME in the question.
125 putU16(answer + 2, qtype);
126 putU16(answer + 4, net::kClassIN);
127 putU32(answer + 6, kTTL);
128 putU16(answer + 10, 4);
szym 2012/02/15 21:44:04 As above.
szym 2012/02/15 21:57:23 BUG: This should be |response_size|.
Xianzhu 2012/02/16 01:19:36 Done.
Xianzhu 2012/02/16 01:19:36 Good Catch! I think it should be the sizeof RDATA.
129 if (qtype == kDNS_A)
130 putU32(answer + 12, INADDR_LOOPBACK);
131 else
132 memcpy(answer + 12, &in6addr_loopback, sizeof(in6_addr));
133
134 SendPacketTo(sock, response, response_size, client_addr);
135 }
136
137 void HandleRequest(int sock, const char* request, size_t size,
138 const sockaddr_in& client_addr) {
139 if (size < kMinRequestSize) {
140 LOG(ERROR) << "Request is too small " << size
141 << "\n" << DumpBinary(request, size);
142 SendEmptyResponse(sock, client_addr, 0);
szym 2012/02/15 21:44:04 If id is set to 0, the client will ignore this, so
Xianzhu 2012/02/16 01:19:36 Done.
143 return;
144 }
145
146 uint16 id = getU16(request);
147 uint16 flags = getU16(request + 2);
szym 2012/02/15 21:44:04 See BigEndianReader in "net/base/big_endian.h"
szym 2012/02/15 21:46:43 There's also the option to use dns_protocol::Heade
Xianzhu 2012/02/16 01:19:36 Done.
Xianzhu 2012/02/16 01:19:36 Done.
148 uint16 qdcount = getU16(request + 4);
149 uint16 ancount = getU16(request + 6);
150 uint16 nscount = getU16(request + 8);
151 uint16 arcount = getU16(request + 10);
152 if ((flags & 0xf800) || qdcount != 1 || ancount || nscount || arcount) {
szym 2012/02/15 21:44:04 0xf800 looks arbitrary. Maybe: const uint16 kAllow
Xianzhu 2012/02/16 01:19:36 Done.
153 LOG(ERROR) << "Unsupported request: FLAGS=" << flags
154 << " QDCOUNT=" << qdcount
155 << " ANCOUNT=" << ancount
156 << " NSCOUNT=" << nscount
157 << " ARCOUNT=" << arcount
158 << "\n" << DumpBinary(request, size);
159 SendEmptyResponse(sock, client_addr, id);
160 return;
161 }
162
163 // Should be the end of the QNAME.
164 if (request[size - 5]) {
szym 2012/02/15 21:44:04 This is only a partial check. You're already inclu
Xianzhu 2012/02/16 01:19:36 We don't actually parse the QNAME, so it seems unn
165 LOG(ERROR) << "Error parsing QNAME" << "\n" << DumpBinary(request, size);
166 SendEmptyResponse(sock, client_addr, id);
167 return;
168 }
169
170 uint16 qtype = getU16(request + size - 4);
171 uint16 qclass = getU16(request + size - 2);
172 if ((qtype != kDNS_A && qtype != kDNS_AAAA) || qclass != net::kClassIN) {
173 LOG(ERROR) << "Unsupported query: QTYPE=" << qtype << " QCLASS=" << qclass
174 << "\n" << DumpBinary(request, size);
175 SendEmptyResponse(sock, client_addr, id);
176 return;
177 }
178
179 SendResponse(sock, client_addr, id, qtype,
180 request + kHeaderSize, size - kHeaderSize);
181 }
182
183 } // namespace
184
185 int main(int argc, char** argv) {
186 printf("Fake DNS server\n");
187
188 CommandLine command_line(argc, argv);
189 if (tools::HasHelpSwitch(command_line) || command_line.GetArgs().size()) {
190 tools::ShowHelp(argv[0], "", "");
191 return 0;
192 }
193
194 int sock = socket(AF_INET, SOCK_DGRAM, 0);
195 if (sock < 0) {
196 perror("create socket");
szym 2012/02/15 21:44:04 Why perror here and LOG(ERROR) above?
Xianzhu 2012/02/16 01:19:36 Because this is in the main process which can be s
197 return 1;
198 }
199
200 sockaddr_in addr;
201 memset(&addr, 0, sizeof(addr));
202 addr.sin_family = AF_INET;
203 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
204 addr.sin_port = htons(53);
205 int reuse_addr = 1;
206 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr));
szym 2012/02/15 21:44:04 I don't think SO_REUSEADDR is necessary. AFAIK, TI
Xianzhu 2012/02/16 01:19:36 Verified you are right.
207 if (HANDLE_EINTR(bind(sock, reinterpret_cast<sockaddr*>(&addr),
208 sizeof(addr))) < 0) {
209 perror("server bind");
210 HANDLE_EINTR(close(sock));
211 return 1;
212 }
213
214 if (!tools::HasNoSpawnDaemonSwitch(command_line))
215 tools::SpawnDaemon(0);
216
217 while (true) {
218 sockaddr_in client_addr;
219 socklen_t client_addr_len = sizeof(client_addr);
220 char request[kMaxMessageSize];
221 int size = HANDLE_EINTR(recvfrom(sock, request, sizeof(request),
222 MSG_WAITALL,
223 reinterpret_cast<sockaddr*>(&client_addr),
224 &client_addr_len));
225 if (size < 0) {
226 // Unrecoverable error, can only exit.
227 LOG(ERROR) << "Failed to receive a request: " << strerror(errno);
228 HANDLE_EINTR(close(sock));
229 return 1;
230 }
231
232 if (size > 0)
233 HandleRequest(sock, request, size, client_addr);
234 }
235 }
236
OLDNEW
« no previous file with comments | « build/all_android.gyp ('k') | tools/android/fake_dns/fake_dns.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698