Index: Makefile =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/Makefile,v retrieving revision 1.63 diff -u -p -r1.63 Makefile --- Makefile 3 Feb 2018 13:39:48 -0000 1.63 +++ Makefile 2 Dec 2019 23:11:06 -0000 @@ -42,7 +42,7 @@ SRCS= tcpdump.c addrtoname.c privsep.c p print-vrrp.c print-wb.c print-decnet.c print-isoclns.c print-ipx.c \ print-atm.c print-dvmrp.c print-krb.c print-pim.c print-netbios.c \ util.c bpf_dump.c parsenfsfh.c version.c print-igrp.c \ - print-gre.c print-radius.c print-enc.c print-cnfp.c \ + print-gre.c print-nsh.c print-radius.c print-enc.c print-cnfp.c \ print-ipsec.c print-ike.c print-raw.c print-l2tp.c print-mobile.c \ print-ip6.c print-ip6opts.c print-icmp6.c print-dhcp6.c print-frag6.c \ print-bgp.c print-ospf6.c print-ripng.c print-rt6.c print-stp.c \ Index: interface.h =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v retrieving revision 1.82 diff -u -p -r1.82 interface.h --- interface.h 2 Dec 2019 22:07:20 -0000 1.82 +++ interface.h 2 Dec 2019 23:11:06 -0000 @@ -216,6 +216,7 @@ extern void ppp_ether_if_print(u_char *, const u_char *); extern void gre_print(const u_char *, u_int); extern void vxlan_print(const u_char *, u_int); +extern void nsh_print(const u_char *, u_int); extern void icmp_print(const u_char *, u_int, const u_char *); extern void ieee802_11_if_print(u_char *, const struct pcap_pkthdr *, const u_char *); Index: print-ether.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v retrieving revision 1.35 diff -u -p -r1.35 print-ether.c --- print-ether.c 18 Nov 2018 08:55:51 -0000 1.35 +++ print-ether.c 2 Dec 2019 23:11:06 -0000 @@ -289,6 +289,13 @@ recurse: } return (1); +#ifndef ETHERTYPE_NSH +#define ETHERTYPE_NSH 0x894f +#endif + case ETHERTYPE_NSH: + nsh_print(p, length); + return (1); + #ifndef ETHERTYPE_PBB #define ETHERTYPE_PBB 0x88e7 #endif Index: print-gre.c =================================================================== RCS file: /cvs/src/usr.sbin/tcpdump/print-gre.c,v retrieving revision 1.28 diff -u -p -r1.28 print-gre.c --- print-gre.c 2 Dec 2019 22:32:01 -0000 1.28 +++ print-gre.c 2 Dec 2019 23:11:06 -0000 @@ -277,6 +277,12 @@ gre_print_0(const u_char *p, u_int lengt case ETHERTYPE_TRANSETHER: ether_tryprint(p, length, 0); break; +#ifndef ETHERTYPE_NSH +#define ETHERTYPE_NSH 0x894f +#endif + case ETHERTYPE_NSH: + nsh_print(p, length); + break; case ERSPAN_II: gre_print_erspan(flags, p, length); break; @@ -758,7 +764,7 @@ vxlan_print(const u_char *p, u_int lengt ether_tryprint(p, length, 0); break; case VXLAN_PROTO_NSH: - printf("NSH"); + nsh_print(p, length); break; case VXLAN_PROTO_MPLS: mpls_print(p, length); Index: print-nsh.c =================================================================== RCS file: print-nsh.c diff -N print-nsh.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ print-nsh.c 2 Dec 2019 23:11:06 -0000 @@ -0,0 +1,308 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2019 David Gwynne + * + * 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. + */ + +/* + * RFC 8300 Network Service Header (NSH) + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "interface.h" +#include "addrtoname.h" +#include "extract.h" + +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) +#endif + +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + +struct nsh_header { + uint32_t base; +#define NSH_VER_SHIFT 30 +#define NSH_VER_MASK (0x03 << NSH_VER_SHIFT) +#define NSH_VER_0 0x0 +#define NSH_VER_RESERVED (0x01 << NSH_VER_SHIFT) +#define NSH_OAM_SHIFT 29 +#define NSH_OAM_MASK (0x01 << NSH_OAM_SHIFT) +#define NSH_TTL_SHIFT 22 +#define NSH_TTL_MASK (0x3f << NSH_TTL_SHIFT) +#define NSH_LEN_SHIFT 16 +#define NSH_LEN_MASK (0x3f << NSH_LEN_SHIFT) +#define NSH_LEN_FACTOR 4 +#define NSH_MDTYPE_SHIFT 8 +#define NSH_MDTYPE_MASK (0x0f << NSH_MDTYPE_SHIFT) +#define NSH_PROTO_SHIFT 0 +#define NSH_PROTO_MASK (0xff << NSH_PROTO_SHIFT) + + uint32_t sp; +#define NSH_SPI_SHIFT 8 +#define NSH_SPI_MASK (0xffffff << NSH_SPI_SHIFT) +#define NSH_SI_SHIFT 0 +#define NSH_SI_MASK (0xff << NSH_SI_SHIFT) +}; + +#define NSH_PROTO_IPV4 0x01 +#define NSH_PROTO_IPV6 0x02 +#define NSH_PROTO_ETHERNET 0x03 +#define NSH_PROTO_NSH 0x04 +#define NSH_PROTO_MPLS 0x05 +#define NSH_PROTO_EXP1 0xfe /* Experiment 1 */ +#define NSH_PROTO_EXP2 0xff /* Experiment 2 */ + +#define NSH_MDTYPE_RESERVED 0x0 +#define NSH_MDTYPE_1 0x1 +#define NSH_MDTYPE_2 0x2 +#define NSH_MDTYPE_EXP 0xf /* Experimentation */ + +struct nsh_context_header { + uint32_t ch[4]; +}; + +struct nsh_md_header { + uint16_t class; + uint8_t type; + uint8_t len; +#define NSH_MD_LEN_MASK 0x7f +}; + +static void nsh_print_bytes(const void *, u_int); + +static void nsh_print_mdtype1(const u_char *, u_int); +static void nsh_print_mdtype2(const u_char *, u_int); + +void +nsh_print(const u_char *p, u_int length) +{ + struct nsh_header nsh; + uint32_t field, len, proto; + int l = snapend - p; + + printf("NSH"); + + if (l < sizeof(nsh)) + goto trunc; + if (length < sizeof(nsh)) { + printf(" encapsulation truncated"); + return; + } + + nsh.base = EXTRACT_32BITS(p); + nsh.sp = EXTRACT_32BITS(p + sizeof(nsh.base)); + + field = (nsh.base & NSH_VER_MASK) >> NSH_VER_SHIFT; + switch (field) { + case NSH_VER_0: + break; + case NSH_VER_RESERVED: + printf(" Reserved version"); + return; + default: + printf(" Unknown version %u", field); + return; + } + + field = (nsh.sp & NSH_SPI_MASK) >> NSH_SPI_SHIFT; + printf(" spi %u", field); + field = (nsh.sp & NSH_SI_MASK) >> NSH_SI_SHIFT; + printf(" si %u", field); + + len = ((nsh.base & NSH_LEN_MASK) >> NSH_LEN_SHIFT) * NSH_LEN_FACTOR; + if (vflag > 1) { + field = (nsh.base & NSH_TTL_MASK) >> NSH_TTL_SHIFT; + printf(" (ttl %u, len %u)", field, len); + } + + if (l < len) + goto trunc; + if (length < len) { + printf(" encapsulation truncated"); + return; + } + + p += sizeof(nsh); + l -= sizeof(nsh); + len -= sizeof(nsh); + + field = (nsh.base & NSH_MDTYPE_MASK) >> NSH_MDTYPE_SHIFT; + switch (field) { + case NSH_MDTYPE_RESERVED: + printf(" md-type-reserved"); + break; + case NSH_MDTYPE_1: + printf(" md1"); + if (vflag) + nsh_print_mdtype1(p, len); + break; + case NSH_MDTYPE_2: + printf(" md2"); + if (vflag) + nsh_print_mdtype2(p, len); + break; + case NSH_MDTYPE_EXP: + printf(" mdtype-experimentation"); + break; + default: + printf(" mdtype-unknown-0x%02x", field); + break; + } + + printf("%s", vflag ? "\n " : ": "); + + p += len; + l -= len; + length -= len; + + proto = (nsh.base & NSH_PROTO_MASK) >> NSH_PROTO_SHIFT; + + if (nsh.base & NSH_OAM_MASK) + printf("NSH OAM (proto 0x%0x, len %u)", proto, length); + else { + switch (field) { + case NSH_PROTO_IPV4: + ip_print(p, length); + return; + case NSH_PROTO_IPV6: + ip_print(p, length); + return; + case NSH_PROTO_ETHERNET: + ether_tryprint(p, length, 0); + return; + case NSH_PROTO_NSH: + nsh_print(p, length); + return; + case NSH_PROTO_MPLS: + mpls_print(p, length); + return; + case NSH_PROTO_EXP1: + printf("NSH Experiment 1"); + break; + case NSH_PROTO_EXP2: + printf("NSH Experiment 2"); + break; + default: + printf("nsh-unknown-proto-0x%02x", field); + break; + } + } + + if (vflag) + default_print_unaligned(p, length); + + return; +trunc: + printf(" [|nsh]"); +} + +static void +nsh_print_mdtype1(const u_char *p, u_int len) +{ + const struct nsh_context_header *ctx; + size_t i; + + if (len != sizeof(*ctx)) + printf("nsh-mdtype1-length-%u (not %zu)", len, sizeof(*ctx)); + + printf("\n\tcontext"); + + ctx = (const struct nsh_context_header *)p; + for (i = 0; i < nitems(ctx->ch); i++) { + printf(" "); + nsh_print_bytes(&ctx->ch[i], sizeof(ctx->ch[i])); + } +} + +static void +nsh_print_mdtype2(const u_char *p, u_int l) +{ + if (l == 0) + return; + + do { + struct nsh_md_header h; + uint8_t len; + + if (l < sizeof(h)) + goto trunc; + + memcpy(&h, p, sizeof(h)); + p += sizeof(h); + l -= sizeof(h); + + h.class = ntohs(h.class); + len = h.len & NSH_MD_LEN_MASK; + printf("\n\tmd class %u type %u", h.class, h.type); + if (len > 0) { + printf(" "); + nsh_print_bytes(p, len); + } + + len = roundup(len, 4); + if (l < len) + goto trunc; + + p += len; + l -= len; + } while (l > 0); + + return; +trunc: + printf("[|nsh md]"); +} + +static void +nsh_print_bytes(const void *b, u_int l) +{ + const uint8_t *p = b; + u_int i; + + for (i = 0; i < l; i++) { + int ch = p[i]; +#if 0 + if (isprint(ch) && !isspace(ch)) + putchar(ch); + else { + switch (ch) { + case '\\': + printf("\\\\"); + break; + case '\0': + printf("\\0"); + break; + default: + printf("\\x%02x", ch); + break; + } + } +#else + printf("%02x", ch); +#endif + } +}