Commit message: CVE-2017-13044/HNCP: add DHCPv4-Data bounds checks

dhcpv4_print() in print-hncp.c had the same bug as dhcpv6_print(), apply
a fix along the same lines.

This fixes a buffer over-read discovered by Bhargava Shastry,
SecT/TU Berlin.

Add a test using the capture file supplied by the reporter(s).
CVE: CVE-2017-13044
CWE: CWE-125
Vulnerability description: The HNCP parser in tcpdump before 4.9.2 has a buffer over-read in print-hncp.c:dhcpv4_print().

Project: tcpdump
File: print-hncp.c

format_256(const u_char *data)
{
    static char buf[4][sizeof("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")];
    static int i = 0;
    i = (i + 1) % 4;
    snprintf(buf[i], sizeof(buf[i]), "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64,
         EXTRACT_64BITS(data),
         EXTRACT_64BITS(data + 8),
         EXTRACT_64BITS(data + 16),
         EXTRACT_64BITS(data + 24)
    );
    return buf[i];
}

Project: tcpdump
File: print-hncp.c

format_interval(const uint32_t n)
{
    static char buf[4][sizeof("0000000.000s")];
    static int i = 0;
    i = (i + 1) % 4;
    snprintf(buf[i], sizeof(buf[i]), "%u.%03us", n / 1000, n % 1000);
    return buf[i];
}

Project: tcpdump
File: print-hncp.c

format_ip6addr(netdissect_options *ndo, const u_char *cp)
{
    if (is_ipv4_mapped_address(cp))
        return ipaddr_string(ndo, cp + IPV4_MAPPED_HEADING_LEN);
    else
        return ip6addr_string(ndo, cp);
}

Project: tcpdump
File: print-hncp.c

format_nid(const u_char *data)
{
    static char buf[4][sizeof("01:01:01:01")];
    static int i = 0;
    i = (i + 1) % 4;
    snprintf(buf[i], sizeof(buf[i]), "%02x:%02x:%02x:%02x",
             data[0], data[1], data[2], data[3]);
    return buf[i];
}

Project: tcpdump
File: print-hncp.c

hncp_print(netdissect_options *ndo,
           const u_char *cp, u_int length)
{
    ND_PRINT((ndo, "hncp (%d)", length));
    hncp_print_rec(ndo, cp, length, 1);
}

Project: tcpdump
File: print-hncp.c

is_in_line(netdissect_options *ndo, int indent)
{
    return indent - 1 >= ndo->ndo_vflag && ndo->ndo_vflag < 3;
}

Project: tcpdump
File: print-hncp.c

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 };

    return memcmp(addr, ipv4_mapped_heading, IPV4_MAPPED_HEADING_LEN) == 0;
}

Project: tcpdump
File: print-hncp.c

print_dns_label(netdissect_options *ndo,
                const u_char *cp, u_int max_length, int print)
{
    u_int length = 0;
    while (length < max_length) {
        u_int lab_length = cp[length++];
        if (lab_length == 0)
            return (int)length;
        if (length > 1 && print)
            safeputchar(ndo, '.');
        if (length+lab_length > max_length) {
            if (print)
                safeputs(ndo, cp+length, max_length-length);
            break;
        }
        if (print)
            safeputs(ndo, cp+length, lab_length);
        length += lab_length;
    }
    if (print)
        ND_PRINT((ndo, "[|DNS]"));
    return -1;
}

Project: tcpdump
File: print-hncp.c

print_type_in_line(netdissect_options *ndo,
                   uint32_t type, int count, int indent, int *first_one)
{
    if (count > 0) {
        if (*first_one) {
            *first_one = 0;
            if (indent > 1) {
                u_int t;
                ND_PRINT((ndo, "\n"));
                for (t = indent; t > 0; t--)
                    ND_PRINT((ndo, "\t"));
            } else {
                ND_PRINT((ndo, " "));
            }
        } else {
            ND_PRINT((ndo, ", "));
        }
        ND_PRINT((ndo, "%s", tok2str(type_values, "Easter Egg", type)));
        if (count > 1)
            ND_PRINT((ndo, " (x%d)", count));
    }
}