]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/reczones.cc
limit compression pointers to 14 bits
[thirdparty/pdns.git] / pdns / reczones.cc
CommitLineData
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
32extern int g_argc;
33extern char** g_argv;
49a699c4
BH
34
35void primeHints(void)
36{
37 // prime root cache
fb17a52f 38 const vState validationState = Insecure;
e325f20c 39 vector<DNSRecord> nsset;
49a699c4 40 if(!t_RC)
f26bf547 41 t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
49a699c4
BH
42
43 if(::arg()["hint-file"].empty()) {
e325f20c 44 DNSRecord arr, aaaarr, nsrr;
12c06211 45 nsrr.d_name=g_rootdnsname;
e325f20c 46 arr.d_type=QType::A;
47 aaaarr.d_type=QType::AAAA;
48 nsrr.d_type=QType::NS;
49 arr.d_ttl=aaaarr.d_ttl=nsrr.d_ttl=time(0)+3600000;
49a699c4
BH
50
51 for(char c='a';c<='m';++c) {
e863a05a 52 char templ[40];
49a699c4 53 strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1);
a683e8bd 54 templ[sizeof(templ)-1] = '\0';
49a699c4 55 *templ=c;
e325f20c 56 aaaarr.d_name=arr.d_name=DNSName(templ);
57 nsrr.d_content=std::make_shared<NSRecordContent>(DNSName(templ));
10c96475 58 arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
e325f20c 59 vector<DNSRecord> aset;
60 aset.push_back(arr);
2b984251 61 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
10c96475
PL
62 if (rootIps6[c-'a'] != NULL) {
63 aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
49a699c4 64
e325f20c 65 vector<DNSRecord> aaaaset;
66 aaaaset.push_back(aaaarr);
2b984251 67 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);
49a699c4
BH
68 }
69
e325f20c 70 nsset.push_back(nsrr);
49a699c4
BH
71 }
72 }
73 else {
74 ZoneParserTNG zpt(::arg()["hint-file"]);
75 DNSResourceRecord rr;
76
77 while(zpt.get(rr)) {
78 rr.ttl+=time(0);
79 if(rr.qtype.getCode()==QType::A) {
e325f20c 80 vector<DNSRecord> aset;
81 aset.push_back(DNSRecord(rr));
2b984251 82 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
49a699c4 83 } else if(rr.qtype.getCode()==QType::AAAA) {
e325f20c 84 vector<DNSRecord> aaaaset;
85 aaaaset.push_back(DNSRecord(rr));
2b984251 86 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);
49a699c4
BH
87 } else if(rr.qtype.getCode()==QType::NS) {
88 rr.content=toLower(rr.content);
e325f20c 89 nsset.push_back(DNSRecord(rr));
49a699c4
BH
90 }
91 }
92 }
0d032a66 93 t_RC->doWipeCache(g_rootdnsname, false, QType::NS);
2b984251 94 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
49a699c4
BH
95}
96
9065eb05 97static void makeNameToIPZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const DNSName& hostname, const string& ip)
49a699c4
BH
98{
99 SyncRes::AuthDomain ad;
687fe166
CH
100 ad.d_rdForward=false;
101
e325f20c 102 DNSRecord dr;
103 dr.d_name=hostname;
e693ff5a 104 dr.d_place=DNSResourceRecord::ANSWER;
e325f20c 105 dr.d_ttl=86400;
106 dr.d_type=QType::SOA;
107 dr.d_class = 1;
6177a176 108 dr.d_content = DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800");
49a699c4 109
e325f20c 110 ad.d_records.insert(dr);
49a699c4 111
e325f20c 112 dr.d_type=QType::NS;
113 dr.d_content=std::make_shared<NSRecordContent>("localhost.");
49a699c4 114
e325f20c 115 ad.d_records.insert(dr);
49a699c4 116
e325f20c 117 dr.d_type=QType::A;
6177a176 118 dr.d_content = DNSRecordContent::mastermake(QType::A, 1, ip);
e325f20c 119 ad.d_records.insert(dr);
49a699c4 120
e325f20c 121 if(newMap->count(dr.d_name)) {
e6a9dde5 122 g_log<<Logger::Warning<<"Hosts file will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl;
49a699c4
BH
123 }
124 else {
e6a9dde5 125 g_log<<Logger::Warning<<"Inserting forward zone '"<<dr.d_name<<"' based on hosts file"<<endl;
3337c2f7
RG
126 ad.d_name=dr.d_name;
127 (*newMap)[ad.d_name]=ad;
49a699c4
BH
128 }
129}
130
131//! parts[0] must be an IP address, the rest must be host names
9065eb05 132static void makeIPToNamesZone(std::shared_ptr<SyncRes::domainmap_t> newMap, const vector<string>& parts)
49a699c4
BH
133{
134 string address=parts[0];
135 vector<string> ipparts;
136 stringtok(ipparts, address,".");
137
138 SyncRes::AuthDomain ad;
687fe166
CH
139 ad.d_rdForward=false;
140
e325f20c 141 DNSRecord dr;
49a699c4 142 for(int n=ipparts.size()-1; n>=0 ; --n) {
e325f20c 143 dr.d_name.appendRawLabel(ipparts[n]);
49a699c4 144 }
e325f20c 145 dr.d_name.appendRawLabel("in-addr");
146 dr.d_name.appendRawLabel("arpa");
147 dr.d_class = 1;
e693ff5a 148 dr.d_place=DNSResourceRecord::ANSWER;
e325f20c 149 dr.d_ttl=86400;
150 dr.d_type=QType::SOA;
6177a176 151 dr.d_content=DNSRecordContent::mastermake(QType::SOA, 1, "localhost. root 1 604800 86400 2419200 604800");
49a699c4 152
e325f20c 153 ad.d_records.insert(dr);
49a699c4 154
e325f20c 155 dr.d_type=QType::NS;
156 dr.d_content=std::make_shared<NSRecordContent>(DNSName("localhost."));
49a699c4 157
e325f20c 158 ad.d_records.insert(dr);
159 dr.d_type=QType::PTR;
49a699c4
BH
160
161 if(ipparts.size()==4) // otherwise this is a partial zone
162 for(unsigned int n=1; n < parts.size(); ++n) {
6177a176 163 dr.d_content=DNSRecordContent::mastermake(QType::PTR, 1, DNSName(parts[n]).toString()); // XXX FIXME DNSNAME PAIN CAN THIS BE RIGHT?
e325f20c 164 ad.d_records.insert(dr);
49a699c4
BH
165 }
166
e325f20c 167 if(newMap->count(dr.d_name)) {
e6a9dde5 168 g_log<<Logger::Warning<<"Will not overwrite zone '"<<dr.d_name<<"' already loaded"<<endl;
49a699c4
BH
169 }
170 else {
171 if(ipparts.size()==4)
e6a9dde5 172 g_log<<Logger::Warning<<"Inserting reverse zone '"<<dr.d_name<<"' based on hosts file"<<endl;
3337c2f7
RG
173 ad.d_name = dr.d_name;
174 (*newMap)[ad.d_name]=ad;
49a699c4
BH
175 }
176}
177
178
179
180/* mission in life: parse three cases
181 1) 1.2.3.4
182 2) 1.2.3.4:5300
183 3) 2001::1
184 4) [2002::1]:53
185*/
186
187ComboAddress parseIPAndPort(const std::string& input, uint16_t port)
188{
189 if(input.find(':') == string::npos || input.empty()) // common case
190 return ComboAddress(input, port);
191
192 pair<string,string> both;
193
194 try { // case 2
195 both=splitField(input,':');
335da0ba 196 uint16_t newport=static_cast<uint16_t>(pdns_stou(both.second));
49a699c4
BH
197 return ComboAddress(both.first, newport);
198 }
199 catch(...){}
200
201 if(input[0]=='[') { // case 4
202 both=splitField(input.substr(1),']');
335da0ba 203 return ComboAddress(both.first, both.second.empty() ? port : static_cast<uint16_t>(pdns_stou(both.second.substr(1))));
49a699c4
BH
204 }
205
206 return ComboAddress(input, port); // case 3
207}
208
209
210void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true)
211{
212 vector<string> servers;
213 stringtok(servers, input, sepa);
214 ad.d_servers.clear();
215
216 for(vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) {
217 if(verbose && iter != servers.begin())
e6a9dde5 218 g_log<<", ";
49a699c4
BH
219
220 ComboAddress addr=parseIPAndPort(*iter, 53);
221 if(verbose)
e6a9dde5 222 g_log<<addr.toStringWithPort();
49a699c4
BH
223 ad.d_servers.push_back(addr);
224 }
225 if(verbose)
e6a9dde5 226 g_log<<endl;
49a699c4
BH
227}
228
3427fa8a 229void* pleaseWipeNegCache()
49a699c4 230{
a712cb56 231 SyncRes::clearNegCache();
3427fa8a 232 return 0;
49a699c4
BH
233}
234
9065eb05 235void* pleaseUseNewSDomainsMap(std::shared_ptr<SyncRes::domainmap_t> newmap)
49a699c4 236{
a712cb56 237 SyncRes::setDomainMap(newmap);
3427fa8a 238 return 0;
49a699c4
BH
239}
240
241string reloadAuthAndForwards()
242{
a712cb56 243 std::shared_ptr<SyncRes::domainmap_t> original=SyncRes::getDomainMap();
49a699c4
BH
244
245 try {
e6a9dde5 246 g_log<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl;
a712cb56 247
49a699c4 248 string configname=::arg()["config-dir"]+"/recursor.conf";
3e63da83
JR
249 if(::arg()["config-name"]!="") {
250 configname=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
251 }
49a699c4
BH
252 cleanSlashes(configname);
253
49e3ed87
PL
254 if(!::arg().preParseFile(configname.c_str(), "forward-zones"))
255 throw runtime_error("Unable to re-parse configuration file '"+configname+"'");
49a699c4 256 ::arg().preParseFile(configname.c_str(), "forward-zones-file");
4b6d1ba4 257 ::arg().preParseFile(configname.c_str(), "forward-zones-recurse");
49a699c4
BH
258 ::arg().preParseFile(configname.c_str(), "auth-zones");
259 ::arg().preParseFile(configname.c_str(), "export-etc-hosts", "off");
260 ::arg().preParseFile(configname.c_str(), "serve-rfc1918");
302df819
AT
261 ::arg().preParseFile(configname.c_str(), "include-dir");
262 ::arg().preParse(g_argc, g_argv, "include-dir");
263
264 // then process includes
265 std::vector<std::string> extraConfigs;
266 ::arg().gatherIncludes(extraConfigs);
267
ef7cd021 268 for(const std::string& fn : extraConfigs) {
49e3ed87
PL
269 if(!::arg().preParseFile(fn.c_str(), "forward-zones", ::arg()["forward-zones"]))
270 throw runtime_error("Unable to re-parse configuration file include '"+fn+"'");
302df819 271 ::arg().preParseFile(fn.c_str(), "forward-zones-file", ::arg()["forward-zones-file"]);
4b6d1ba4 272 ::arg().preParseFile(fn.c_str(), "forward-zones-recurse", ::arg()["forward-zones-recurse"]);
302df819
AT
273 ::arg().preParseFile(fn.c_str(), "auth-zones",::arg()["auth-zones"]);
274 ::arg().preParseFile(fn.c_str(), "export-etc-hosts",::arg()["export-etc-hosts"]);
275 ::arg().preParseFile(fn.c_str(), "serve-rfc1918",::arg()["serve-rfc1918"]);
276 }
49a699c4 277
452d5116
AT
278 ::arg().preParse(g_argc, g_argv, "forward-zones");
279 ::arg().preParse(g_argc, g_argv, "forward-zones-file");
4b6d1ba4 280 ::arg().preParse(g_argc, g_argv, "forward-zones-recurse");
452d5116
AT
281 ::arg().preParse(g_argc, g_argv, "auth-zones");
282 ::arg().preParse(g_argc, g_argv, "export-etc-hosts");
283 ::arg().preParse(g_argc, g_argv, "serve-rfc1918");
284
9065eb05 285 std::shared_ptr<SyncRes::domainmap_t> newDomainMap = parseAuthAndForwards();
b68af3ee 286
287 // purge both original and new names
288 std::set<DNSName> oldAndNewDomains;
9065eb05 289 for(const auto& i : *newDomainMap) {
b68af3ee 290 oldAndNewDomains.insert(i.first);
291 }
292
293 if(original) {
294 for(const auto& i : *original) {
295 oldAndNewDomains.insert(i.first);
296 }
297 }
298
299 for(const auto i : oldAndNewDomains) {
300 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeCache, i, true));
301 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipePacketCache, i, true));
302 broadcastAccFunction<uint64_t>(boost::bind(pleaseWipeAndCountNegCache, i, true));
49a699c4
BH
303 }
304
9065eb05 305 broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap));
49a699c4
BH
306 return "ok\n";
307 }
308 catch(std::exception& e) {
e6a9dde5 309 g_log<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<e.what()<<endl;
49a699c4 310 }
3f81d239 311 catch(PDNSException& ae) {
e6a9dde5 312 g_log<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<ae.reason<<endl;
49a699c4
BH
313 }
314 catch(...) {
e6a9dde5 315 g_log<<Logger::Error<<"Encountered unknown error reloading zones, keeping original data"<<endl;
49a699c4
BH
316 }
317 return "reloading failed, see log\n";
318}
319
9065eb05 320std::shared_ptr<SyncRes::domainmap_t> parseAuthAndForwards()
49a699c4
BH
321{
322 TXTRecordContent::report();
323 OPTRecordContent::report();
324
9065eb05 325 auto newMap = std::make_shared<SyncRes::domainmap_t>();
49a699c4
BH
326
327 typedef vector<string> parts_t;
328 parts_t parts;
329 const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"};
330 for(int n=0; n < 3 ; ++n ) {
331 parts.clear();
39588f55 332 stringtok(parts, ::arg()[option_names[n]], " ,\t\n\r");
49a699c4
BH
333 for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) {
334 SyncRes::AuthDomain ad;
71925546
AT
335 if ((*iter).find('=') == string::npos)
336 throw PDNSException("Error parsing '" + *iter + "', missing =");
49a699c4
BH
337 pair<string,string> headers=splitField(*iter, '=');
338 trim(headers.first);
339 trim(headers.second);
c5c066bf 340 // headers.first=toCanonic("", headers.first);
49a699c4 341 if(n==0) {
687fe166 342 ad.d_rdForward = false;
e6a9dde5 343 g_log<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl;
c5c066bf 344 ZoneParserTNG zpt(headers.second, DNSName(headers.first));
49a699c4 345 DNSResourceRecord rr;
e325f20c 346 DNSRecord dr;
49a699c4
BH
347 while(zpt.get(rr)) {
348 try {
e325f20c 349 dr=DNSRecord(rr);
e693ff5a 350 dr.d_place=DNSResourceRecord::ANSWER;
49a699c4
BH
351 }
352 catch(std::exception &e) {
86f1af1c 353 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
354 }
355 catch(...) {
86f1af1c 356 throw PDNSException("Error parsing record '"+rr.qname.toLogString()+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'");
49a699c4
BH
357 }
358
e325f20c 359 ad.d_records.insert(dr);
49a699c4
BH
360 }
361 }
362 else {
e6a9dde5 363 g_log<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' ";
49a699c4 364 if(n == 2) {
e6a9dde5 365 g_log<<"with recursion ";
687fe166 366 ad.d_rdForward = true;
49a699c4 367 }
687fe166 368 else ad.d_rdForward = false;
e6a9dde5 369 g_log<<"to: ";
49a699c4
BH
370
371 convertServersForAD(headers.second, ad, ";");
372 if(n == 2) {
687fe166 373 ad.d_rdForward = true;
49a699c4
BH
374 }
375 }
3337c2f7
RG
376
377 ad.d_name = DNSName(headers.first);
378 (*newMap)[ad.d_name]=ad;
49a699c4
BH
379 }
380 }
381
382 if(!::arg()["forward-zones-file"].empty()) {
e6a9dde5 383 g_log<<Logger::Warning<<"Reading zone forwarding information from '"<<::arg()["forward-zones-file"]<<"'"<<endl;
49a699c4 384 SyncRes::AuthDomain ad;
5e1f23ca
RG
385 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fopen(::arg()["forward-zones-file"].c_str(), "r"), fclose);
386 if(!fp) {
3f81d239 387 throw PDNSException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror());
49a699c4
BH
388 }
389
834942f1 390 string line;
49a699c4
BH
391 int linenum=0;
392 uint64_t before = newMap->size();
834942f1 393 while(linenum++, stringfgets(fp.get(), line)) {
fa2909dc
PL
394 trim(line);
395 if (line[0] == '#') // Comment line, skip to the next line
396 continue;
49a699c4
BH
397 string domain, instructions;
398 tie(domain, instructions)=splitField(line, '=');
fa2909dc 399 instructions = splitField(instructions, '#').first; // Remove EOL comments
49a699c4
BH
400 trim(domain);
401 trim(instructions);
e58483cc
BH
402 if(domain.empty() && instructions.empty()) { // empty line
403 continue;
404 }
49a699c4
BH
405 if(boost::starts_with(domain,"+")) {
406 domain=domain.c_str()+1;
407 ad.d_rdForward = true;
408 }
409 else
410 ad.d_rdForward = false;
411 if(domain.empty()) {
335da0ba 412 throw PDNSException("Error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
49a699c4
BH
413 }
414
415 try {
416 convertServersForAD(instructions, ad, ",; ", false);
417 }
418 catch(...) {
335da0ba 419 throw PDNSException("Conversion error parsing line "+std::to_string(linenum)+" of " +::arg()["forward-zones-file"]);
49a699c4
BH
420 }
421
3337c2f7
RG
422 ad.d_name = DNSName(domain);
423 (*newMap)[ad.d_name]=ad;
49a699c4 424 }
e6a9dde5 425 g_log<<Logger::Warning<<"Done parsing " << newMap->size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl;
49a699c4
BH
426 }
427
428 if(::arg().mustDo("export-etc-hosts")) {
429 string line;
430 string fname=::arg()["etc-hosts-file"];
431
432 ifstream ifs(fname.c_str());
433 if(!ifs) {
8c0128ef 434 g_log<<Logger::Warning<<"Could not open "<<fname<<" for reading"<<endl;
49a699c4
BH
435 }
436 else {
ac0b4eb3 437 string searchSuffix = ::arg()["export-etc-hosts-search-suffix"];
49a699c4
BH
438 string::size_type pos;
439 while(getline(ifs,line)) {
232f0877
CH
440 pos=line.find('#');
441 if(pos!=string::npos)
442 line.resize(pos);
443 trim(line);
444 if(line.empty())
445 continue;
446 parts.clear();
447 stringtok(parts, line, "\t\r\n ");
448 if(parts[0].find(':')!=string::npos)
449 continue;
450
451 for(unsigned int n=1; n < parts.size(); ++n) {
452 if(searchSuffix.empty() || parts[n].find('.') != string::npos)
8171ab83 453 makeNameToIPZone(newMap, DNSName(parts[n]), parts[0]);
232f0877 454 else {
8171ab83 455 DNSName canonic=toCanonic(DNSName(searchSuffix), parts[n]); /// XXXX DNSName pain
456 if(canonic != DNSName(parts[n])) { // XXX further DNSName pain
232f0877 457 makeNameToIPZone(newMap, canonic, parts[0]);
ac0b4eb3
BH
458 }
459 }
460 }
232f0877 461 makeIPToNamesZone(newMap, parts);
49a699c4
BH
462 }
463 }
464 }
465 if(::arg().mustDo("serve-rfc1918")) {
e6a9dde5 466 g_log<<Logger::Warning<<"Inserting rfc 1918 private space zones"<<endl;
49a699c4
BH
467 parts.clear();
468 parts.push_back("127");
469 makeIPToNamesZone(newMap, parts);
470 parts[0]="10";
471 makeIPToNamesZone(newMap, parts);
472
473 parts[0]="192.168";
474 makeIPToNamesZone(newMap, parts);
475 for(int n=16; n < 32; n++) {
335da0ba 476 parts[0]="172."+std::to_string(n);
49a699c4
BH
477 makeIPToNamesZone(newMap,parts);
478 }
479 }
480 return newMap;
481}
482