Skip to content

Commit

Permalink
Damage control in Lua createForward() and createForward6().
Browse files Browse the repository at this point in the history
- make sure all computed results are passed to a ComboAddress
  constructor, which will reject ill-formed data. This wasn't the case
  in createForward, when interpreting part of the requested name as an
  ipv4 address encoded in hexadecimal (e.g. 7f000001), but the actual
  name wasn't.
  This would otherwise end up with a SERVFAIL answer and a Lua stack
  traceback containing messages such as:
    Unable to convert presentation address '4294967292.xx.yy.zz'
  for a name ending with "-4" and six hex digits.

- wrap these functions into a try/catch block in order to cope with
  possible exceptions raised by ComboAddress.
  This wasn't the case in createForward6 when the requested name
  contains at least 8 dots - this doesn't imply each component is a
  valid ipv6 chunk.

(cherry picked from commit 9780054)
  • Loading branch information
miodvallat committed Feb 27, 2025
1 parent a702c6f commit bca8c8d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 68 deletions.
150 changes: 83 additions & 67 deletions pdns/lua-record.cc
Original file line number Diff line number Diff line change
Expand Up @@ -723,67 +723,77 @@ static void setupLuaRecords(LuaContext& lua)
});
lua.writeFunction("createForward", []() {
static string allZerosIP("0.0.0.0");
DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
// parts is something like ["1", "2", "3", "4", "static"] or
// ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
auto parts = rel.getRawLabels();
// Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
if(parts.size()>=4) {
try {
ComboAddress ca(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
return ca.toString();
} catch (const PDNSException &e) {
return allZerosIP;
try {
DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
// parts is something like ["1", "2", "3", "4", "static"] or
// ["1", "2", "3", "4"] or ["ip40414243", "ip-addresses", ...]
auto parts = rel.getRawLabels();
// Yes, this still breaks if an 1-2-3-4.XXXX is nested too deeply...
if (parts.size() >= 4) {
ComboAddress address(parts[0]+"."+parts[1]+"."+parts[2]+"."+parts[3]);
return address.toString();
}
} else if (parts.size() >= 1) {
// either hex string, or 12-13-14-15
vector<string> ip_parts;
stringtok(ip_parts, parts[0], "-");
unsigned int x1, x2, x3, x4;
if (ip_parts.size() >= 4) {
// 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
string ret;
for (size_t n=4; n > 0; n--) {
auto octet = ip_parts[ip_parts.size() - n];
try {
auto octetVal = std::stol(octet);
if (!parts.empty()) {
auto& input = parts.at(0);
// either hex string, or 12-13-14-15
vector<string> ip_parts;
stringtok(ip_parts, input, "-");
if (ip_parts.size() >= 4) {
// 1-2-3-4 with any prefix (e.g. ip-foo-bar-1-2-3-4)
string ret;
for (size_t index=4; index > 0; index--) {
auto octet = ip_parts.at(ip_parts.size() - index);
auto octetVal = std::stol(octet); // may throw
if (octetVal >= 0 && octetVal <= 255) {
ret += ip_parts.at(ip_parts.size() - n) + ".";
ret += octet + ".";
} else {
return allZerosIP;
}
} catch (const std::exception &e) {
return allZerosIP;
}
ret.resize(ret.size() - 1); // remove trailing dot after last octet
return ret;
}
if (input.length() >= 8) {
auto last8 = input.substr(input.length()-8);
unsigned int part1{0};
unsigned int part2{0};
unsigned int part3{0};
unsigned int part4{0};
if (sscanf(last8.c_str(), "%02x%02x%02x%02x", &part1, &part2, &part3, &part4) == 4) {

Check warning on line 762 in pdns/lua-record.cc

View workflow job for this annotation

GitHub Actions / build auth

do not call c-style vararg functions (cppcoreguidelines-pro-type-vararg - Level=Warning)
ComboAddress address(std::to_string(part1) + "." + std::to_string(part2) + "." + std::to_string(part3) + "." + std::to_string(part4));
return address.toString();
}
}
ret.resize(ret.size() - 1); // remove trailing dot after last octet
return ret;
} else if(parts[0].length() >= 8 && sscanf(parts[0].c_str()+(parts[0].length()-8), "%02x%02x%02x%02x", &x1, &x2, &x3, &x4)==4) {
return std::to_string(x1)+"."+std::to_string(x2)+"."+std::to_string(x3)+"."+std::to_string(x4);
}
return allZerosIP;
} catch (const PDNSException &e) {
return allZerosIP;
}
return allZerosIP;
});

lua.writeFunction("createForward6", []() {
DNSName rel=s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone);
auto parts = rel.getRawLabels();
if(parts.size()==8) {
string tot;
for(int i=0; i<8; ++i) {
if(i)
tot.append(1,':');
tot+=parts[i];
static string allZerosIP{"::"};
try {
DNSName rel{s_lua_record_ctx->qname.makeRelative(s_lua_record_ctx->zone)};

auto parts = rel.getRawLabels();
if (parts.size() == 8) {
string tot;
for (int chunk = 0; chunk < 8; ++chunk) {
if (chunk != 0) {
tot.append(1, ':');
}
tot += parts.at(chunk);
}
ComboAddress address(tot);
return address.toString();
}
ComboAddress ca(tot);
return ca.toString();
}
else if(parts.size()==1) {
if (parts[0].find('-') != std::string::npos) {
boost::replace_all(parts[0],"-",":");
ComboAddress ca(parts[0]);
return ca.toString();
} else {
if (parts.size() == 1) {
if (parts[0].find('-') != std::string::npos) {
std::replace(parts[0].begin(), parts[0].end(), '-', ':');
ComboAddress address(parts[0]);
return address.toString();
}
if (parts[0].size() >= 32) {
auto ippart = parts[0].substr(parts[0].size()-32);
auto fulladdress =
Expand All @@ -796,57 +806,63 @@ static void setupLuaRecords(LuaContext& lua)
ippart.substr(24, 4) + ":" +
ippart.substr(28, 4);

ComboAddress ca(fulladdress);
return ca.toString();
ComboAddress address(fulladdress);
return address.toString();
}
}
return allZerosIP;
} catch (const PDNSException &e) {
return allZerosIP;
}

return std::string("::");
});
lua.writeFunction("createReverse6", [](string format, boost::optional<std::unordered_map<string,string>> e){
lua.writeFunction("createReverse6", [](const string &format, boost::optional<std::unordered_map<string,string>> excp){
vector<ComboAddress> candidates;

try {
auto labels= s_lua_record_ctx->qname.getRawLabels();
if(labels.size()<32)
if (labels.size()<32) {
return std::string("unknown");
}
boost::format fmt(format);
fmt.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit ) );


string together;
vector<string> quads;
for(int i=0; i<8; ++i) {
if(i)
together+=":";
for (int chunk = 0; chunk < 8; ++chunk) {
if (chunk != 0) {
together += ":";
}
string lquad;
for(int j=0; j <4; ++j) {
lquad.append(1, labels[31-i*4-j][0]);
together += labels[31-i*4-j][0];
for (int quartet = 0; quartet < 4; ++quartet) {
lquad.append(1, labels[31 - chunk * 4 - quartet][0]);
together += labels[31 - chunk * 4 - quartet][0];
}
quads.push_back(lquad);
}
ComboAddress ip6(together,0);
ComboAddress ip6(together,0);

if(e) {
auto& addrs=*e;
if (excp) {
auto& addrs=*excp;
for(const auto& addr: addrs) {
// this makes sure we catch all forms of the address
if(ComboAddress(addr.first,0)==ip6)
if (ComboAddress(addr.first, 0) == ip6) {
return addr.second;
}
}
}

string dashed=ip6.toString();
boost::replace_all(dashed, ":", "-");

for(int i=31; i>=0; --i)
fmt % labels[i];
for (int byte = 31; byte >= 0; --byte) {
fmt % labels[byte];
}
fmt % dashed;

for(const auto& lquad : quads)
for(const auto& lquad : quads) {
fmt % lquad;
}

return fmt.str();
}
Expand Down
5 changes: 4 additions & 1 deletion regression-tests.auth-py/test_LuaRecords.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,8 @@ def testCreateForwardAndReverse(self):
"ip40414243": "64.65.66.67",
"ipp40414243": "64.65.66.67",
"ip4041424": "0.0.0.0",
"ip-441424": "0.0.0.0",
"ip-5abcdef": "0.0.0.0",
"2.2.2.2": "0.0.0.0" # filtered
}),
".createreverse.example.org." : (dns.rdatatype.PTR, {
Expand All @@ -974,7 +976,8 @@ def testCreateForwardAndReverse(self):
"2001--db8" : "2001::db8",
"20010002000300040005000600070db8" : "2001:2:3:4:5:6:7:db8",
"blabla20010002000300040005000600070db8" : "2001:2:3:4:5:6:7:db8",
"4000-db8--1" : "fe80::1" # filtered, with fallback address override
"4000-db8--1" : "fe80::1", # filtered, with fallback address override
"l1.l2.l3.l4.l5.l6.l7.l8" : "fe80::1"
}),
".createreverse6.example.org." : (dns.rdatatype.PTR, {
"8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2" : "2001--db8.example.com.",
Expand Down

0 comments on commit bca8c8d

Please sign in to comment.