]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/reczones.cc
Merge pull request #5523 from rubenk/fix-typos-in-logmessage
[thirdparty/pdns.git] / pdns / reczones.cc
1 /*
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 */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include "syncres.hh"
26 #include "arguments.hh"
27 #include "zoneparser-tng.hh"
28 #include "logger.hh"
29 #include "dnsrecords.hh"
30 #include "rec-lua-conf.hh"
31 #include <thread>
32 #include "ixfr.hh"
33 #include "rpzloader.hh"
34 #include "root-addresses.hh"
35
36 extern int g_argc;
37 extern char** g_argv;
38
39 void primeHints(void)
40 {
41 // prime root cache
42 const vState validationState = Insecure;
43 vector<DNSRecord> nsset;
44 if(!t_RC)
45 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
46
47 if(::arg()["hint-file"].empty()) {
48 DNSRecord arr, aaaarr, nsrr;
49 nsrr.d_name=g_rootdnsname;
50 arr.d_type=QType::A;
51 aaaarr.d_type=QType::AAAA;
52 nsrr.d_type=QType::NS;
53 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(0)+3600000;
54
55 for(char c='a';c<='m';++c) {
56 static char templ[40];
57 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
58 templ[sizeof(templ)-1] = '\0';
59 *templ=c;
60 aaaarr.d_name=arr.d_name=DNSName(templ);
61 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
62 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
63 vector<DNSRecord> aset;
64 aset.push_back(arr);
65 t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, nuke it all
66 if (rootIps6[c-'a'] != NULL) {
67 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
68
69 vector<DNSRecord> aaaaset;
70 aaaaset.push_back(aaaarr);
71 t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
72 }
73
74 nsset.push_back(nsrr);
75 }
76 }
77 else {
78 ZoneParserTNG zpt(::arg()["hint-file"]);
79 DNSResourceRecord rr;
80
81 while(zpt.get(rr)) {
82 rr.ttl+=time(0);
83 if(rr.qtype.getCode()==QType::A) {
84 vector<DNSRecord> aset;
85 aset.push_back(DNSRecord(rr));
86 t_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, etc see above
87 } else if(rr.qtype.getCode()==QType::AAAA) {
88 vector<DNSRecord> aaaaset;
89 aaaaset.push_back(DNSRecord(rr));
90 t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
91 } else if(rr.qtype.getCode()==QType::NS) {
92 rr.content=toLower(rr.content);
93 nsset.push_back(DNSRecord(rr));
94 }
95 }
96 }
97 t_RC->doWipeCache(g_rootdnsname, false, QType::NS);
98 t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, validationState); // and stuff in the cache
99 }
100
101 static void makeNameToIPZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const DNSName& hostname, const string& ip)
102 {
103 SyncRes::AuthDomain ad;
104 ad.d_rdForward=false;
105
106 DNSRecord dr;
107 dr.d_name=hostname;
108 dr.d_place=DNSResourceRecord::ANSWER;
109 dr.d_ttl=86400;
110 dr.d_type=QType::SOA;
111 dr.d_class = 1;
112 dr.d_content = DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800");
113
114 ad.d_records.insert(dr);
115
116 dr.d_type=QType::NS;
117 dr.d_content=std::make_shared<NSRecordContent>("localhost.");
118
119 ad.d_records.insert(dr);
120
121 dr.d_type=QType::A;
122 dr.d_content = DNSRecordContent::mastermake(QType::A, 1, ip);
123 ad.d_records.insert(dr);
124
125 if(newMap->count(dr.d_name)) {
126 L<<Logger::Warning<<"Hosts file will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl;
127 }
128 else {
129 L<<Logger::Warning<<"Inserting forward zone '"<<dr.d_name<<"' based on hosts file"<<endl;
130 ad.d_name=dr.d_name;
131 (*newMap)[ad.d_name]=ad;
132 }
133 }
134
135 //! parts[0] must be an IP address, the rest must be host names
136 static void makeIPToNamesZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const vector<string>& parts)
137 {
138 string address=parts[0];
139 vector<string> ipparts;
140 stringtok(ipparts, address,".");
141
142 SyncRes::AuthDomain ad;
143 ad.d_rdForward=false;
144
145 DNSRecord dr;
146 for(int n=ipparts.size()-1; n>=0 ; --n) {
147 dr.d_name.appendRawLabel(ipparts[n]);
148 }
149 dr.d_name.appendRawLabel("in-addr");
150 dr.d_name.appendRawLabel("arpa");
151 dr.d_class = 1;
152 dr.d_place=DNSResourceRecord::ANSWER;
153 dr.d_ttl=86400;
154 dr.d_type=QType::SOA;
155 dr.d_content=DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800");
156
157 ad.d_records.insert(dr);
158
159 dr.d_type=QType::NS;
160 dr.d_content=std::make_shared<NSRecordContent>(DNSName("localhost."));
161
162 ad.d_records.insert(dr);
163 dr.d_type=QType::PTR;
164
165 if(ipparts.size()==4) // otherwise this is a partial zone
166 for(unsigned int n=1; n < parts.size(); ++n) {
167 dr.d_content=DNSRecordContent::mastermake(QType::PTR, 1, DNSName(parts[n]).toString()); // XXX FIXME DNSNAME PAIN CAN THIS BE RIGHT?
168 ad.d_records.insert(dr);
169 }
170
171 if(newMap->count(dr.d_name)) {
172 L<<Logger::Warning<<"Will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl;
173 }
174 else {
175 if(ipparts.size()==4)
176 L<<Logger::Warning<<"Inserting reverse zone '"<<dr.d_name<<"' based on hosts file"<<endl;
177 ad.d_name = dr.d_name;
178 (*newMap)[ad.d_name]=ad;
179 }
180 }
181
182
183
184 /* mission in life: parse three cases
185 1) 1.2.3.4
186 2) 1.2.3.4:5300
187 3) 2001::1
188 4) [2002::1]:53
189 */
190
191 ComboAddress parseIPAndPort(const std::string& input, uint16_t port)
192 {
193 if(input.find(':') == string::npos || input.empty()) // common case
194 return ComboAddress(input, port);
195
196 pair<string,string> both;
197
198 try { // case 2
199 both=splitField(input,':');
200 uint16_t newport=static_cast<uint16_t>(pdns_stou(both.second));
201 return ComboAddress(both.first, newport);
202 }
203 catch(...){}
204
205 if(input[0]=='[') { // case 4
206 both=splitField(input.substr(1),']');
207 return ComboAddress(both.first, both.second.empty() ? port : static_cast<uint16_t>(pdns_stou(both.second.substr(1))));
208 }
209
210 return ComboAddress(input, port); // case 3
211 }
212
213
214 void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true)
215 {
216 vector<string> servers;
217 stringtok(servers, input, sepa);
218 ad.d_servers.clear();
219
220 for(vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) {
221 if(verbose && iter != servers.begin())
222 L<<", ";
223
224 ComboAddress addr=parseIPAndPort(*iter, 53);
225 if(verbose)
226 L<<addr.toStringWithPort();
227 ad.d_servers.push_back(addr);
228 }
229 if(verbose)
230 L<<endl;
231 }
232
233 void* pleaseWipeNegCache()
234 {
235 SyncRes::clearNegCache();
236 return 0;
237 }
238
239 void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap)
240 {
241 SyncRes::setDomainMap(newmap);
242 return 0;
243 }
244
245 string reloadAuthAndForwards()
246 {
247 std::shared_ptr<SyncRes::domainmap_t> original=SyncRes::getDomainMap();
248
249 try {
250 L<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl;
251
252 if (original) {
253 for(const auto& i : *original) {
254 for(const auto& j : i.second.d_records)
255 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, j.d_name, false));
256 }
257 }
258
259 string configname=::arg()["config-dir"]+"/recursor.conf";
260 cleanSlashes(configname);
261
262 if(!::arg().preParseFile(configname.c_str(), "forward-zones"))
263 throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
264 ::arg().preParseFile(configname.c_str(), "forward-zones-file");
265 ::arg().preParseFile(configname.c_str(), "forward-zones-recurse");
266 ::arg().preParseFile(configname.c_str(), "auth-zones");
267 ::arg().preParseFile(configname.c_str(), "export-etc-hosts", "off");
268 ::arg().preParseFile(configname.c_str(), "serve-rfc1918");
269 ::arg().preParseFile(configname.c_str(), "include-dir");
270 ::arg().preParse(g_argc, g_argv, "include-dir");
271
272 // then process includes
273 std::vector<std::string> extraConfigs;
274 ::arg().gatherIncludes(extraConfigs);
275
276 for(const std::string& fn : extraConfigs) {
277 if(!::arg().preParseFile(fn.c_str(), "forward-zones", ::arg()["forward-zones"]))
278 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
279 ::arg().preParseFile(fn.c_str(), "forward-zones-file", ::arg()["forward-zones-file"]);
280 ::arg().preParseFile(fn.c_str(), "forward-zones-recurse", ::arg()["forward-zones-recurse"]);
281 ::arg().preParseFile(fn.c_str(), "auth-zones",::arg()["auth-zones"]);
282 ::arg().preParseFile(fn.c_str(), "export-etc-hosts",::arg()["export-etc-hosts"]);
283 ::arg().preParseFile(fn.c_str(), "serve-rfc1918",::arg()["serve-rfc1918"]);
284 }
285
286 ::arg().preParse(g_argc, g_argv, "forward-zones");
287 ::arg().preParse(g_argc, g_argv, "forward-zones-file");
288 ::arg().preParse(g_argc, g_argv, "forward-zones-recurse");
289 ::arg().preParse(g_argc, g_argv, "auth-zones");
290 ::arg().preParse(g_argc, g_argv, "export-etc-hosts");
291 ::arg().preParse(g_argc, g_argv, "serve-rfc1918");
292
293 std::shared_ptr<SyncRes::domainmap_t> newDomainMap = parseAuthAndForwards();
294
295 // purge again - new zones need to blank out the cache
296 for(const auto& i : *newDomainMap) {
297 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, i.first, true));
298 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, i.first, true));
299 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, i.first, true));
300 }
301
302 broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap));
303 return "ok\n";
304 }
305 catch(std::exception& e) {
306 L<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<e.what()<<endl;
307 }
308 catch(PDNSException& ae) {
309 L<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<ae.reason<<endl;
310 }
311 catch(...) {
312 L<<Logger::Error<<"Encountered unknown error reloading zones, keeping original data"<<endl;
313 }
314 return "reloading failed, see log\n";
315 }
316
317
318 void RPZIXFRTracker(const ComboAddress& master, const DNSName& zoneName, boost::optional<DNSFilterEngine::Policy> defpol, uint32_t maxTTL, size_t zoneIdx, const TSIGTriplet& tt, shared_ptr<SOARecordContent> oursr, size_t maxReceivedBytes, const ComboAddress& localAddress)
319 {
320 uint32_t refresh = oursr->d_st.refresh;
321 for(;;) {
322 DNSRecord dr;
323 dr.d_content=oursr;
324
325 sleep(refresh);
326
327 L<<Logger::Info<<"Getting IXFR deltas for "<<zoneName<<" from "<<master.toStringWithPort()<<", our serial: "<<getRR<SOARecordContent>(dr)->d_st.serial<<endl;
328 vector<pair<vector<DNSRecord>, vector<DNSRecord> > > deltas;
329
330 ComboAddress local(localAddress);
331 if (local == ComboAddress())
332 local = getQueryLocalAddress(master.sin4.sin_family, 0);
333
334 try {
335 deltas = getIXFRDeltas(master, zoneName, dr, tt, &local, maxReceivedBytes);
336 } catch(std::runtime_error& e ){
337 L<<Logger::Warning<<e.what()<<endl;
338 continue;
339 }
340 if(deltas.empty())
341 continue;
342 L<<Logger::Info<<"Processing "<<deltas.size()<<" delta"<<addS(deltas)<<" for RPZ "<<zoneName<<endl;
343
344 auto luaconfsLocal = g_luaconfs.getLocal();
345 const std::shared_ptr<DNSFilterEngine::Zone> oldZone = luaconfsLocal->dfe.getZone(zoneIdx);
346 /* we need to make a _full copy_ of the zone we are going to work on */
347 std::shared_ptr<DNSFilterEngine::Zone> newZone = std::make_shared<DNSFilterEngine::Zone>(*oldZone);
348
349 int totremove=0, totadd=0;
350 for(const auto& delta : deltas) {
351 const auto& remove = delta.first;
352 const auto& add = delta.second;
353 if(remove.empty()) {
354 L<<Logger::Warning<<"IXFR update is a whole new zone"<<endl;
355 newZone->clear();
356 }
357 for(const auto& rr : remove) { // should always contain the SOA
358 if(rr.d_type == QType::NS)
359 continue;
360 if(rr.d_type == QType::SOA) {
361 auto oldsr = getRR<SOARecordContent>(rr);
362 if(oldsr && oldsr->d_st.serial == oursr->d_st.serial) {
363 // cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
364 }
365 else
366 L<<Logger::Error<<"GOT WRONG SOA SERIAL REMOVAL, SHOULD TRIGGER WHOLE RELOAD"<<endl;
367 }
368 else {
369 totremove++;
370 L<<Logger::Debug<<"Had removal of "<<rr.d_name<<endl;
371 RPZRecordToPolicy(rr, newZone, false, defpol, maxTTL);
372 }
373 }
374
375 for(const auto& rr : add) { // should always contain the new SOA
376 if(rr.d_type == QType::NS)
377 continue;
378 if(rr.d_type == QType::SOA) {
379 auto newsr = getRR<SOARecordContent>(rr);
380 // L<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<newsr->d_st.serial<<endl;
381 if (newsr) {
382 oursr = newsr;
383 }
384 }
385 else {
386 totadd++;
387 L<<Logger::Debug<<"Had addition of "<<rr.d_name<<endl;
388 RPZRecordToPolicy(rr, newZone, true, defpol, maxTTL);
389 }
390 }
391 }
392 L<<Logger::Info<<"Had "<<totremove<<" RPZ removal"<<addS(totremove)<<", "<<totadd<<" addition"<<addS(totadd)<<" for "<<zoneName<<" New serial: "<<oursr->d_st.serial<<endl;
393
394 /* we need to replace the existing zone with the new one,
395 but we don't want to touch anything else, especially other zones,
396 since they might have been updated by another RPZ IXFR tracker thread.
397 */
398 g_luaconfs.modify([zoneIdx, &newZone](LuaConfigItems& lci) {
399 lci.dfe.setZone(zoneIdx, newZone);
400 });
401 }
402 }
403
404 std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards()
405 {
406 TXTRecordContent::report();
407 OPTRecordContent::report();
408
409 auto newMap = std::make_shared<SyncRes::domainmap_t>();
410
411 typedef vector<string> parts_t;
412 parts_t parts;
413 const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"};
414 for(int n=0; n < 3 ; ++n ) {
415 parts.clear();
416 stringtok(parts, ::arg()[option_names[n]], " ,\t\n\r");
417 for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) {
418 SyncRes::AuthDomain ad;
419 if ((*iter).find('=') == string::npos)
420 throw PDNSException("Error parsing '" + *iter + "', missing =");
421 pair<string,string> headers=splitField(*iter, '=');
422 trim(headers.first);
423 trim(headers.second);
424 // headers.first=toCanonic("", headers.first);
425 if(n==0) {
426 ad.d_rdForward = false;
427 L<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl;
428 ZoneParserTNG zpt(headers.second, DNSName(headers.first));
429 DNSResourceRecord rr;
430 DNSRecord dr;
431 while(zpt.get(rr)) {
432 try {
433 dr=DNSRecord(rr);
434 dr.d_place=DNSResourceRecord::ANSWER;
435 }
436 catch(std::exception &e) {
437 throw PDNSException("Error parsing record '"+rr.qname.toString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"': "+e.what());
438 }
439 catch(...) {
440 throw PDNSException("Error parsing record '"+rr.qname.toString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'");
441 }
442
443 ad.d_records.insert(dr);
444 }
445 }
446 else {
447 L<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' ";
448 if(n == 2) {
449 L<<"with recursion ";
450 ad.d_rdForward = true;
451 }
452 else ad.d_rdForward = false;
453 L<<"to: ";
454
455 convertServersForAD(headers.second, ad, ";");
456 if(n == 2) {
457 ad.d_rdForward = true;
458 }
459 }
460
461 ad.d_name = DNSName(headers.first);
462 (*newMap)[ad.d_name]=ad;
463 }
464 }
465
466 if(!::arg()["forward-zones-file"].empty()) {
467 L<<Logger::Warning<<"Reading zone forwarding information from '"<<::arg()["forward-zones-file"]<<"'"<<endl;
468 SyncRes::AuthDomain ad;
469 FILE *rfp=fopen(::arg()["forward-zones-file"].c_str(), "r");
470
471 if(!rfp) {
472 throw PDNSException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror());
473 }
474
475 shared_ptr<FILE> fp=shared_ptr<FILE>(rfp, fclose);
476
477 string line;
478 int linenum=0;
479 uint64_t before = newMap->size();
480 while(linenum++, stringfgets(fp.get(), line)) {
481 trim(line);
482 if (line[0] == '#') // Comment line, skip to the next line
483 continue;
484 string domain, instructions;
485 tie(domain, instructions)=splitField(line, '=');
486 instructions = splitField(instructions, '#').first; // Remove EOL comments
487 trim(domain);
488 trim(instructions);
489 if(domain.empty() && instructions.empty()) { // empty line
490 continue;
491 }
492 if(boost::starts_with(domain,"+")) {
493 domain=domain.c_str()+1;
494 ad.d_rdForward = true;
495 }
496 else
497 ad.d_rdForward = false;
498 if(domain.empty()) {
499 throw PDNSException("Error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
500 }
501
502 try {
503 convertServersForAD(instructions, ad, ",; ", false);
504 }
505 catch(...) {
506 throw PDNSException("Conversion error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
507 }
508
509 ad.d_name = DNSName(domain);
510 (*newMap)[ad.d_name]=ad;
511 }
512 L<<Logger::Warning<<"Done parsing " << newMap->size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl;
513 }
514
515 if(::arg().mustDo("export-etc-hosts")) {
516 string line;
517 string fname=::arg()["etc-hosts-file"];
518
519 ifstream ifs(fname.c_str());
520 if(!ifs) {
521 L<<Logger::Warning<<"Could not open /etc/hosts for reading"<<endl;
522 }
523 else {
524 string searchSuffix = ::arg()["export-etc-hosts-search-suffix"];
525 string::size_type pos;
526 while(getline(ifs,line)) {
527 pos=line.find('#');
528 if(pos!=string::npos)
529 line.resize(pos);
530 trim(line);
531 if(line.empty())
532 continue;
533 parts.clear();
534 stringtok(parts, line, "\t\r\n ");
535 if(parts[0].find(':')!=string::npos)
536 continue;
537
538 for(unsigned int n=1; n < parts.size(); ++n) {
539 if(searchSuffix.empty() || parts[n].find('.') != string::npos)
540 makeNameToIPZone(newMap, DNSName(parts[n]), parts[0]);
541 else {
542 DNSName canonic=toCanonic(DNSName(searchSuffix), parts[n]); /// XXXX DNSName pain
543 if(canonic != DNSName(parts[n])) { // XXX further DNSName pain
544 makeNameToIPZone(newMap, canonic, parts[0]);
545 }
546 }
547 }
548 makeIPToNamesZone(newMap, parts);
549 }
550 }
551 }
552 if(::arg().mustDo("serve-rfc1918")) {
553 L<<Logger::Warning<<"Inserting rfc 1918 private space zones"<<endl;
554 parts.clear();
555 parts.push_back("127");
556 makeIPToNamesZone(newMap, parts);
557 parts[0]="10";
558 makeIPToNamesZone(newMap, parts);
559
560 parts[0]="192.168";
561 makeIPToNamesZone(newMap, parts);
562 for(int n=16; n < 32; n++) {
563 parts[0]="172."+std::to_string(n);
564 makeIPToNamesZone(newMap,parts);
565 }
566 }
567 return newMap;
568 }
569