From aec9c9074c9485bd6ac36e258b6ea3260a9131fb Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Wed, 16 Sep 2020 10:21:24 +0200 Subject: [PATCH] newCAFromRaw(): create ComboAddress from raw 4/16 byte strings, plus test (code copied from dnsdist) --- .github/actions/spell-check/expect.txt | 1 + docs/lua-records/reference/comboaddress.rst | 8 ++++++ pdns/lua-base4.cc | 23 +++++++++++++++++ regression-tests.auth-py/test_LuaRecords.py | 28 +++++++++++++++++++++ 4 files changed, 60 insertions(+) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index e8045650af..90441a7017 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1365,6 +1365,7 @@ randomises randomloader rapidjson raspbian +rawaddress rb RBL rcode diff --git a/docs/lua-records/reference/comboaddress.rst b/docs/lua-records/reference/comboaddress.rst index 7d79eeec03..719a9f25cb 100644 --- a/docs/lua-records/reference/comboaddress.rst +++ b/docs/lua-records/reference/comboaddress.rst @@ -19,6 +19,14 @@ Functions and methods of a ``ComboAddress`` addr = newCA("1.2.3.4") +.. function:: newCAFromRaw(rawaddress[, port]) -> ComboAddress + + Returns a new :class:`ComboAddress` object based on the 4- or 16-octet string. + For example, ``newCAFromRaw('ABCD')`` makes a ``ComboAddress`` object holding the IP ``65.66.67.68``, because those are the ASCII values for those four letters. + + :param string rawaddress: The IPv4 of IPv6 address as a 4/16 octet string + :param int port: The optional port number + .. class:: ComboAddress A ``ComboAddress`` represents an IP address with possibly a port number. diff --git a/pdns/lua-base4.cc b/pdns/lua-base4.cc index e00ac5cd2f..efbf71257a 100644 --- a/pdns/lua-base4.cc +++ b/pdns/lua-base4.cc @@ -125,6 +125,29 @@ void BaseLua4::prepareContext() { } ); d_lw->writeFunction("newCA", [](const std::string& a) { return ComboAddress(a); }); + d_lw->writeFunction("newCAFromRaw", [](const std::string& raw, boost::optional port) { + if (raw.size() == 4) { + struct sockaddr_in sin4; + memset(&sin4, 0, sizeof(sin4)); + sin4.sin_family = AF_INET; + memcpy(&sin4.sin_addr.s_addr, raw.c_str(), raw.size()); + if (port) { + sin4.sin_port = htons(*port); + } + return ComboAddress(&sin4); + } + else if (raw.size() == 16) { + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr.s6_addr, raw.c_str(), raw.size()); + if (port) { + sin6.sin6_port = htons(*port); + } + return ComboAddress(&sin6); + } + return ComboAddress(); + }); typedef std::unordered_set cas_t; d_lw->registerFunction("equal", [](const ComboAddress& lhs, const ComboAddress& rhs) { return ComboAddress::addressOnlyEqual()(lhs, rhs); }); diff --git a/regression-tests.auth-py/test_LuaRecords.py b/regression-tests.auth-py/test_LuaRecords.py index 32ff9f0a32..152b5bab51 100644 --- a/regression-tests.auth-py/test_LuaRecords.py +++ b/regression-tests.auth-py/test_LuaRecords.py @@ -121,6 +121,8 @@ resolve IN LUA A ";local r=resolve('localhost', 1) local t={{}} *.createreverse IN LUA PTR "createReverse('%5%.example.com', {{['10.10.10.10'] = 'quad10.example.com.'}})" *.createreverse6 IN LUA PTR "createReverse6('%33%.example.com', {{['2001:db8::1'] = 'example.example.com.'}})" +newcafromraw IN LUA A "newCAFromRaw('ABCD'):toString()" +newcafromraw IN LUA AAAA "newCAFromRaw('ABCD020340506070'):toString()" """, 'createforward6.example.org': """ createforward6.example.org. 3600 IN SOA {soa} @@ -607,6 +609,32 @@ createforward6.example.org. 3600 IN NS ns2.example.org. self.assertRcodeEqual(res, dns.rcode.NOERROR) self.assertEqual(self.sortRRsets(res.answer), self.sortRRsets(response.answer)) + def testCAFromRaw(self): + """ + Test newCAFromRaw() function + """ + name = 'newcafromraw.example.org.' + + query = dns.message.make_query(name, 'A') + + response = dns.message.make_response(query) + + response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.A, '65.66.67.68')) + + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertEqual(res.answer, response.answer) + + query = dns.message.make_query(name, 'AAAA') + + response = dns.message.make_response(query) + + response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.AAAA, '4142:4344:3032:3033:3430:3530:3630:3730')) + + res = self.sendUDPQuery(query) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertEqual(res.answer, response.answer) + def testResolve(self): """ Test resolve() function -- 2.47.2