mirror of
https://gitlab.isc.org/isc-projects/bind9.git
synced 2025-12-20 00:55:29 +08:00
add API to parse and extract IP from PTR name
Add an API to parse and extract either an IPv4 or IPv6 address from a name using the reverse format. It takes care of family detection, and returns a generic error in case of syntax error.
This commit is contained in:
117
lib/dns/byaddr.c
117
lib/dns/byaddr.c
@@ -15,8 +15,10 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/hex.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netaddr.h>
|
||||
#include <isc/parseint.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/util.h>
|
||||
@@ -82,3 +84,118 @@ dns_byaddr_createptrname(const isc_netaddr_t *address, dns_name_t *name) {
|
||||
isc_buffer_add(&buffer, len);
|
||||
return dns_name_fromtext(name, &buffer, dns_rootname, 0);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parseptrnamev4(const dns_name_t *name, isc_netaddr_t *addr) {
|
||||
isc_buffer_t b;
|
||||
static unsigned char inaddrarpa_data[] = "\007IN-ADDR\004ARPA";
|
||||
static dns_name_t const inaddrarpa =
|
||||
DNS_NAME_INITABSOLUTE(inaddrarpa_data);
|
||||
|
||||
if (!dns_name_issubdomain(name, &inaddrarpa)) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
*addr = (isc_netaddr_t){ .family = AF_INET };
|
||||
isc_buffer_init(&b, &addr->type.in, sizeof(addr->type.in));
|
||||
|
||||
/*
|
||||
* Parse the IP address by extracting z y x w labels in reverse
|
||||
* order to put the IP blocks in the right order.
|
||||
*/
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
dns_label_t label;
|
||||
char labelstr[4];
|
||||
uint8_t block;
|
||||
|
||||
dns_name_getlabel(name, i, &label);
|
||||
if (label.length > 4) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip the first byte of the label as it encodes the length
|
||||
* of the label (name wire format).
|
||||
*/
|
||||
strncpy(labelstr, (char *)label.base + 1, label.length);
|
||||
labelstr[label.length - 1] = 0;
|
||||
if (isc_parse_uint8(&block, labelstr, 10) != ISC_R_SUCCESS) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
isc_buffer_putuint8(&b, block);
|
||||
}
|
||||
|
||||
INSIST(isc_buffer_availablelength(&b) == 0);
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
parseptrnamev6(const dns_name_t *name, isc_netaddr_t *addr) {
|
||||
isc_buffer_t b;
|
||||
isc_hex_decodectx_t ctx;
|
||||
static unsigned char ip6arpa_data[] = "\003IP6\004ARPA";
|
||||
static dns_name_t const ip6arpa = DNS_NAME_INITABSOLUTE(ip6arpa_data);
|
||||
|
||||
if (!dns_name_issubdomain(name, &ip6arpa)) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
*addr = (isc_netaddr_t){ .family = AF_INET6 };
|
||||
isc_buffer_init(&b, &addr->type.in6, sizeof(addr->type.in6));
|
||||
isc_hex_decodeinit(&ctx, isc_buffer_length(&b), &b);
|
||||
|
||||
/*
|
||||
* Parse the IP address by extracting labels in reverse order to
|
||||
* put the IP blocks in the right order.
|
||||
*/
|
||||
for (int i = 31; i >= 0; i--) {
|
||||
dns_label_t label;
|
||||
|
||||
dns_name_getlabel(name, i, &label);
|
||||
if (label.length != 2) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* First byte is the label length
|
||||
*/
|
||||
if (isc_hex_decodechar(&ctx, label.base[1]) != ISC_R_SUCCESS) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (isc_hex_decodefinish(&ctx) != ISC_R_SUCCESS) {
|
||||
return ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
INSIST(isc_buffer_availablelength(&b) == 0);
|
||||
return ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_byaddr_parseptrname(const dns_name_t *name, isc_netaddr_t *addr) {
|
||||
int result;
|
||||
|
||||
REQUIRE(DNS_NAME_VALID(name));
|
||||
REQUIRE(addr != NULL);
|
||||
REQUIRE(dns_name_isabsolute(name));
|
||||
|
||||
switch (dns_name_countlabels(name)) {
|
||||
case 7:
|
||||
/* z.y.x.w.in-addr.arpa. has 7 labels */
|
||||
result = parseptrnamev4(name, addr);
|
||||
break;
|
||||
case 35:
|
||||
/*
|
||||
* 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.0.0.0.0.0.0.0.ip6.arpa. has 35 labels
|
||||
*/
|
||||
result = parseptrnamev6(name, addr);
|
||||
break;
|
||||
default:
|
||||
result = ISC_R_FAILURE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -52,3 +52,15 @@ dns_byaddr_createptrname(const isc_netaddr_t *address, dns_name_t *name);
|
||||
* \li 'address' is a valid address.
|
||||
* \li 'name' is a valid name with a dedicated buffer.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_byaddr_parseptrname(const dns_name_t *name, isc_netaddr_t *addr);
|
||||
/*%<
|
||||
* Parse a name in a PTR format and convert it into a isc_net_addr_t. Support
|
||||
* both IPv4 and IPv6 reverse format.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
* \li 'name' is a valid name.
|
||||
* \li 'addr' is a valid object
|
||||
*/
|
||||
|
||||
98
tests/dns/byaddr_test.c
Normal file
98
tests/dns/byaddr_test.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <sched.h> /* IWYU pragma: keep */
|
||||
#include <setjmp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <isc/lib.h>
|
||||
#include <isc/netaddr.h>
|
||||
|
||||
#include <dns/byaddr.h>
|
||||
#include <dns/name.h>
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
ISC_RUN_TEST_IMPL(byaddr_parseptrname) {
|
||||
struct {
|
||||
const char *ptrname;
|
||||
const char *address;
|
||||
} tests[] = {
|
||||
{ "1.0.168.192.in-addr.arpa.", "192.168.0.1" },
|
||||
{ "ab.0.168.192.in-addr.arpa.", NULL },
|
||||
{ "abcd.0.168.192.in-addr.arpa.", NULL },
|
||||
{ "1111.0.168.192.in-addr.arpa.", NULL },
|
||||
{ "1.0.168.192.in-addr.arp.", NULL },
|
||||
{ "4.1.999.4.in-addr.arpa.", NULL },
|
||||
{ "e.f.a.c.3.2.1.0.e.f.a.c.7.6.5.4.1.1.1.1.0.0.0.0.0.0.0."
|
||||
"0.1.2.e.f.ip6.arpa.",
|
||||
"fe21::1111:4567:cafe:123:cafe" },
|
||||
{ "e.f.a.c.3.g.1.0.e.f.a.c.7.6.5.4.1.1.1.1.0.0.0.0.0.0.0."
|
||||
"0.1.2.e.f.ip6.arpa.",
|
||||
NULL },
|
||||
{ "e.f.a.c.3.ee.1.0.e.f.a.c.7.6.5.4.1.1.1.1.0.0.0.0.0.0.0."
|
||||
"0.1.2.e.f.ip6.arpa.",
|
||||
NULL },
|
||||
{ "e.f.a.c.3.2.1.0.e.f.a.c.7.6.5.4.1.1.1.1.0.0.0.0.0.0.0."
|
||||
"0.1.2.e.f.ip6.arp.",
|
||||
NULL },
|
||||
{ "a::z.ip6.arpa.", NULL },
|
||||
{ "ed.f.a.c.3.2.1.0.e.f.a.c.7.6.5.4.1.1.1.1.0.0.0.0.0.0.0."
|
||||
"0.1.2.e.f.ip6.arpa.",
|
||||
NULL },
|
||||
{ "1.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.0.0.0.0."
|
||||
"ip6.arpa.",
|
||||
NULL },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
|
||||
int result;
|
||||
char bdata[128];
|
||||
isc_buffer_t b;
|
||||
isc_netaddr_t addr;
|
||||
dns_name_t name;
|
||||
|
||||
isc_buffer_init(&b, bdata, sizeof(bdata));
|
||||
dns_name_init(&name);
|
||||
dns_name_setbuffer(&name, &b);
|
||||
dns_name_fromstring(&name, tests[i].ptrname, NULL, 0, NULL);
|
||||
|
||||
result = dns_byaddr_parseptrname(&name, &addr);
|
||||
|
||||
if (tests[i].address) {
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
} else {
|
||||
assert_int_not_equal(result, ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
dns_name_invalidate(&name);
|
||||
isc_buffer_clear(&b);
|
||||
isc_netaddr_totext(&addr, &b);
|
||||
isc_buffer_putuint8(&b, 0);
|
||||
|
||||
if (tests[i].address) {
|
||||
result = strcmp(tests[i].address, b.base);
|
||||
assert_int_equal(result, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY(byaddr_parseptrname)
|
||||
ISC_TEST_LIST_END
|
||||
ISC_TEST_MAIN
|
||||
@@ -12,6 +12,7 @@
|
||||
dns_tests = [
|
||||
'acl',
|
||||
'badcache',
|
||||
'byaddr',
|
||||
'db',
|
||||
'dbdiff',
|
||||
'dbiterator',
|
||||
|
||||
Reference in New Issue
Block a user