diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2019-12-02 22:07:21 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2019-12-02 22:07:21 +0000 |
commit | 238eefc523062a817404549c6085da4eca45e2a2 (patch) | |
tree | b137bfe5dfc5ed4c1fea641a45db05dcdcf6dcd5 /usr.sbin | |
parent | 716c19fbda8645e16773fdb2dfb7cc66c5504f9d (diff) |
rewrite dhcpv6 parsing so it follows the rfc, not an incompat draft.
it looks like this code was using draft-ietf-dhc-dhcpv6-14 from
1999. there were 27 drafts, and by the time it got to draft 23 and
the rfc it was significantly different. this code for draft 14
cannot handle actual dhcpv6 messages. im kind of surprised
(disappointed?) that noone noticed before. i only noticed cos the
code was segfaulting on sparc64, and when i tried to fix it the
resulting messages looked nothing like what stock tcpdump produced.
the main difference between the early drafts and what ended up in
the rfc is that the base dhcpv6 messages in early drafts were large
structure with a lot of fixed fields, while the rfc settled on a 4
byte header that contains a 1 byte message type and a 3 byte
transaction id. the rest of the messages are built from dhcp options
fields.
this cuts all the old handling out, and fixes the fault in the
options handling by using EXTRACT_16BITS to get at the code and
length fields instead of using ntohs. dhcpv6 explicitly states that
it does not align options, so this is necessary to avoid faults on
strict alignment archs anyway. no options are pretty printed at the
moment, you just get a numeric type, a length, and a hexdump of the
value. this is still better than the garbage that the draft parsing
produced.
if someone is interested in making this easier to read, it would
be a straightforward and well contained project to better handle
option printing.
ok deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/tcpdump/interface.h | 6 | ||||
-rw-r--r-- | usr.sbin/tcpdump/print-dhcp6.c | 426 | ||||
-rw-r--r-- | usr.sbin/tcpdump/print-udp.c | 7 |
3 files changed, 159 insertions, 280 deletions
diff --git a/usr.sbin/tcpdump/interface.h b/usr.sbin/tcpdump/interface.h index 81f669b1701..f7a55d0492f 100644 --- a/usr.sbin/tcpdump/interface.h +++ b/usr.sbin/tcpdump/interface.h @@ -1,4 +1,4 @@ -/* $OpenBSD: interface.h,v 1.81 2019/05/26 22:42:42 dlg Exp $ */ +/* $OpenBSD: interface.h,v 1.82 2019/12/02 22:07:20 dlg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 @@ -20,7 +20,7 @@ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * @(#) $Id: interface.h,v 1.81 2019/05/26 22:42:42 dlg Exp $ (LBL) + * @(#) $Id: interface.h,v 1.82 2019/12/02 22:07:20 dlg Exp $ (LBL) */ #ifndef tcpdump_interface_h @@ -296,7 +296,7 @@ extern void icmp6_print(const u_char *, u_int, const u_char *); extern void ripng_print(const u_char *, int); extern int rt6_print(const u_char *, const u_char *); extern void ospf6_print(const u_char *, u_int); -extern void dhcp6_print(const u_char *, u_int, u_short, u_short); +extern void dhcp6_print(const u_char *, u_int); extern uint32_t in_cksum_add(const void *, size_t, uint32_t); extern uint16_t in_cksum_fini(uint32_t); diff --git a/usr.sbin/tcpdump/print-dhcp6.c b/usr.sbin/tcpdump/print-dhcp6.c index 95d24fa21c4..bb4e0aa20d4 100644 --- a/usr.sbin/tcpdump/print-dhcp6.c +++ b/usr.sbin/tcpdump/print-dhcp6.c @@ -1,32 +1,19 @@ -/* $OpenBSD: print-dhcp6.c,v 1.11 2018/10/22 16:12:45 kn Exp $ */ +/* $OpenBSD: print-dhcp6.c,v 1.12 2019/12/02 22:07:20 dlg Exp $ */ /* - * Copyright (C) 1998 and 1999 WIDE Project. - * All rights reserved. - * - * 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. + * Copyright (c) 2019 David Gwynne <dlg@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/time.h> @@ -44,286 +31,179 @@ struct rtentry; #include <arpa/inet.h> #include "interface.h" +#include "extract.h" #include "addrtoname.h" -#include "dhcp6.h" -#include "dhcp6opt.h" - -#if 0 -static void dhcp6opttab_init(void); -static struct dhcp6_opt *dhcp6opttab_byname(char *); -#endif -static struct dhcp6_opt *dhcp6opttab_bycode(u_int); - -static char tstr[] = " [|dhcp6]"; - -static struct dhcp6_opt dh6opttab[] = { - /* IP Address Extension */ - { 1, OL6_N, "IP Address", OT6_NONE, }, - - /* General Extension */ - { 2, 4, "Time Offset", OT6_NUM, }, - { 3, OL6_N, "IEEE 1003.1 POSIX Timezone", OT6_STR, }, - { 6, OL6_16N, "Domain Name Server", OT6_V6, }, - { 10, OL6_N, "Domain Name", OT6_STR, }, - - /* Application and Service Parameters */ - { 16, OL6_N, "Directory Agent", OT6_NONE, }, - { 17, OL6_N, "Service Scope" , OT6_NONE, }, - { 18, OL6_16N, "Network Time Protocol Servers", OT6_V6, }, - { 19, OL6_N, "NIS Domain", OT6_STR, }, - { 20, OL6_16N, "NIS Servers", OT6_V6, }, - { 21, OL6_N, "NIS+ Domain", OT6_STR, }, - { 22, OL6_16N, "NIS+ Servers", OT6_V6, }, - - /* TCP Parameters */ - { 32, 4, "TCP Keepalive Interval", OT6_NUM, }, - - /* DHCPv6 Extensions */ - { 40, 4, "Maximum DHCPv6 Message Size", OT6_NUM, }, - { 41, OL6_N, "DHCP Retransmission and Configuration Parameter", - OT6_NONE, }, - { 48, OL6_N, "Platform Specific Information", OT6_NONE, }, - { 49, OL6_N, "Platform Class Identifier", OT6_STR, }, - { 64, OL6_N, "Class Identifier", OT6_STR, }, - { 66, 16, "Reconfigure Multicast Address", OT6_V6, }, - { 67, 16, "Renumber DHCPv6 Server Address", - OT6_V6, }, - { 68, OL6_N, "DHCP Relay ICMP Error Message", OT6_NONE, }, - { 84, OL6_N, "Client-Server Authentication", OT6_NONE, }, - { 85, 4, "Client Key Selection", OT6_NUM, }, - - /* End Extension */ - { 65536, OL6_Z, "End", OT6_NONE, }, - - { 0 }, -}; - -#if 0 -static struct dhcp6_opt *dh6o_pad; -static struct dhcp6_opt *dh6o_end; -static void -dhcp6opttab_init() -{ - dh6o_pad = dhcp6opttab_bycode(0); - dh6o_end = dhcp6opttab_bycode(65536); -} -#endif +/* Message type */ +#define DH6_SOLICIT 1 +#define DH6_ADVERTISE 2 +#define DH6_REQUEST 3 +#define DH6_CONFIRM 4 +#define DH6_RENEW 5 +#define DH6_REBIND 6 +#define DH6_REPLY 7 +#define DH6_RELEASE 8 +#define DH6_DECLINE 9 +#define DH6_RECONFIGURE 10 +#define DH6_INFORMATION_REQUEST 11 +#define DH6_RELAY_FORW 12 +#define DH6_RELAY_REPL 13 -#if 0 -static struct dhcp6_opt * -dhcp6opttab_byname(name) - char *name; +static void +dhcp6opt_print(const u_char *cp, u_int length) { - struct dhcp6_opt *p; + uint16_t code, len; + u_int i; + int l = snapend - cp; + + while (length > 0) { + if (l < sizeof(code)) + goto trunc; + if (length < sizeof(code)) + goto iptrunc; + + code = EXTRACT_16BITS(cp); + cp += sizeof(code); + length -= sizeof(code); + l -= sizeof(code); + + if (l < sizeof(len)) + goto trunc; + if (length < sizeof(len)) + goto iptrunc; + + len = EXTRACT_16BITS(cp); + cp += sizeof(len); + length -= sizeof(len); + l -= sizeof(len); + + printf("\n\toption %u len %u", code, len); + + if (len > 0) { + if (l < len) + goto trunc; + if (length < len) + goto iptrunc; - for (p = dh6opttab; p->code; p++) - if (strcmp(name, p->name) == 0) - return p; - return NULL; -} -#endif + printf(" "); + for (i = 0; i < len; i++) + printf("%02x", cp[4 + i] & 0xff); -static struct dhcp6_opt * -dhcp6opttab_bycode(code) - u_int code; -{ - struct dhcp6_opt *p; + cp += len; + length -= len; + l -= len; + } + } + return; - for (p = dh6opttab; p->code; p++) - if (p->code == code) - return p; - return NULL; +trunc: + printf(" [|dhcp6opt]"); + return; +iptrunc: + printf(" ip truncated"); } static void -dhcp6ext_print(u_char *cp, u_char *ep) +dhcp6_relay_print(const u_char *cp, u_int length) { - u_int16_t code, len; - struct dhcp6_opt *p; - char buf[BUFSIZ]; - int i; - - if (cp == ep) - return; - printf(" "); - while (cp < ep) { - code = ntohs(*(u_int16_t *)&cp[0]); - if (code != 65535) - len = ntohs(*(u_int16_t *)&cp[2]); - else - len = 0; - p = dhcp6opttab_bycode(code); - if (p == NULL) { - printf("(unknown, len=%d)", len); - cp += len + 4; - continue; - } + uint8_t msgtype; + const char *msgname = NULL; - /* sanity check on length */ - switch (p->len) { - case OL6_N: - break; - case OL6_16N: - if (len % 16 != 0) - goto trunc; - break; - case OL6_Z: - if (len != 0) - goto trunc; - break; - default: - if (len != p->len) - goto trunc; - break; - } - if (cp + 4 + len > ep) { - printf("[|%s]", p->name); - return; - } + msgtype = *cp; - printf("(%s, ", p->name); - switch (p->type) { - case OT6_V6: - for (i = 0; i < len; i += 16) { - inet_ntop(AF_INET6, &cp[4 + i], buf, - sizeof(buf)); - if (i != 0) - printf(","); - printf("%s", buf); - } - break; - case OT6_STR: - memset(&buf, 0, sizeof(buf)); - strlcpy(buf, &cp[4], len); - printf("%s", buf); - break; - case OT6_NUM: - printf("%d", (u_int32_t)ntohl(*(u_int32_t *)&cp[4])); - break; - default: - for (i = 0; i < len; i++) - printf("%02x", cp[4 + i] & 0xff); - } - printf(")"); - cp += len + 4; + switch (msgtype) { + case DH6_RELAY_FORW: + msgname = "Relay-forward"; + break; + case DH6_RELAY_REPL: + msgname = "Relay-reply"; + break; } - return; -trunc: - printf("[|dhcp6ext]"); + printf(" %s", msgname); } -/* - * Print dhcp6 requests - */ void -dhcp6_print(const u_char *cp, u_int length, - u_short sport, u_short dport) +dhcp6_print(const u_char *cp, u_int length) { - union dhcp6 *dh6; - u_char *ep; - u_char *extp; + uint8_t msgtype; + uint32_t hdr; + int l = snapend - cp; + const char *msgname; - printf("dhcp6"); + printf("DHCPv6"); - ep = (u_char *)snapend; + if (l < sizeof(msgtype)) + goto trunc; + if (length < sizeof(msgtype)) + goto iptrunc; - dh6 = (union dhcp6 *)cp; - TCHECK(dh6->dh6_msgtype); - switch (dh6->dh6_msgtype) { + msgtype = *cp; + + switch (msgtype) { case DH6_SOLICIT: - if (vflag && TTEST(dh6->dh6_sol.dh6sol_relayaddr)) { - printf(" solicit("); - if ((dh6->dh6_sol.dh6sol_flags & DH6SOL_CLOSE) != 0) - printf("C"); - if (dh6->dh6_sol.dh6sol_flags != 0) - printf(" "); - printf("cliaddr=%s", - ip6addr_string(&dh6->dh6_sol.dh6sol_cliaddr)); - printf(" relayaddr=%s", - ip6addr_string(&dh6->dh6_sol.dh6sol_relayaddr)); - printf(")"); - } else - printf(" solicit"); + msgname = "Solicit"; break; - case DH6_ADVERT: - if (!(vflag && TTEST(dh6->dh6_adv.dh6adv_serveraddr))) { - printf(" advert"); - break; - } - printf(" advert("); - if ((dh6->dh6_adv.dh6adv_flags & DH6ADV_SERVPRESENT) != 0) - printf("S"); - if (dh6->dh6_adv.dh6adv_flags != 0) - printf(" "); - printf("pref=%u", dh6->dh6_adv.dh6adv_pref); - printf(" cliaddr=%s", - ip6addr_string(&dh6->dh6_adv.dh6adv_cliaddr)); - printf(" relayaddr=%s", - ip6addr_string(&dh6->dh6_adv.dh6adv_relayaddr)); - printf(" servaddr=%s", - ip6addr_string(&dh6->dh6_adv.dh6adv_serveraddr)); - extp = (u_char *)((&dh6->dh6_adv) + 1); - dhcp6ext_print(extp, ep); - printf(")"); + case DH6_ADVERTISE: + msgname = "Advertise"; break; case DH6_REQUEST: - if (!(vflag && TTEST(dh6->dh6_req.dh6req_relayaddr))) { - printf(" request"); - break; - } - printf(" request("); - if ((dh6->dh6_req.dh6req_flags & DH6REQ_CLOSE) != 0) - printf("C"); - if ((dh6->dh6_req.dh6req_flags & DH6REQ_SERVPRESENT) != 0) - printf("S"); - if ((dh6->dh6_req.dh6req_flags & DH6REQ_REBOOT) != 0) - printf("R"); - if (dh6->dh6_req.dh6req_flags != 0) - printf(" "); - printf("xid=0x%04x", dh6->dh6_req.dh6req_xid); - printf(" cliaddr=%s", - ip6addr_string(&dh6->dh6_req.dh6req_cliaddr)); - printf(" relayaddr=%s", - ip6addr_string(&dh6->dh6_req.dh6req_relayaddr)); - extp = (char *)((&dh6->dh6_req) + 1); - if ((dh6->dh6_req.dh6req_flags & DH6REQ_SERVPRESENT) != 0) { - printf(" servaddr=%s", ip6addr_string(extp)); - extp += 16; - } - dhcp6ext_print(extp, ep); - printf(")"); + msgname = "Request"; + break; + case DH6_CONFIRM: + msgname = "Confirm"; + break; + case DH6_RENEW: + msgname = "Renew"; + break; + case DH6_REBIND: + msgname = "Rebind"; break; case DH6_REPLY: - if (!(vflag && TTEST(dh6->dh6_rep.dh6rep_xid))) { - printf(" reply"); - break; - } - printf(" reply("); - if ((dh6->dh6_rep.dh6rep_flagandstat & DH6REP_CLIPRESENT) != 0) - printf("C"); - if (dh6->dh6_rep.dh6rep_flagandstat != 0) - printf(" "); - printf("stat=0x%02x", - dh6->dh6_rep.dh6rep_flagandstat & DH6REP_STATMASK); - extp = (u_char *)((&dh6->dh6_rep) + 1); - if ((dh6->dh6_rep.dh6rep_flagandstat & DH6REP_CLIPRESENT) != 0) { - printf(" cliaddr=%s", ip6addr_string(extp)); - extp += 16; - } - dhcp6ext_print(extp, ep); - printf(")"); + msgname = "Reply"; break; case DH6_RELEASE: - printf(" release"); + msgname = "Release"; + break; + case DH6_DECLINE: + msgname = "Decline"; + break; + case DH6_RECONFIGURE: + msgname = "Reconfigure"; break; - case DH6_RECONFIG: - printf(" reconfig"); + case DH6_INFORMATION_REQUEST: + msgname = "Information-request"; break; + case DH6_RELAY_FORW: + case DH6_RELAY_REPL: + dhcp6_relay_print(cp, length); + return; + default: + printf(" unknown message type %u", msgtype); + return; + } + + printf(" %s", msgname); + + if (l < sizeof(hdr)) + goto trunc; + if (length < sizeof(hdr)) + goto iptrunc; + + hdr = EXTRACT_32BITS(cp); + printf(" xid %x", hdr & 0xffffff); + + if (vflag) { + cp += sizeof(hdr); + length -= sizeof(hdr); + + dhcp6opt_print(cp, length); } return; trunc: - printf("%s", tstr); + printf(" [|dhcp6]"); + return; +iptrunc: + printf(" ip truncated"); } diff --git a/usr.sbin/tcpdump/print-udp.c b/usr.sbin/tcpdump/print-udp.c index f27ff8959a7..bb2d4878a75 100644 --- a/usr.sbin/tcpdump/print-udp.c +++ b/usr.sbin/tcpdump/print-udp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print-udp.c,v 1.51 2018/10/22 16:12:45 kn Exp $ */ +/* $OpenBSD: print-udp.c,v 1.52 2019/12/02 22:07:20 dlg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996 @@ -565,9 +565,8 @@ udp_print(const u_char *bp, u_int length, const void *iph) mpls_print(cp, length); else if (ISPORT(RIPNG_PORT)) ripng_print(cp, length); - else if (ISPORT(DHCP6_PORT1) || ISPORT(DHCP6_PORT2)) { - dhcp6_print(cp, length, sport, dport); - } + else if (ISPORT(DHCP6_PORT1) || ISPORT(DHCP6_PORT2)) + dhcp6_print(cp, length); else if (ISPORT(GTP_C_PORT) || ISPORT(GTP_U_PORT) || ISPORT(GTP_PRIME_PORT)) gtp_print(cp, length, sport, dport); |