1 /* $OpenBSD: print-nhrp.c,v 1.1 2020/04/15 20:19:25 remi Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Remi Locherer <remi@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * RFC 2332 NBMA Next Hop Resolution Protocol (NHRP) 21 */ 22 23 #include <sys/time.h> 24 #include <sys/uio.h> 25 #include <sys/socket.h> 26 27 #include <netinet/in.h> 28 #include <netinet/ip.h> 29 #include <arpa/inet.h> 30 31 #include <net/ethertypes.h> 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <ctype.h> 36 37 #include "addrtoname.h" 38 #include "afnum.h" 39 #include "interface.h" 40 #include "extract.h" 41 42 #define NHRP_VER_RFC2332 1 43 44 #define NHRP_PKG_RESOLUTION_REQUEST 1 45 #define NHRP_PKG_RESOLUTION_REPLY 2 46 #define NHRP_PKG_REGISTRATION_REQUEST 3 47 #define NHRP_PKG_REGISTRATION_REPLY 4 48 #define NHRP_PKG_PURGE_REQUEST 5 49 #define NHRP_PKG_PURGE_REPLY 6 50 #define NHRP_PKG_ERROR_INDICATION 7 51 52 53 struct nhrp_header { 54 /* fixed header part */ 55 u_int16_t afn; /* link layer address */ 56 u_int16_t pro_type; /* protocol type (short form) */ 57 u_int8_t pro_snap[5]; /* protocol type (long form) */ 58 u_int8_t hopcnt; /* hop count */ 59 u_int16_t pktsz; /* length of the NHRP packet (octets) */ 60 u_int16_t chksum; /* IP checksum over the entier packet */ 61 u_int16_t extoff; /* extension offset */ 62 u_int8_t op_version; /* version of address mapping and 63 management protocol */ 64 u_int8_t op_type; /* NHRP packet type */ 65 u_int8_t shtl; /* type and length of src NBMA addr */ 66 u_int8_t sstl; /* type and length of src NBMA 67 subaddress */ 68 /* mandatory header part */ 69 u_int8_t spl; /* src proto len */ 70 u_int8_t dpl; /* dst proto len */ 71 u_int16_t flags; /* flags */ 72 union { 73 u_int32_t id; /* request id */ 74 struct { /* error code */ 75 u_int16_t code; 76 u_int16_t offset; 77 } err; 78 } u; 79 }; 80 81 struct nhrp_cie { 82 /* client information entrie */ 83 u_int8_t code; 84 u_int8_t plen; 85 u_int16_t unused; 86 u_int16_t mtu; 87 u_int16_t htime; 88 u_int8_t cli_addr_tl; 89 u_int8_t cli_saddr_tl; 90 u_int8_t cli_proto_tl; 91 u_int8_t pref; 92 }; 93 94 static const u_char * nhrp_print_cie(const u_char *, u_int16_t, u_int16_t); 95 96 97 void 98 nhrp_print(const u_char *p, u_int length) 99 { 100 struct nhrp_header *hdr; 101 const u_char *nhrpext, *nhrpend; 102 103 printf("NHRP: "); 104 105 if ((snapend - p) < sizeof(*hdr)) 106 goto trunc; 107 108 hdr = (struct nhrp_header *)p; 109 110 if (hdr->op_version != NHRP_VER_RFC2332) { 111 printf("unknown-version-%02x", hdr->op_version); 112 return; 113 114 } 115 116 nhrpext = p + EXTRACT_16BITS(&hdr->extoff); 117 nhrpend = p + EXTRACT_16BITS(&hdr->pktsz); 118 119 switch (hdr->op_type) { 120 case NHRP_PKG_RESOLUTION_REQUEST: 121 printf("res request, "); 122 break; 123 case NHRP_PKG_RESOLUTION_REPLY: 124 printf("res reply, "); 125 break; 126 case NHRP_PKG_REGISTRATION_REQUEST: 127 printf("reg request, "); 128 break; 129 case NHRP_PKG_REGISTRATION_REPLY: 130 printf("reg reply, "); 131 break; 132 case NHRP_PKG_PURGE_REQUEST: 133 printf("purge request, "); 134 break; 135 case NHRP_PKG_PURGE_REPLY: 136 printf("purge reply, "); 137 break; 138 case NHRP_PKG_ERROR_INDICATION: 139 printf("error %u", hdr->u.err.code); 140 return; 141 default: 142 printf("unknown-op-type-%04x, ", hdr->op_type); 143 break; 144 } 145 146 printf("id %u", EXTRACT_32BITS(&hdr->u.id)); 147 148 if (vflag) { 149 printf(", hopcnt %u", hdr->hopcnt); 150 151 /* most significat bit must be 0 */ 152 if (hdr->shtl & 0x80) 153 printf(" (shtl bit 7 set)"); 154 155 /* check 2nd most significant bit */ 156 if (hdr->shtl & 0x40) 157 printf(" (nbma E.154)"); 158 } 159 160 p += sizeof(*hdr); 161 if ((snapend - p) < hdr->shtl) 162 goto trunc; 163 164 if (hdr->shtl) { 165 switch (EXTRACT_16BITS(&hdr->afn)) { 166 case AFNUM_INET: 167 printf(", src nbma %s", ipaddr_string(p)); 168 break; 169 case AFNUM_INET6: 170 printf(", src nbma %s", ip6addr_string(p)); 171 break; 172 case AFNUM_802: 173 printf(", src nbma %s", etheraddr_string(p)); 174 break; 175 default: 176 printf(", unknown-nbma-addr-family-%04x", 177 EXTRACT_16BITS(&hdr->afn)); 178 break; 179 } 180 } 181 182 p += hdr->shtl; 183 if ((snapend - p) < (hdr->spl + hdr->dpl)) 184 goto trunc; 185 186 switch (EXTRACT_16BITS(&hdr->pro_type)) { 187 case ETHERTYPE_IP: 188 printf(", %s -> %s", 189 ipaddr_string(p), 190 ipaddr_string(p + hdr->spl)); 191 break; 192 case ETHERTYPE_IPV6: 193 printf(", %s -> %s", 194 ip6addr_string(p), 195 ip6addr_string(p + hdr->spl)); 196 break; 197 default: 198 printf(", proto type %04x", 199 EXTRACT_16BITS(&hdr->pro_type)); 200 break; 201 } 202 203 p += hdr->spl + hdr->dpl; 204 205 do { 206 p = nhrp_print_cie(p, hdr->afn, hdr->pro_type); 207 if (p == 0) 208 goto trunc; 209 } while ((hdr->extoff && (p < nhrpext)) || 210 ((!hdr->extoff && (p < nhrpend)))); 211 212 return; 213 214 trunc: 215 printf(" [|nhrp]"); 216 217 } 218 219 static const u_char * 220 nhrp_print_cie(const u_char *data, u_int16_t afn, u_int16_t pro_type) 221 { 222 struct nhrp_cie *cie; 223 int family, type; 224 225 if ((snapend - data) < sizeof(*cie)) 226 return (0); 227 228 cie = (struct nhrp_cie *)data; 229 230 family = EXTRACT_16BITS(&afn); 231 type = EXTRACT_16BITS(&pro_type); 232 233 printf(" (code %d", cie->code); 234 if (vflag) 235 printf(", pl %d, mtu %d, htime %d, pref %d", cie->plen, 236 EXTRACT_16BITS(&cie->mtu), EXTRACT_16BITS(&cie->htime), 237 cie->pref); 238 239 /* check 2nd most significant bit */ 240 if (cie->cli_addr_tl & 0x40) 241 printf(", nbma E.154"); 242 243 data += sizeof(*cie); 244 if ((snapend - data) < cie->cli_addr_tl) 245 return (0); 246 247 if (cie->cli_addr_tl) { 248 switch (family) { 249 case AFNUM_INET: 250 printf(", nbma %s", ipaddr_string(data)); 251 break; 252 case AFNUM_INET6: 253 printf(", nbma %s", ip6addr_string(data)); 254 break; 255 case AFNUM_802: 256 printf(", nbma %s", etheraddr_string(data)); 257 break; 258 default: 259 printf(", unknown-nbma-addr-family-%04x", family); 260 break; 261 } 262 } 263 if (cie->cli_saddr_tl) 264 printf(", unknown-nbma-saddr-family"); 265 266 data += cie->cli_addr_tl + cie->cli_saddr_tl; 267 if ((snapend - data) < cie->cli_proto_tl) 268 return (0); 269 270 if (cie->cli_proto_tl) { 271 switch (type) { 272 case ETHERTYPE_IP: 273 printf(", proto %s", ipaddr_string(data)); 274 break; 275 case ETHERTYPE_IPV6: 276 printf(", proto %s", ip6addr_string(data)); 277 break; 278 default: 279 printf(", unknown-proto-family-%04x", type); 280 break; 281 } 282 } 283 284 printf(")"); 285 286 return (data + cie->cli_proto_tl); 287 } 288