CVE-2016-5427 (C++, published 2016-09-21T14:25Z)
Description: value: PowerDNS (aka pdns) Authoritative Server before 3.4.10 does not properly handle a . (dot) inside labels, which allows remote attackers to cause a denial of service (backend CPU consumption) via a crafted DNS query.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-399 \u2014 Resource Management Errors
Weaknesses in this category are related to improper management of system resources.
Repository: https://github.com/PowerDNS/pdns
Files changed:
pdns/dnsparser.cc
pdns/dnsparser.hh
pdns/misc.cc
Commit message: Reject qname's wirelength > 255, `chopOff()` handle dot inside labels


Vulnerable code:
  getLabelFromContent(d_content, d_pos, ret, recurs++);
void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs) 
      return getLabelFromContent(content, offset, ret, ++recurs);

  static void getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs);
  string::size_type fdot=domain.find('.');

  if(fdot==string::npos) 
    domain="";
  else {
    string::size_type remain = domain.length() - (fdot + 1);
    char tmp[remain];
    memcpy(tmp, domain.c_str()+fdot+1, remain);
    domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
  string::size_type fdot=domain.find('.');
  if(fdot == string::npos)
    return false;

  if(fdot==domain.size()-1) 
    domain=".";
  else  {
    string::size_type remain = domain.length() - (fdot + 1);
    char tmp[remain];
    memcpy(tmp, domain.c_str()+fdot+1, remain);
    domain.assign(tmp, remain);
  return true;

Fixed code:
  size_t wirelength = 0;
  getLabelFromContent(d_content, d_pos, ret, recurs++, wirelength);
void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs, size_t& wirelength)
    wirelength++;
    if (wirelength > 255) {
      throw MOADNSException("Overly long DNS name ("+lexical_cast<string>(wirelength)+")");
    }
      /* the compression pointer does not count into the wire length */
      return getLabelFromContent(content, offset, ret, ++recurs, --wirelength);
      if (wirelength + labellen > 255) {
        throw MOADNSException("Overly long DNS name ("+lexical_cast<string>(wirelength)+")");
      }
      wirelength += labellen;
  static void getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs, size_t& wirelength);
  bool escaped = false;
  const string::size_type domainLen = domain.length();
  for (size_t fdot = 0; fdot < domainLen; fdot++)
  {
    if (domain[fdot] == '.' && !escaped) {
      string::size_type remain = domainLen - (fdot + 1);
      char tmp[remain];
      memcpy(tmp, domain.c_str()+fdot+1, remain);
      domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)

      return true;
    }
    else if (domain[fdot] == '\\' && !escaped) {
      escaped = true;
    }
    else {
      escaped = false;
    }

  domain = "";
  bool escaped = false;
  const string::size_type domainLen = domain.length();
  for (size_t fdot = 0; fdot < domainLen; fdot++)
  {
    if (domain[fdot] == '.' && !escaped) {
      if (fdot==domain.size()-1) {
        domain=".";
      }
      else {
        string::size_type remain = domainLen - (fdot + 1);
        char tmp[remain];
        memcpy(tmp, domain.c_str()+fdot+1, remain);
        domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
      }
      return true;
    }
    else if (domain[fdot] == '\\' && !escaped) {
      escaped = true;
    }
    else {
      escaped = false;
    }

  return false;