/*
* Copyright (c) 2016 Antonin Décimo, Jean-Raphaël Gaglione
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* For IPv4-mapped IPv6 addresses, length of the prefix that precedes
* the 4 bytes of IPv4 address at the end of the IPv6 address.
*/
#define IPV4_MAPPED_HEADING_LEN 12
/*
* Is an IPv6 address an IPv4-mapped address?
*/
static int
is_ipv4_mapped_address(const u_char *addr)
{
/* The value of the prefix */
static const u_char ipv4_mapped_heading[IPV4_MAPPED_HEADING_LEN] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
case HNCP_DELEGATED_PREFIX: {
int l;
if (bodylen < 9 || bodylen < 9 + (GET_U_1(value + 8) + 7) / 8) {
nd_print_invalid(ndo);
break;
}
ND_PRINT(" VLSO: %s PLSO: %s Prefix: ",
format_interval(GET_BE_U_4(value)),
format_interval(GET_BE_U_4(value + 4))
);
l = print_prefix(ndo, value + 8, bodylen - 8);
if (l == -1) {
ND_PRINT("(length is invalid)");
break;
}
if (l < 0) {
/*
* We've already checked that we've captured the
* entire TLV, based on its length, so this will
* either be -1, meaning "the prefix length is
* greater than the longest possible address of
* that type" (i.e., > 32 for IPv4 or > 128 for
* IPv6", or -3, meaning "the prefix runs past
* the end of the TLV".
*/
nd_print_invalid(ndo);
break;
}
l += 8 + (-l & 3);
if (bodylen >= l)
hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
}
break;
case HNCP_PREFIX_POLICY: {
uint8_t policy;
int l;
if (bodylen < 1) {
nd_print_invalid(ndo);
break;
}
policy = GET_U_1(value);
ND_PRINT(" type: ");
if (policy == 0) {
if (bodylen != 1) {
nd_print_invalid(ndo);
break;
}
ND_PRINT("Internet connectivity");
} else if (policy >= 1 && policy <= 128) {
ND_PRINT("Dest-Prefix: ");
l = print_prefix(ndo, value, bodylen);
if (l == -1) {
ND_PRINT("(length is invalid)");
break;
}
if (l < 0) {
/*
* We've already checked that we've captured the
* entire TLV, based on its length, so this will
* either be -1, meaning "the prefix length is
* greater than the longest possible address of
* that type" (i.e., > 32 for IPv4 or > 128 for
* IPv6", or -3, meaning "the prefix runs past
* the end of the TLV".
*/
nd_print_invalid(ndo);
break;
}
} else if (policy == 129) {
ND_PRINT("DNS domain: ");
print_dns_label(ndo, value+1, bodylen-1, 1);
} else if (policy == 130) {
ND_PRINT("Opaque UTF-8: ");
nd_printjnp(ndo, value + 1, bodylen - 1);
} else if (policy == 131) {
if (bodylen != 1) {
nd_print_invalid(ndo);
break;
}
ND_PRINT("Restrictive assignment");
} else if (policy >= 132) {
ND_PRINT("Unknown (%u)", policy); /* Reserved for future additions */
}
}
break;
case HNCP_DHCPV4_DATA: {
if (bodylen == 0) {
nd_print_invalid(ndo);
break;
}
if (dhcpv4_print(ndo, value, bodylen, indent+1) != 0)
goto invalid;
}
break;
case HNCP_DHCPV6_DATA: {
if (bodylen == 0) {
nd_print_invalid(ndo);
break;
}
if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0) {
nd_print_invalid(ndo);
break;
}
}
break;
case HNCP_ASSIGNED_PREFIX: {
uint8_t prty;
int l;
if (bodylen < 6 || bodylen < 6 + (GET_U_1(value + 5) + 7) / 8) {
nd_print_invalid(ndo);
break;
}
prty = GET_U_1(value + 4) & 0xf;
ND_PRINT(" EPID: %08x Prty: %u",
GET_BE_U_4(value),
prty
);
ND_PRINT(" Prefix: ");
if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0) {
nd_print_invalid(ndo);
break;
}
l += 5;
l += -l & 3;
if (bodylen >= l)
hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
}
break;
case HNCP_NODE_ADDRESS: {
uint32_t endpoint_identifier;
const char *ip_address;
if (bodylen < 20) {
nd_print_invalid(ndo);
break;
}
endpoint_identifier = GET_BE_U_4(value);
ip_address = format_ip6addr(ndo, value + 4);
ND_PRINT(" EPID: %08x IP Address: %s",
endpoint_identifier,
ip_address
);
hncp_print_rec(ndo, value + 20, bodylen - 20, indent+1);
}
break;