]>
Commit | Line | Data |
---|---|---|
49a699c4 | 1 | /* |
6edbf68a PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
49a699c4 BH |
25 | #include "syncres.hh" |
26 | #include "arguments.hh" | |
27 | #include "zoneparser-tng.hh" | |
28 | #include "logger.hh" | |
29 | #include "dnsrecords.hh" | |
10c96475 | 30 | #include "root-addresses.hh" |
302df819 AT |
31 | |
32 | extern int g_argc; | |
33 | extern char** g_argv; | |
49a699c4 | 34 | |
1b4e0ae0 OM |
35 | static thread_local set<DNSName> t_rootNSZones; |
36 | ||
feb47aed OM |
37 | static void insertIntoRootNSZones(const DNSName &name) { |
38 | // do not insert dot, wiping dot's NS records from the cache in primeRootNSZones() | |
39 | // will cause infinite recursion | |
40 | if (!name.isRoot()) { | |
41 | t_rootNSZones.insert(name); | |
42 | } | |
43 | } | |
44 | ||
49a699c4 BH |
45 | void primeHints(void) |
46 | { | |
47 | // prime root cache | |
fb17a52f | 48 | const vState validationState = Insecure; |
e325f20c | 49 | vector<DNSRecord> nsset; |
1b4e0ae0 | 50 | t_rootNSZones.clear(); |
49a699c4 BH |
51 | |
52 | if(::arg()["hint-file"].empty()) { | |
e325f20c | 53 | DNSRecord arr, aaaarr, nsrr; |
12c06211 | 54 | nsrr.d_name=g_rootdnsname; |
e325f20c | 55 | arr.d_type=QType::A; |
56 | aaaarr.d_type=QType::AAAA; | |
57 | nsrr.d_type=QType::NS; | |
58 | arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(0)+3600000; | |
49a699c4 BH |
59 | |
60 | for(char c='a';c<='m';++c) { | |
e863a05a | 61 | char templ[40]; |
49a699c4 | 62 | strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1); |
a683e8bd | 63 | templ[sizeof(templ)-1] = '\0'; |
49a699c4 | 64 | *templ=c; |
e325f20c | 65 | aaaarr.d_name=arr.d_name=DNSName(templ); |
feb47aed | 66 | insertIntoRootNSZones(arr.d_name.getLastLabel()); |
e325f20c | 67 | nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ)); |
10c96475 | 68 | arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a'])); |
e325f20c | 69 | vector<DNSRecord> aset; |
70 | aset.push_back(arr); | |
d6fd3cb8 | 71 | s_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); // auth, nuke it all |
10c96475 PL |
72 | if (rootIps6[c-'a'] != NULL) { |
73 | aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a'])); | |
49a699c4 | 74 | |
e325f20c | 75 | vector<DNSRecord> aaaaset; |
76 | aaaaset.push_back(aaaarr); | |
d6fd3cb8 | 77 | s_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); |
49a699c4 BH |
78 | } |
79 | ||
e325f20c | 80 | nsset.push_back(nsrr); |
49a699c4 BH |
81 | } |
82 | } | |
83 | else { | |
84 | ZoneParserTNG zpt(::arg()["hint-file"]); | |
ba3d53d1 | 85 | zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); |
49a699c4 BH |
86 | DNSResourceRecord rr; |
87 | ||
88 | while(zpt.get(rr)) { | |
89 | rr.ttl+=time(0); | |
90 | if(rr.qtype.getCode()==QType::A) { | |
e325f20c | 91 | vector<DNSRecord> aset; |
92 | aset.push_back(DNSRecord(rr)); | |
d6fd3cb8 | 93 | s_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); // auth, etc see above |
49a699c4 | 94 | } else if(rr.qtype.getCode()==QType::AAAA) { |
e325f20c | 95 | vector<DNSRecord> aaaaset; |
96 | aaaaset.push_back(DNSRecord(rr)); | |
d6fd3cb8 | 97 | s_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, boost::none, validationState); |
49a699c4 BH |
98 | } else if(rr.qtype.getCode()==QType::NS) { |
99 | rr.content=toLower(rr.content); | |
e325f20c | 100 | nsset.push_back(DNSRecord(rr)); |
49a699c4 | 101 | } |
feb47aed | 102 | insertIntoRootNSZones(rr.qname.getLastLabel()); |
49a699c4 BH |
103 | } |
104 | } | |
a7956123 | 105 | s_RC->doWipeCache(g_rootdnsname, false, QType::NS); |
d6fd3cb8 | 106 | s_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, boost::none, validationState); // and stuff in the cache |
1b4e0ae0 OM |
107 | } |
108 | ||
c16c8fe5 OM |
109 | |
110 | // Do not only put the root hints into the cache, but also make sure | |
111 | // the NS records of the top level domains of the names of the root | |
112 | // servers are in the cache. We need these to correctly determine the | |
113 | // security status of that specific domain (normally | |
114 | // root-servers.net). This is caused by the accident that the root | |
115 | // servers are authoritative for root-servers.net, and some | |
116 | // implementations reply not with a delegation on a root-servers.net | |
117 | // DS query, but with a NODATA response (the domain is unsigned). | |
1b4e0ae0 OM |
118 | void primeRootNSZones(bool dnssecmode) |
119 | { | |
120 | struct timeval now; | |
121 | gettimeofday(&now, 0); | |
122 | SyncRes sr(now); | |
123 | ||
124 | if (dnssecmode) { | |
125 | sr.setDoDNSSEC(true); | |
126 | sr.setDNSSECValidationRequested(true); | |
127 | } | |
17b71b05 OM |
128 | |
129 | // beginResolve() can yield to another mthread that could trigger t_rootNSZones updates, | |
130 | // so make a local copy | |
131 | set<DNSName> copy(t_rootNSZones); | |
132 | for (const auto & qname: copy) { | |
a7956123 | 133 | s_RC->doWipeCache(qname, false, QType::NS); |
1b4e0ae0 OM |
134 | vector<DNSRecord> ret; |
135 | sr.beginResolve(qname, QType(QType::NS), QClass::IN, ret); | |
136 | } | |
49a699c4 BH |
137 | } |
138 | ||
9065eb05 | 139 | static void makeNameToIPZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const DNSName& hostname, const string& ip) |
49a699c4 BH |
140 | { |
141 | SyncRes::AuthDomain ad; | |
687fe166 CH |
142 | ad.d_rdForward=false; |
143 | ||
e325f20c | 144 | DNSRecord dr; |
145 | dr.d_name=hostname; | |
e693ff5a | 146 | dr.d_place=DNSResourceRecord::ANSWER; |
e325f20c | 147 | dr.d_ttl=86400; |
148 | dr.d_type=QType::SOA; | |
149 | dr.d_class = 1; | |
6177a176 | 150 | dr.d_content = DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"); |
49a699c4 | 151 | |
e325f20c | 152 | ad.d_records.insert(dr); |
49a699c4 | 153 | |
e325f20c | 154 | dr.d_type=QType::NS; |
155 | dr.d_content=std::make_shared<NSRecordContent>("localhost."); | |
49a699c4 | 156 | |
e325f20c | 157 | ad.d_records.insert(dr); |
49a699c4 | 158 | |
e325f20c | 159 | dr.d_type=QType::A; |
6177a176 | 160 | dr.d_content = DNSRecordContent::mastermake(QType::A, 1, ip); |
e325f20c | 161 | ad.d_records.insert(dr); |
49a699c4 | 162 | |
e325f20c | 163 | if(newMap->count(dr.d_name)) { |
e6a9dde5 | 164 | g_log<<Logger::Warning<<"Hosts file will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl; |
49a699c4 BH |
165 | } |
166 | else { | |
e6a9dde5 | 167 | g_log<<Logger::Warning<<"Inserting forward zone '"<<dr.d_name<<"' based on hosts file"<<endl; |
3337c2f7 RG |
168 | ad.d_name=dr.d_name; |
169 | (*newMap)[ad.d_name]=ad; | |
49a699c4 BH |
170 | } |
171 | } | |
172 | ||
173 | //! parts[0] must be an IP address, the rest must be host names | |
9065eb05 | 174 | static void makeIPToNamesZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const vector<string>& parts) |
49a699c4 BH |
175 | { |
176 | string address=parts[0]; | |
177 | vector<string> ipparts; | |
178 | stringtok(ipparts, address,"."); | |
179 | ||
180 | SyncRes::AuthDomain ad; | |
687fe166 CH |
181 | ad.d_rdForward=false; |
182 | ||
e325f20c | 183 | DNSRecord dr; |
49a699c4 | 184 | for(int n=ipparts.size()-1; n>=0 ; --n) { |
e325f20c | 185 | dr.d_name.appendRawLabel(ipparts[n]); |
49a699c4 | 186 | } |
e325f20c | 187 | dr.d_name.appendRawLabel("in-addr"); |
188 | dr.d_name.appendRawLabel("arpa"); | |
189 | dr.d_class = 1; | |
e693ff5a | 190 | dr.d_place=DNSResourceRecord::ANSWER; |
e325f20c | 191 | dr.d_ttl=86400; |
192 | dr.d_type=QType::SOA; | |
6177a176 | 193 | dr.d_content=DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800"); |
49a699c4 | 194 | |
e325f20c | 195 | ad.d_records.insert(dr); |
49a699c4 | 196 | |
e325f20c | 197 | dr.d_type=QType::NS; |
198 | dr.d_content=std::make_shared<NSRecordContent>(DNSName("localhost.")); | |
49a699c4 | 199 | |
e325f20c | 200 | ad.d_records.insert(dr); |
201 | dr.d_type=QType::PTR; | |
49a699c4 BH |
202 | |
203 | if(ipparts.size()==4) // otherwise this is a partial zone | |
204 | for(unsigned int n=1; n < parts.size(); ++n) { | |
6177a176 | 205 | dr.d_content=DNSRecordContent::mastermake(QType::PTR, 1, DNSName(parts[n]).toString()); // XXX FIXME DNSNAME PAIN CAN THIS BE RIGHT? |
e325f20c | 206 | ad.d_records.insert(dr); |
49a699c4 BH |
207 | } |
208 | ||
e325f20c | 209 | if(newMap->count(dr.d_name)) { |
e6a9dde5 | 210 | g_log<<Logger::Warning<<"Will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl; |
49a699c4 BH |
211 | } |
212 | else { | |
213 | if(ipparts.size()==4) | |
e6a9dde5 | 214 | g_log<<Logger::Warning<<"Inserting reverse zone '"<<dr.d_name<<"' based on hosts file"<<endl; |
3337c2f7 RG |
215 | ad.d_name = dr.d_name; |
216 | (*newMap)[ad.d_name]=ad; | |
49a699c4 BH |
217 | } |
218 | } | |
219 | ||
220 | ||
221 | ||
222 | /* mission in life: parse three cases | |
223 | 1) 1.2.3.4 | |
224 | 2) 1.2.3.4:5300 | |
225 | 3) 2001::1 | |
226 | 4) [2002::1]:53 | |
227 | */ | |
228 | ||
229 | ComboAddress parseIPAndPort(const std::string& input, uint16_t port) | |
230 | { | |
231 | if(input.find(':') == string::npos || input.empty()) // common case | |
232 | return ComboAddress(input, port); | |
233 | ||
234 | pair<string,string> both; | |
235 | ||
236 | try { // case 2 | |
237 | both=splitField(input,':'); | |
335da0ba | 238 | uint16_t newport=static_cast<uint16_t>(pdns_stou(both.second)); |
49a699c4 BH |
239 | return ComboAddress(both.first, newport); |
240 | } | |
241 | catch(...){} | |
242 | ||
243 | if(input[0]=='[') { // case 4 | |
244 | both=splitField(input.substr(1),']'); | |
335da0ba | 245 | return ComboAddress(both.first, both.second.empty() ? port : static_cast<uint16_t>(pdns_stou(both.second.substr(1)))); |
49a699c4 BH |
246 | } |
247 | ||
248 | return ComboAddress(input, port); // case 3 | |
249 | } | |
250 | ||
251 | ||
050e6877 | 252 | static void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true) |
49a699c4 BH |
253 | { |
254 | vector<string> servers; | |
255 | stringtok(servers, input, sepa); | |
256 | ad.d_servers.clear(); | |
257 | ||
258 | for(vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) { | |
259 | if(verbose && iter != servers.begin()) | |
e6a9dde5 | 260 | g_log<<", "; |
49a699c4 BH |
261 | |
262 | ComboAddress addr=parseIPAndPort(*iter, 53); | |
263 | if(verbose) | |
e6a9dde5 | 264 | g_log<<addr.toStringWithPort(); |
49a699c4 BH |
265 | ad.d_servers.push_back(addr); |
266 | } | |
267 | if(verbose) | |
e6a9dde5 | 268 | g_log<<endl; |
49a699c4 BH |
269 | } |
270 | ||
050e6877 | 271 | static void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap) |
49a699c4 | 272 | { |
a712cb56 | 273 | SyncRes::setDomainMap(newmap); |
3427fa8a | 274 | return 0; |
49a699c4 BH |
275 | } |
276 | ||
277 | string reloadAuthAndForwards() | |
278 | { | |
a712cb56 | 279 | std::shared_ptr<SyncRes::domainmap_t> original=SyncRes::getDomainMap(); |
49a699c4 BH |
280 | |
281 | try { | |
e6a9dde5 | 282 | g_log<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl; |
a712cb56 | 283 | |
49a699c4 | 284 | string configname=::arg()["config-dir"]+"/recursor.conf"; |
3e63da83 JR |
285 | if(::arg()["config-name"]!="") { |
286 | configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf"; | |
287 | } | |
49a699c4 BH |
288 | cleanSlashes(configname); |
289 | ||
49e3ed87 PL |
290 | if(!::arg().preParseFile(configname.c_str(), "forward-zones")) |
291 | throw runtime_error("Unable to re-parse configuration file '"+configname+"'"); | |
49a699c4 | 292 | ::arg().preParseFile(configname.c_str(), "forward-zones-file"); |
4b6d1ba4 | 293 | ::arg().preParseFile(configname.c_str(), "forward-zones-recurse"); |
49a699c4 BH |
294 | ::arg().preParseFile(configname.c_str(), "auth-zones"); |
295 | ::arg().preParseFile(configname.c_str(), "export-etc-hosts", "off"); | |
296 | ::arg().preParseFile(configname.c_str(), "serve-rfc1918"); | |
302df819 AT |
297 | ::arg().preParseFile(configname.c_str(), "include-dir"); |
298 | ::arg().preParse(g_argc, g_argv, "include-dir"); | |
299 | ||
300 | // then process includes | |
301 | std::vector<std::string> extraConfigs; | |
302 | ::arg().gatherIncludes(extraConfigs); | |
303 | ||
ef7cd021 | 304 | for(const std::string& fn : extraConfigs) { |
49e3ed87 PL |
305 | if(!::arg().preParseFile(fn.c_str(), "forward-zones", ::arg()["forward-zones"])) |
306 | throw runtime_error("Unable to re-parse configuration file include '"+fn+"'"); | |
302df819 | 307 | ::arg().preParseFile(fn.c_str(), "forward-zones-file", ::arg()["forward-zones-file"]); |
4b6d1ba4 | 308 | ::arg().preParseFile(fn.c_str(), "forward-zones-recurse", ::arg()["forward-zones-recurse"]); |
302df819 AT |
309 | ::arg().preParseFile(fn.c_str(), "auth-zones",::arg()["auth-zones"]); |
310 | ::arg().preParseFile(fn.c_str(), "export-etc-hosts",::arg()["export-etc-hosts"]); | |
311 | ::arg().preParseFile(fn.c_str(), "serve-rfc1918",::arg()["serve-rfc1918"]); | |
312 | } | |
49a699c4 | 313 | |
452d5116 AT |
314 | ::arg().preParse(g_argc, g_argv, "forward-zones"); |
315 | ::arg().preParse(g_argc, g_argv, "forward-zones-file"); | |
4b6d1ba4 | 316 | ::arg().preParse(g_argc, g_argv, "forward-zones-recurse"); |
452d5116 AT |
317 | ::arg().preParse(g_argc, g_argv, "auth-zones"); |
318 | ::arg().preParse(g_argc, g_argv, "export-etc-hosts"); | |
319 | ::arg().preParse(g_argc, g_argv, "serve-rfc1918"); | |
320 | ||
9065eb05 | 321 | std::shared_ptr<SyncRes::domainmap_t> newDomainMap = parseAuthAndForwards(); |
b68af3ee | 322 | |
323 | // purge both original and new names | |
324 | std::set<DNSName> oldAndNewDomains; | |
9065eb05 | 325 | for(const auto& i : *newDomainMap) { |
b68af3ee | 326 | oldAndNewDomains.insert(i.first); |
327 | } | |
328 | ||
329 | if(original) { | |
330 | for(const auto& i : *original) { | |
331 | oldAndNewDomains.insert(i.first); | |
332 | } | |
333 | } | |
334 | ||
7af99dff | 335 | for(const auto& i : oldAndNewDomains) { |
2087df40 OM |
336 | broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, i, true, 0xffff)); |
337 | broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, i, true, 0xffff)); | |
338 | broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, i, true)); | |
49a699c4 BH |
339 | } |
340 | ||
9065eb05 | 341 | broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap)); |
49a699c4 BH |
342 | return "ok\n"; |
343 | } | |
344 | catch(std::exception& e) { | |
e6a9dde5 | 345 | g_log<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<e.what()<<endl; |
49a699c4 | 346 | } |
3f81d239 | 347 | catch(PDNSException& ae) { |
e6a9dde5 | 348 | g_log<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<ae.reason<<endl; |
49a699c4 BH |
349 | } |
350 | catch(...) { | |
e6a9dde5 | 351 | g_log<<Logger::Error<<"Encountered unknown error reloading zones, keeping original data"<<endl; |
49a699c4 BH |
352 | } |
353 | return "reloading failed, see log\n"; | |
354 | } | |
355 | ||
9065eb05 | 356 | std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards() |
49a699c4 BH |
357 | { |
358 | TXTRecordContent::report(); | |
359 | OPTRecordContent::report(); | |
360 | ||
9065eb05 | 361 | auto newMap = std::make_shared<SyncRes::domainmap_t>(); |
49a699c4 BH |
362 | |
363 | typedef vector<string> parts_t; | |
364 | parts_t parts; | |
365 | const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"}; | |
366 | for(int n=0; n < 3 ; ++n ) { | |
367 | parts.clear(); | |
39588f55 | 368 | stringtok(parts, ::arg()[option_names[n]], " ,\t\n\r"); |
49a699c4 BH |
369 | for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { |
370 | SyncRes::AuthDomain ad; | |
71925546 AT |
371 | if ((*iter).find('=') == string::npos) |
372 | throw PDNSException("Error parsing '" + *iter + "', missing ="); | |
49a699c4 BH |
373 | pair<string,string> headers=splitField(*iter, '='); |
374 | trim(headers.first); | |
375 | trim(headers.second); | |
c5c066bf | 376 | // headers.first=toCanonic("", headers.first); |
49a699c4 | 377 | if(n==0) { |
687fe166 | 378 | ad.d_rdForward = false; |
e6a9dde5 | 379 | g_log<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl; |
c5c066bf | 380 | ZoneParserTNG zpt(headers.second, DNSName(headers.first)); |
ba3d53d1 | 381 | zpt.setMaxGenerateSteps(::arg().asNum("max-generate-steps")); |
49a699c4 | 382 | DNSResourceRecord rr; |
e325f20c | 383 | DNSRecord dr; |
49a699c4 BH |
384 | while(zpt.get(rr)) { |
385 | try { | |
e325f20c | 386 | dr=DNSRecord(rr); |
e693ff5a | 387 | dr.d_place=DNSResourceRecord::ANSWER; |
49a699c4 BH |
388 | } |
389 | catch(std::exception &e) { | |
86f1af1c | 390 | throw PDNSException("Error parsing record '"+rr.qname.toLogString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"': "+e.what()); |
49a699c4 BH |
391 | } |
392 | catch(...) { | |
86f1af1c | 393 | throw PDNSException("Error parsing record '"+rr.qname.toLogString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'"); |
49a699c4 BH |
394 | } |
395 | ||
e325f20c | 396 | ad.d_records.insert(dr); |
49a699c4 BH |
397 | } |
398 | } | |
399 | else { | |
e6a9dde5 | 400 | g_log<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' "; |
49a699c4 | 401 | if(n == 2) { |
e6a9dde5 | 402 | g_log<<"with recursion "; |
687fe166 | 403 | ad.d_rdForward = true; |
49a699c4 | 404 | } |
687fe166 | 405 | else ad.d_rdForward = false; |
e6a9dde5 | 406 | g_log<<"to: "; |
49a699c4 BH |
407 | |
408 | convertServersForAD(headers.second, ad, ";"); | |
409 | if(n == 2) { | |
687fe166 | 410 | ad.d_rdForward = true; |
49a699c4 BH |
411 | } |
412 | } | |
3337c2f7 RG |
413 | |
414 | ad.d_name = DNSName(headers.first); | |
415 | (*newMap)[ad.d_name]=ad; | |
49a699c4 BH |
416 | } |
417 | } | |
418 | ||
419 | if(!::arg()["forward-zones-file"].empty()) { | |
e6a9dde5 | 420 | g_log<<Logger::Warning<<"Reading zone forwarding information from '"<<::arg()["forward-zones-file"]<<"'"<<endl; |
49a699c4 | 421 | SyncRes::AuthDomain ad; |
5e1f23ca RG |
422 | auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(::arg()["forward-zones-file"].c_str(), "r"), fclose); |
423 | if(!fp) { | |
3f81d239 | 424 | throw PDNSException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror()); |
49a699c4 BH |
425 | } |
426 | ||
834942f1 | 427 | string line; |
49a699c4 BH |
428 | int linenum=0; |
429 | uint64_t before = newMap->size(); | |
834942f1 | 430 | while(linenum++, stringfgets(fp.get(), line)) { |
fa2909dc PL |
431 | trim(line); |
432 | if (line[0] == '#') // Comment line, skip to the next line | |
433 | continue; | |
49a699c4 BH |
434 | string domain, instructions; |
435 | tie(domain, instructions)=splitField(line, '='); | |
fa2909dc | 436 | instructions = splitField(instructions, '#').first; // Remove EOL comments |
49a699c4 BH |
437 | trim(domain); |
438 | trim(instructions); | |
e58483cc BH |
439 | if(domain.empty() && instructions.empty()) { // empty line |
440 | continue; | |
441 | } | |
49a699c4 BH |
442 | if(boost::starts_with(domain,"+")) { |
443 | domain=domain.c_str()+1; | |
444 | ad.d_rdForward = true; | |
445 | } | |
446 | else | |
447 | ad.d_rdForward = false; | |
448 | if(domain.empty()) { | |
335da0ba | 449 | throw PDNSException("Error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]); |
49a699c4 BH |
450 | } |
451 | ||
452 | try { | |
453 | convertServersForAD(instructions, ad, ",; ", false); | |
454 | } | |
455 | catch(...) { | |
335da0ba | 456 | throw PDNSException("Conversion error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]); |
49a699c4 BH |
457 | } |
458 | ||
3337c2f7 RG |
459 | ad.d_name = DNSName(domain); |
460 | (*newMap)[ad.d_name]=ad; | |
49a699c4 | 461 | } |
e6a9dde5 | 462 | g_log<<Logger::Warning<<"Done parsing " << newMap->size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl; |
49a699c4 BH |
463 | } |
464 | ||
465 | if(::arg().mustDo("export-etc-hosts")) { | |
466 | string line; | |
467 | string fname=::arg()["etc-hosts-file"]; | |
468 | ||
469 | ifstream ifs(fname.c_str()); | |
470 | if(!ifs) { | |
8c0128ef | 471 | g_log<<Logger::Warning<<"Could not open "<<fname<<" for reading"<<endl; |
49a699c4 BH |
472 | } |
473 | else { | |
ac0b4eb3 | 474 | string searchSuffix = ::arg()["export-etc-hosts-search-suffix"]; |
49a699c4 BH |
475 | string::size_type pos; |
476 | while(getline(ifs,line)) { | |
232f0877 CH |
477 | pos=line.find('#'); |
478 | if(pos!=string::npos) | |
479 | line.resize(pos); | |
480 | trim(line); | |
481 | if(line.empty()) | |
482 | continue; | |
483 | parts.clear(); | |
484 | stringtok(parts, line, "\t\r\n "); | |
485 | if(parts[0].find(':')!=string::npos) | |
486 | continue; | |
487 | ||
488 | for(unsigned int n=1; n < parts.size(); ++n) { | |
489 | if(searchSuffix.empty() || parts[n].find('.') != string::npos) | |
8171ab83 | 490 | makeNameToIPZone(newMap, DNSName(parts[n]), parts[0]); |
232f0877 | 491 | else { |
8171ab83 | 492 | DNSName canonic=toCanonic(DNSName(searchSuffix), parts[n]); /// XXXX DNSName pain |
493 | if(canonic != DNSName(parts[n])) { // XXX further DNSName pain | |
232f0877 | 494 | makeNameToIPZone(newMap, canonic, parts[0]); |
ac0b4eb3 BH |
495 | } |
496 | } | |
497 | } | |
232f0877 | 498 | makeIPToNamesZone(newMap, parts); |
49a699c4 BH |
499 | } |
500 | } | |
501 | } | |
502 | if(::arg().mustDo("serve-rfc1918")) { | |
e6a9dde5 | 503 | g_log<<Logger::Warning<<"Inserting rfc 1918 private space zones"<<endl; |
49a699c4 BH |
504 | parts.clear(); |
505 | parts.push_back("127"); | |
506 | makeIPToNamesZone(newMap, parts); | |
507 | parts[0]="10"; | |
508 | makeIPToNamesZone(newMap, parts); | |
509 | ||
510 | parts[0]="192.168"; | |
511 | makeIPToNamesZone(newMap, parts); | |
512 | for(int n=16; n < 32; n++) { | |
335da0ba | 513 | parts[0]="172."+std::to_string(n); |
49a699c4 BH |
514 | makeIPToNamesZone(newMap,parts); |
515 | } | |
516 | } | |
517 | return newMap; | |
518 | } |