176 uint16_t
id = htons (packet.id);
177 data.write (
reinterpret_cast<const char*
> (&
id),
sizeof (
id));
179 uint16_t flags = htons (packet.flags);
180 data.write (
reinterpret_cast<const char*
> (&flags),
sizeof (flags));
182 uint16_t qcount = htons (
static_cast<uint16_t
> (packet.questions.size ()));
183 data.write (
reinterpret_cast<const char*
> (&qcount),
sizeof (qcount));
185 uint16_t ancount = htons (
static_cast<uint16_t
> (packet.answers.size ()));
186 data.write (
reinterpret_cast<const char*
> (&ancount),
sizeof (ancount));
188 uint16_t nscount = htons (
static_cast<uint16_t
> (packet.authorities.size ()));
189 data.write (
reinterpret_cast<const char*
> (&nscount),
sizeof (nscount));
191 uint16_t arcount = htons (
static_cast<uint16_t
> (packet.additionals.size ()));
192 data.write (
reinterpret_cast<const char*
> (&arcount),
sizeof (arcount));
194 for (
auto const& question : packet.questions)
196 if (encodeQuestion (question, data) == -1)
202 for (
auto const& answer : packet.answers)
204 if (encodeResource (answer, data) == -1)
210 for (
auto const& authority : packet.authorities)
212 if (encodeResource (authority, data) == -1)
218 for (
auto const& additional : packet.additionals)
220 if (encodeResource (additional, data) == -1)
237 data.read (
reinterpret_cast<char*
> (&packet.
id), sizeof (packet.
id));
238 packet.
id = ntohs (packet.
id);
240 data.read (
reinterpret_cast<char*
> (&packet.
flags), sizeof (packet.
flags));
244 data.read (
reinterpret_cast<char*
> (&qcount),
sizeof (qcount));
245 qcount = ntohs (qcount);
247 uint16_t ancount = 0;
248 data.read (
reinterpret_cast<char*
> (&ancount),
sizeof (ancount));
249 ancount = ntohs (ancount);
251 uint16_t nscount = 0;
252 data.read (
reinterpret_cast<char*
> (&nscount),
sizeof (nscount));
253 nscount = ntohs (nscount);
255 uint16_t arcount = 0;
256 data.read (
reinterpret_cast<char*
> (&arcount),
sizeof (arcount));
257 arcount = ntohs (arcount);
260 for (uint16_t i = 0; i < qcount; ++i)
263 if (decodeQuestion (question, data) == -1)
267 packet.
questions.emplace_back (std::move (question));
271 for (uint16_t i = 0; i < ancount; ++i)
274 if (decodeResource (answer, data) == -1)
278 packet.
answers.emplace_back (std::move (answer));
282 for (uint16_t i = 0; i < nscount; ++i)
285 if (decodeResource (authority, data) == -1)
289 packet.
authorities.emplace_back (std::move (authority));
293 for (uint16_t i = 0; i < arcount; ++i)
296 if (decodeResource (additional, data) == -1)
300 packet.
additionals.emplace_back (std::move (additional));
362 switch (recordClass & 0x7FFF)
377 int encodeName (
const std::string& name, std::stringstream& data)
const
379 std::istringstream iss (name);
381 for (std::string token; std::getline (iss, token,
'.');)
383 uint8_t len =
static_cast<uint8_t
> (token.size ());
384 data.write (
reinterpret_cast<const char*
> (&len), 1);
385 data.write (token.data (), len);
400 int decodeName (std::string& name, std::stringstream& data,
int depth = 0)
const
410 if (!data.read (
reinterpret_cast<char*
> (&first), sizeof (first)))
415 if ((first & 0xC0) == 0xC0)
418 if (!data.read (
reinterpret_cast<char*
> (&second), sizeof (second)))
423 uint16_t ptr = ((first & 0x3F) << 8) | second;
424 auto saved = data.tellg ();
427 if (decodeName (name, data, depth + 1) == -1)
437 if (!name.empty () && name.back () ==
'.')
444 name.reserve (name.size () + first + 1);
445 name.resize (name.size () + first);
446 if (!data.read (&name[name.size () - first], first))
462 int encodeMail (
const std::string& mail, std::stringstream& data)
const
464 std::string encodedMail = mail;
465 size_t atPos = encodedMail.find (
'@');
467 if (atPos != std::string::npos)
469 encodedMail.replace (atPos, 1,
".");
472 encodeName (encodedMail, data);
483 int decodeMail (std::string& mail, std::stringstream& data)
const
485 if (decodeName (mail, data) == -1)
490 auto pos = mail.find (
'.');
491 if (pos != std::string::npos)
505 int encodeQuestion (
const QuestionRecord& question, std::stringstream& data)
const
507 encodeName (question.host, data);
509 uint16_t type = htons (question.type);
510 data.write (
reinterpret_cast<const char*
> (&type),
sizeof (type));
512 uint16_t dnsclass = htons (question.dnsclass);
513 data.write (
reinterpret_cast<const char*
> (&dnsclass),
sizeof (dnsclass));
524 int decodeQuestion (QuestionRecord& question, std::stringstream& data)
const
526 if (decodeName (question.host, data) == -1)
531 data.read (
reinterpret_cast<char*
> (&question.type), sizeof (question.type));
532 question.type = ntohs (question.type);
534 data.read (
reinterpret_cast<char*
> (&question.dnsclass), sizeof (question.dnsclass));
535 question.dnsclass = ntohs (question.dnsclass);
546 int encodeResource (
const ResourceRecord& resource, std::stringstream& data)
const
548 encodeName (resource.host, data);
550 uint16_t type = htons (resource.type);
551 data.write (
reinterpret_cast<const char*
> (&type),
sizeof (type));
553 uint16_t dnsclass = htons (resource.dnsclass);
554 data.write (
reinterpret_cast<const char*
> (&dnsclass),
sizeof (dnsclass));
556 uint32_t ttl = htonl (resource.ttl);
557 data.write (
reinterpret_cast<const char*
> (&ttl),
sizeof (ttl));
559 uint16_t dataLen = 0;
560 auto dataLenPos = data.tellp ();
561 data.write (
reinterpret_cast<const char*
> (&dataLen),
sizeof (dataLen));
563 auto dataBegPos = data.tellp ();
567 data.write (
reinterpret_cast<const char*
> (resource.addr.addr ()), sizeof (in_addr));
571 data.write (
reinterpret_cast<const char*
> (resource.addr.addr ()), sizeof (in6_addr));
575 encodeName (resource.name, data);
579 encodeName (resource.name, data);
583 encodeName (resource.name, data);
587 uint16_t mxpref = htons (resource.mxpref);
588 data.write (
reinterpret_cast<const char*
> (&mxpref),
sizeof (mxpref));
589 encodeName (resource.name, data);
593 encodeName (resource.name, data);
594 encodeMail (resource.mail, data);
596 uint32_t serial = htonl (resource.serial);
597 data.write (
reinterpret_cast<const char*
> (&serial),
sizeof (serial));
599 uint32_t refresh = htonl (resource.refresh);
600 data.write (
reinterpret_cast<const char*
> (&refresh),
sizeof (refresh));
602 uint32_t retry = htonl (resource.retry);
603 data.write (
reinterpret_cast<const char*
> (&retry),
sizeof (retry));
605 uint32_t expire = htonl (resource.expire);
606 data.write (
reinterpret_cast<const char*
> (&expire),
sizeof (expire));
608 uint32_t minimum = htonl (resource.minimum);
609 data.write (
reinterpret_cast<const char*
> (&minimum),
sizeof (minimum));
613 for (
auto const& txt : resource.txts)
615 uint8_t size =
static_cast<uint8_t
> (txt.size ());
616 data.write (
reinterpret_cast<const char*
> (&size),
sizeof (size));
617 data.write (txt.data (), size);
622 uint16_t priority = htons (resource.priority);
623 data.write (
reinterpret_cast<const char*
> (&priority),
sizeof (priority));
625 uint16_t weight = htons (resource.weight);
626 data.write (
reinterpret_cast<const char*
> (&weight),
sizeof (weight));
628 uint16_t
port = htons (resource.port);
629 data.write (
reinterpret_cast<const char*
> (&port),
sizeof (port));
631 encodeName (resource.name, data);
634 auto dataEndPos = data.tellp ();
635 dataLen =
static_cast<uint16_t
> (dataEndPos - dataBegPos);
637 data.seekp (dataLenPos);
638 dataLen = htons (dataLen);
639 data.write (
reinterpret_cast<const char*
> (&dataLen),
sizeof (dataLen));
640 data.seekp (dataEndPos);
651 int decodeResource (ResourceRecord& resource, std::stringstream& data)
const
653 if (decodeName (resource.host, data) == -1)
658 data.read (
reinterpret_cast<char*
> (&resource.type), sizeof (resource.type));
659 resource.type = ntohs (resource.type);
661 data.read (
reinterpret_cast<char*
> (&resource.dnsclass), sizeof (resource.dnsclass));
662 resource.dnsclass = ntohs (resource.dnsclass);
664 data.read (
reinterpret_cast<char*
> (&resource.ttl), sizeof (resource.ttl));
665 resource.ttl = ntohl (resource.ttl);
667 uint16_t dataLen = 0;
668 data.read (
reinterpret_cast<char*
> (&dataLen),
sizeof (dataLen));
669 dataLen = ntohs (dataLen);
671 auto dataBegPos = data.tellg ();
676 data.read (
reinterpret_cast<char*
> (&addr),
sizeof (addr));
677 resource.addr = IpAddress (&addr,
sizeof (
struct in_addr));
681 struct in6_addr addr;
682 data.read (
reinterpret_cast<char*
> (&addr),
sizeof (addr));
683 resource.addr = IpAddress (&addr,
sizeof (
struct in6_addr));
687 if (decodeName (resource.name, data) == -1)
694 if (decodeName (resource.name, data) == -1)
701 if (decodeName (resource.name, data) == -1)
708 data.read (
reinterpret_cast<char*
> (&resource.mxpref), sizeof (resource.mxpref));
709 resource.mxpref = ntohs (resource.mxpref);
711 if (decodeName (resource.name, data) == -1)
718 if (decodeName (resource.name, data) == -1)
723 decodeMail (resource.mail, data);
725 data.read (
reinterpret_cast<char*
> (&resource.serial), sizeof (resource.serial));
726 resource.serial = ntohl (resource.serial);
728 data.read (
reinterpret_cast<char*
> (&resource.refresh), sizeof (resource.refresh));
729 resource.refresh = ntohl (resource.refresh);
731 data.read (
reinterpret_cast<char*
> (&resource.retry), sizeof (resource.retry));
732 resource.retry = ntohl (resource.retry);
734 data.read (
reinterpret_cast<char*
> (&resource.expire), sizeof (resource.expire));
735 resource.expire = ntohl (resource.expire);
737 data.read (
reinterpret_cast<char*
> (&resource.minimum), sizeof (resource.minimum));
738 resource.minimum = ntohl (resource.minimum);
742 while (data.tellg () != -1 && (data.tellg () - dataBegPos < dataLen))
745 if (!data.read (
reinterpret_cast<char*
> (&size), sizeof (size)))
752 if (!data.read (&txt[0], size))
757 resource.txts.emplace_back (std::move (txt));
762 data.read (
reinterpret_cast<char*
> (&resource.priority), sizeof (resource.priority));
763 resource.priority = ntohs (resource.priority);
765 data.read (
reinterpret_cast<char*
> (&resource.weight), sizeof (resource.weight));
766 resource.weight = ntohs (resource.weight);
768 data.read (
reinterpret_cast<char*
> (&resource.port), sizeof (resource.port));
769 resource.port = ntohs (resource.port);
771 if (decodeName (resource.name, data) == -1)
778 data.seekg (dataBegPos +
static_cast<std::streamoff
> (dataLen));