1671dd9faSspz /* 2671dd9faSspz * Copyright (c) 1988-1997 3671dd9faSspz * The Regents of the University of California. All rights reserved. 4671dd9faSspz * 5671dd9faSspz * Copyright (c) 1998-2012 Michael Richardson <mcr@tcpdump.org> 6671dd9faSspz * The TCPDUMP project 7671dd9faSspz * 8671dd9faSspz * Redistribution and use in source and binary forms, with or without 9671dd9faSspz * modification, are permitted provided that: (1) source code distributions 10671dd9faSspz * retain the above copyright notice and this paragraph in its entirety, (2) 11671dd9faSspz * distributions including binary code include the above copyright notice and 12671dd9faSspz * this paragraph in its entirety in the documentation or other materials 13671dd9faSspz * provided with the distribution, and (3) all advertising materials mentioning 14671dd9faSspz * features or use of this software display the following acknowledgement: 15671dd9faSspz * ``This product includes software developed by the University of California, 16671dd9faSspz * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 17671dd9faSspz * the University nor the names of its contributors may be used to endorse 18671dd9faSspz * or promote products derived from this software without specific prior 19671dd9faSspz * written permission. 20671dd9faSspz * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 21671dd9faSspz * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 22671dd9faSspz * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 23671dd9faSspz */ 24671dd9faSspz 25dc860a36Sspz #include <sys/cdefs.h> 26dc860a36Sspz #ifndef lint 27*26ba0b50Schristos __RCSID("$NetBSD: netdissect.c,v 1.4 2024/09/02 16:15:30 christos Exp $"); 28dc860a36Sspz #endif 29dc860a36Sspz 30c74ad251Schristos #include <config.h> 31671dd9faSspz 32c74ad251Schristos #include "netdissect-stdinc.h" 33671dd9faSspz #include "netdissect.h" 34671dd9faSspz #include <string.h> 35671dd9faSspz #include <stdio.h> 36c74ad251Schristos #include <stdlib.h> 37671dd9faSspz 38671dd9faSspz #ifdef USE_LIBSMI 39671dd9faSspz #include <smi.h> 40671dd9faSspz #endif 41671dd9faSspz 42671dd9faSspz /* 43671dd9faSspz * Initialize anything that must be initialized before dissecting 44671dd9faSspz * packets. 45671dd9faSspz * 46671dd9faSspz * This should be called at the beginning of the program; it does 47671dd9faSspz * not need to be called, and should not be called, for every 48671dd9faSspz * netdissect_options structure. 49671dd9faSspz */ 50671dd9faSspz int 51671dd9faSspz nd_init(char *errbuf, size_t errbuf_size) 52671dd9faSspz { 53671dd9faSspz #ifdef _WIN32 54671dd9faSspz WORD wVersionRequested; 55671dd9faSspz WSADATA wsaData; 56671dd9faSspz int err; 57671dd9faSspz 58671dd9faSspz /* 59671dd9faSspz * Request Winsock 2.2; we expect Winsock 2. 60671dd9faSspz */ 61671dd9faSspz wVersionRequested = MAKEWORD(2, 2); 62671dd9faSspz err = WSAStartup(wVersionRequested, &wsaData); 63671dd9faSspz if (err != 0) { 64671dd9faSspz strlcpy(errbuf, "Attempting to initialize Winsock failed", 65671dd9faSspz errbuf_size); 66671dd9faSspz return (-1); 67671dd9faSspz } 68671dd9faSspz #endif /* _WIN32 */ 69671dd9faSspz 70671dd9faSspz #ifdef USE_LIBSMI 71671dd9faSspz /* 72671dd9faSspz * XXX - should we just fail if this fails? Some of the 73671dd9faSspz * libsmi calls may fail. 74671dd9faSspz */ 75671dd9faSspz smiInit("tcpdump"); 76671dd9faSspz #endif 77671dd9faSspz 78671dd9faSspz /* 79671dd9faSspz * Clears the error buffer, and uses it so we don't get 80671dd9faSspz * "unused argument" warnings at compile time. 81671dd9faSspz */ 82671dd9faSspz strlcpy(errbuf, "", errbuf_size); 83671dd9faSspz return (0); 84671dd9faSspz } 85671dd9faSspz 86671dd9faSspz /* 87671dd9faSspz * Clean up anything that ndo_init() did. 88671dd9faSspz */ 89671dd9faSspz void 90671dd9faSspz nd_cleanup(void) 91671dd9faSspz { 92671dd9faSspz #ifdef USE_LIBSMI 93671dd9faSspz /* 94671dd9faSspz * This appears, in libsmi 0.4.8, to do nothing if smiInit() 95671dd9faSspz * wasn't done or failed, so we call it unconditionally. 96671dd9faSspz */ 97671dd9faSspz smiExit(); 98671dd9faSspz #endif 99671dd9faSspz 100671dd9faSspz #ifdef _WIN32 101671dd9faSspz /* 102671dd9faSspz * Undo the WSAStartup() call above. 103671dd9faSspz */ 104671dd9faSspz WSACleanup(); 105671dd9faSspz #endif 106671dd9faSspz } 107671dd9faSspz 108671dd9faSspz int 109671dd9faSspz nd_have_smi_support(void) 110671dd9faSspz { 111671dd9faSspz #ifdef USE_LIBSMI 112671dd9faSspz return (1); 113671dd9faSspz #else 114671dd9faSspz return (0); 115671dd9faSspz #endif 116671dd9faSspz } 117671dd9faSspz 118671dd9faSspz /* 119671dd9faSspz * Indicates whether an SMI module has been loaded, so that we can use 120671dd9faSspz * libsmi to translate OIDs. 121671dd9faSspz */ 122671dd9faSspz int nd_smi_module_loaded; 123671dd9faSspz 124671dd9faSspz int 125671dd9faSspz nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size) 126671dd9faSspz { 127671dd9faSspz #ifdef USE_LIBSMI 128671dd9faSspz if (smiLoadModule(module) == 0) { 129671dd9faSspz snprintf(errbuf, errbuf_size, "could not load MIB module %s", 130671dd9faSspz module); 131671dd9faSspz return (-1); 132671dd9faSspz } 133671dd9faSspz nd_smi_module_loaded = 1; 134671dd9faSspz return (0); 135671dd9faSspz #else 136671dd9faSspz snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support", 137671dd9faSspz module); 138671dd9faSspz return (-1); 139671dd9faSspz #endif 140671dd9faSspz } 141671dd9faSspz 142671dd9faSspz const char * 143671dd9faSspz nd_smi_version_string(void) 144671dd9faSspz { 145671dd9faSspz #ifdef USE_LIBSMI 146671dd9faSspz return (smi_version_string); 147671dd9faSspz #else 148671dd9faSspz return (NULL); 149671dd9faSspz #endif 150671dd9faSspz } 151c74ad251Schristos 152c74ad251Schristos 153c74ad251Schristos int 154c74ad251Schristos nd_push_buffer(netdissect_options *ndo, u_char *new_buffer, 155c74ad251Schristos const u_char *new_packetp, const u_int newlen) 156c74ad251Schristos { 157c74ad251Schristos struct netdissect_saved_packet_info *ndspi; 158c74ad251Schristos 159c74ad251Schristos ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info)); 160c74ad251Schristos if (ndspi == NULL) 161c74ad251Schristos return (0); /* fail */ 162c74ad251Schristos ndspi->ndspi_buffer = new_buffer; 163c74ad251Schristos ndspi->ndspi_packetp = ndo->ndo_packetp; 164c74ad251Schristos ndspi->ndspi_snapend = ndo->ndo_snapend; 165c74ad251Schristos ndspi->ndspi_prev = ndo->ndo_packet_info_stack; 166c74ad251Schristos 167c74ad251Schristos ndo->ndo_packetp = new_packetp; 168c74ad251Schristos ndo->ndo_snapend = new_packetp + newlen; 169c74ad251Schristos ndo->ndo_packet_info_stack = ndspi; 170c74ad251Schristos 171c74ad251Schristos return (1); /* success */ 172c74ad251Schristos } 173c74ad251Schristos 174c74ad251Schristos 175c74ad251Schristos /* 176c74ad251Schristos * In a given netdissect_options structure: 177c74ad251Schristos * 178c74ad251Schristos * push the current packet information onto the packet information 179c74ad251Schristos * stack; 180c74ad251Schristos * 181c74ad251Schristos * given a pointer into the packet and a length past that point in 182c74ad251Schristos * the packet, calculate a new snapshot end that's at the lower 183c74ad251Schristos * of the current snapshot end and that point in the packet; 184c74ad251Schristos * 185c74ad251Schristos * set the snapshot end to that new value. 186c74ad251Schristos */ 187c74ad251Schristos int 188c74ad251Schristos nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen) 189c74ad251Schristos { 190c74ad251Schristos struct netdissect_saved_packet_info *ndspi; 191c74ad251Schristos u_int snaplen_remaining; 192c74ad251Schristos 193c74ad251Schristos ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info)); 194c74ad251Schristos if (ndspi == NULL) 195c74ad251Schristos return (0); /* fail */ 196c74ad251Schristos ndspi->ndspi_buffer = NULL; /* no new buffer */ 197c74ad251Schristos ndspi->ndspi_packetp = ndo->ndo_packetp; 198c74ad251Schristos ndspi->ndspi_snapend = ndo->ndo_snapend; 199c74ad251Schristos ndspi->ndspi_prev = ndo->ndo_packet_info_stack; 200c74ad251Schristos 201c74ad251Schristos /* 202c74ad251Schristos * Push the saved previous data onto the stack. 203c74ad251Schristos */ 204c74ad251Schristos ndo->ndo_packet_info_stack = ndspi; 205c74ad251Schristos 206c74ad251Schristos /* 207c74ad251Schristos * Find out how many bytes remain after the current snapend. 208c74ad251Schristos * 209c74ad251Schristos * We're restricted to packets with at most UINT_MAX bytes; 210c74ad251Schristos * cast the result to u_int, so that we don't get truncation 211c74ad251Schristos * warnings on LP64 and LLP64 platforms. (ptrdiff_t is 212c74ad251Schristos * signed and we want an unsigned difference; the pointer 213c74ad251Schristos * should at most be equal to snapend, and must *never* 214c74ad251Schristos * be past snapend.) 215c74ad251Schristos */ 216c74ad251Schristos snaplen_remaining = (u_int)(ndo->ndo_snapend - bp); 217c74ad251Schristos 218c74ad251Schristos /* 219c74ad251Schristos * If the new snapend is smaller than the one calculated 220c74ad251Schristos * above, set the snapend to that value, otherwise leave 221c74ad251Schristos * it unchanged. 222c74ad251Schristos */ 223c74ad251Schristos if (newlen <= snaplen_remaining) { 224c74ad251Schristos /* Snapend isn't past the previous snapend */ 225c74ad251Schristos ndo->ndo_snapend = bp + newlen; 226c74ad251Schristos } 227c74ad251Schristos 228c74ad251Schristos return (1); /* success */ 229c74ad251Schristos } 230c74ad251Schristos 231c74ad251Schristos /* 232c74ad251Schristos * In a given netdissect_options structure: 233c74ad251Schristos * 234c74ad251Schristos * given a pointer into the packet and a length past that point in 235c74ad251Schristos * the packet, calculate a new snapshot end that's at the lower 236c74ad251Schristos * of the previous snapshot end - or, if there is no previous 237c74ad251Schristos * snapshot end, the current snapshot end - and that point in the 238c74ad251Schristos * packet; 239c74ad251Schristos * 240c74ad251Schristos * set the snapshot end to that new value. 241c74ad251Schristos * 242c74ad251Schristos * This is to change the current snapshot end. This may increase the 243c74ad251Schristos * snapshot end, as it may be used, for example, for a Jumbo Payload 244c74ad251Schristos * option in IPv6. It must not increase it past the snapshot length 245c74ad251Schristos * atop which the current one was pushed, however. 246c74ad251Schristos */ 247c74ad251Schristos void 248c74ad251Schristos nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen) 249c74ad251Schristos { 250c74ad251Schristos struct netdissect_saved_packet_info *ndspi; 251c74ad251Schristos const u_char *previous_snapend; 252c74ad251Schristos u_int snaplen_remaining; 253c74ad251Schristos 254c74ad251Schristos ndspi = ndo->ndo_packet_info_stack; 255c74ad251Schristos if (ndspi->ndspi_prev != NULL) 256c74ad251Schristos previous_snapend = ndspi->ndspi_prev->ndspi_snapend; 257c74ad251Schristos else 258c74ad251Schristos previous_snapend = ndo->ndo_snapend; 259c74ad251Schristos 260c74ad251Schristos /* 261c74ad251Schristos * Find out how many bytes remain after the previous 262c74ad251Schristos * snapend - or, if there is no previous snapend, after 263c74ad251Schristos * the current snapend. 264c74ad251Schristos * 265c74ad251Schristos * We're restricted to packets with at most UINT_MAX bytes; 266c74ad251Schristos * cast the result to u_int, so that we don't get truncation 267c74ad251Schristos * warnings on LP64 and LLP64 platforms. (ptrdiff_t is 268c74ad251Schristos * signed and we want an unsigned difference; the pointer 269c74ad251Schristos * should at most be equal to snapend, and must *never* 270c74ad251Schristos * be past snapend.) 271c74ad251Schristos */ 272c74ad251Schristos snaplen_remaining = (u_int)(previous_snapend - bp); 273c74ad251Schristos 274c74ad251Schristos /* 275c74ad251Schristos * If the new snapend is smaller than the one calculated 276c74ad251Schristos * above, set the snapend to that value, otherwise leave 277c74ad251Schristos * it unchanged. 278c74ad251Schristos */ 279c74ad251Schristos if (newlen <= snaplen_remaining) { 280c74ad251Schristos /* Snapend isn't past the previous snapend */ 281c74ad251Schristos ndo->ndo_snapend = bp + newlen; 282c74ad251Schristos } 283c74ad251Schristos } 284c74ad251Schristos 285c74ad251Schristos void 286c74ad251Schristos nd_pop_packet_info(netdissect_options *ndo) 287c74ad251Schristos { 288c74ad251Schristos struct netdissect_saved_packet_info *ndspi; 289c74ad251Schristos 290c74ad251Schristos ndspi = ndo->ndo_packet_info_stack; 291c74ad251Schristos ndo->ndo_packetp = ndspi->ndspi_packetp; 292c74ad251Schristos ndo->ndo_snapend = ndspi->ndspi_snapend; 293c74ad251Schristos ndo->ndo_packet_info_stack = ndspi->ndspi_prev; 294c74ad251Schristos 295c74ad251Schristos free(ndspi->ndspi_buffer); 296c74ad251Schristos free(ndspi); 297c74ad251Schristos } 298c74ad251Schristos 299c74ad251Schristos void 300c74ad251Schristos nd_pop_all_packet_info(netdissect_options *ndo) 301c74ad251Schristos { 302c74ad251Schristos while (ndo->ndo_packet_info_stack != NULL) 303c74ad251Schristos nd_pop_packet_info(ndo); 304c74ad251Schristos } 305*26ba0b50Schristos 306*26ba0b50Schristos NORETURN void 307*26ba0b50Schristos nd_trunc_longjmp(netdissect_options *ndo) 308*26ba0b50Schristos { 309*26ba0b50Schristos longjmp(ndo->ndo_early_end, ND_TRUNCATED); 310*26ba0b50Schristos #ifdef _AIX 311*26ba0b50Schristos /* 312*26ba0b50Schristos * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells 313*26ba0b50Schristos * XL C that the function is noreturn, but GCC remains unaware of that and 314*26ba0b50Schristos * yields a "'noreturn' function does return" warning. 315*26ba0b50Schristos */ 316*26ba0b50Schristos ND_UNREACHABLE 317*26ba0b50Schristos #endif /* _AIX */ 318*26ba0b50Schristos } 319