Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / tools / dns_fuzz_stub / dns_fuzz_stub.cc
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 <algorithm>
6 #include <sstream>
7 #include <string>
8 #include <vector>
9
10 #include "base/basictypes.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/json/json_reader.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/time/time.h"
16 #include "base/values.h"
17 #include "net/base/address_list.h"
18 #include "net/base/dns_util.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/dns/dns_protocol.h"
22 #include "net/dns/dns_query.h"
23 #include "net/dns/dns_response.h"
24
25 namespace {
26
27 void CrashDoubleFree(void) {
28   // Cause ASAN to detect a double-free
29   void *p = malloc(1);
30   LOG(INFO) << "Allocated p=" << p << ".  Double-freeing...";
31   free(p);
32   free(p);
33 }
34
35 void CrashNullPointerDereference(void) {
36   // Cause the program to segfault with a NULL pointer dereference
37   int *p = NULL;
38   *p = 0;
39 }
40
41 bool FitsUint8(int num) {
42   return (num >= 0) && (num <= kuint8max);
43 }
44
45 bool FitsUint16(int num) {
46   return (num >= 0) && (num <= kuint16max);
47 }
48
49 bool ReadTestCase(const char* filename,
50                   uint16* id, std::string* qname, uint16* qtype,
51                   std::vector<char>* resp_buf,
52                   bool* crash_test) {
53   base::FilePath filepath = base::FilePath::FromUTF8Unsafe(filename);
54
55   std::string json;
56   if (!base::ReadFileToString(filepath, &json)) {
57     LOG(ERROR) << filename << ": couldn't read file.";
58     return false;
59   }
60
61   scoped_ptr<base::Value> value(base::JSONReader::Read(json));
62   if (!value.get()) {
63     LOG(ERROR) << filename << ": couldn't parse JSON.";
64     return false;
65   }
66
67   base::DictionaryValue* dict;
68   if (!value->GetAsDictionary(&dict)) {
69     LOG(ERROR) << filename << ": test case is not a dictionary.";
70     return false;
71   }
72
73   *crash_test = dict->HasKey("crash_test");
74   if (*crash_test) {
75     LOG(INFO) << filename << ": crash_test is set!";
76     return true;
77   }
78
79   int id_int;
80   if (!dict->GetInteger("id", &id_int)) {
81     LOG(ERROR) << filename << ": id is missing or not an integer.";
82     return false;
83   }
84   if (!FitsUint16(id_int)) {
85     LOG(ERROR) << filename << ": id is out of range.";
86     return false;
87   }
88   *id = static_cast<uint16>(id_int);
89
90   if (!dict->GetStringASCII("qname", qname)) {
91     LOG(ERROR) << filename << ": qname is missing or not a string.";
92     return false;
93   }
94
95   int qtype_int;
96   if (!dict->GetInteger("qtype", &qtype_int)) {
97     LOG(ERROR) << filename << ": qtype is missing or not an integer.";
98     return false;
99   }
100   if (!FitsUint16(qtype_int)) {
101     LOG(ERROR) << filename << ": qtype is out of range.";
102     return false;
103   }
104   *qtype = static_cast<uint16>(qtype_int);
105
106   base::ListValue* resp_list;
107   if (!dict->GetList("response", &resp_list)) {
108     LOG(ERROR) << filename << ": response is missing or not a list.";
109     return false;
110   }
111
112   size_t resp_size = resp_list->GetSize();
113   resp_buf->clear();
114   resp_buf->reserve(resp_size);
115   for (size_t i = 0; i < resp_size; i++) {
116     int resp_byte_int;
117     if ((!resp_list->GetInteger(i, &resp_byte_int))) {
118       LOG(ERROR) << filename << ": response[" << i << "] is not an integer.";
119       return false;
120     }
121     if (!FitsUint8(resp_byte_int)) {
122       LOG(ERROR) << filename << ": response[" << i << "] is out of range.";
123       return false;
124     }
125     resp_buf->push_back(static_cast<char>(resp_byte_int));
126   }
127   DCHECK(resp_buf->size() == resp_size);
128
129   LOG(INFO) << "Query: id=" << id_int << ", "
130             << "qname=" << *qname << ", "
131             << "qtype=" << qtype_int << ", "
132             << "resp_size=" << resp_size;
133
134   return true;
135 }
136
137 void RunTestCase(uint16 id, std::string& qname, uint16 qtype,
138                  std::vector<char>& resp_buf) {
139   net::DnsQuery query(id, qname, qtype);
140   net::DnsResponse response;
141   std::copy(resp_buf.begin(), resp_buf.end(), response.io_buffer()->data());
142
143   if (!response.InitParse(resp_buf.size(), query)) {
144     LOG(INFO) << "InitParse failed.";
145     return;
146   }
147
148   net::AddressList address_list;
149   base::TimeDelta ttl;
150   net::DnsResponse::Result result = response.ParseToAddressList(
151       &address_list, &ttl);
152   if (result != net::DnsResponse::DNS_PARSE_OK) {
153     LOG(INFO) << "ParseToAddressList failed: " << result;
154     return;
155   }
156
157   // Print the response in one compact line.
158   std::stringstream result_line;
159   result_line << "Response: address_list={ ";
160   for (unsigned int i = 0; i < address_list.size(); i++)
161     result_line << address_list[i].ToString() << " ";
162   result_line << "}, ttl=" << ttl.InSeconds() << "s";
163
164   LOG(INFO) << result_line.str();
165 }
166
167 bool ReadAndRunTestCase(const char* filename) {
168   uint16 id = 0;
169   std::string qname;
170   uint16 qtype = 0;
171   std::vector<char> resp_buf;
172   bool crash_test = false;
173
174   LOG(INFO) << "Test case: " << filename;
175
176   // ReadTestCase will print a useful error message if it fails.
177   if (!ReadTestCase(filename, &id, &qname, &qtype, &resp_buf, &crash_test))
178     return false;
179
180   if (crash_test) {
181     LOG(INFO) << "Crashing.";
182     CrashDoubleFree();
183     // if we're not running under ASAN, that might not have worked
184     CrashNullPointerDereference();
185     NOTREACHED();
186     return true;
187   }
188
189   std::string qname_dns;
190   if (!net::DNSDomainFromDot(qname, &qname_dns)) {
191     LOG(ERROR) << filename << ": DNSDomainFromDot(" << qname << ") failed.";
192     return false;
193   }
194
195   RunTestCase(id, qname_dns, qtype, resp_buf);
196
197   return true;
198 }
199
200 }
201
202 int main(int argc, char** argv) {
203   int ret = 0;
204
205   for (int i = 1; i < argc; i++)
206     if (!ReadAndRunTestCase(argv[i]))
207       ret = 2;
208
209   // Cluster-Fuzz likes "#EOF" as the last line of output to help distinguish
210   // successful runs from crashes.
211   printf("#EOF\n");
212
213   return ret;
214 }
215