Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1988-1997
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Copyright (c) 1998-2012  Michael Richardson <mcr (at) tcpdump.org>
      6  *      The TCPDUMP project
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that: (1) source code distributions
     10  * retain the above copyright notice and this paragraph in its entirety, (2)
     11  * distributions including binary code include the above copyright notice and
     12  * this paragraph in its entirety in the documentation or other materials
     13  * provided with the distribution, and (3) all advertising materials mentioning
     14  * features or use of this software display the following acknowledgement:
     15  * ``This product includes software developed by the University of California,
     16  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     17  * the University nor the names of its contributors may be used to endorse
     18  * or promote products derived from this software without specific prior
     19  * written permission.
     20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     21  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     23  */
     24 
     25 #include <sys/cdefs.h>
     26 #ifndef lint
     27 __RCSID("$NetBSD: netdissect.c,v 1.4 2024/09/02 16:15:30 christos Exp $");
     28 #endif
     29 
     30 #include <config.h>
     31 
     32 #include "netdissect-stdinc.h"
     33 #include "netdissect.h"
     34 #include <string.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 
     38 #ifdef USE_LIBSMI
     39 #include <smi.h>
     40 #endif
     41 
     42 /*
     43  * Initialize anything that must be initialized before dissecting
     44  * packets.
     45  *
     46  * This should be called at the beginning of the program; it does
     47  * not need to be called, and should not be called, for every
     48  * netdissect_options structure.
     49  */
     50 int
     51 nd_init(char *errbuf, size_t errbuf_size)
     52 {
     53 #ifdef _WIN32
     54 	WORD wVersionRequested;
     55 	WSADATA wsaData;
     56 	int err;
     57 
     58 	/*
     59 	 * Request Winsock 2.2; we expect Winsock 2.
     60 	 */
     61 	wVersionRequested = MAKEWORD(2, 2);
     62 	err = WSAStartup(wVersionRequested, &wsaData);
     63 	if (err != 0) {
     64 		strlcpy(errbuf, "Attempting to initialize Winsock failed",
     65 		    errbuf_size);
     66 		return (-1);
     67 	}
     68 #endif /* _WIN32 */
     69 
     70 #ifdef USE_LIBSMI
     71 	/*
     72 	 * XXX - should we just fail if this fails?  Some of the
     73 	 * libsmi calls may fail.
     74 	 */
     75 	smiInit("tcpdump");
     76 #endif
     77 
     78 	/*
     79 	 * Clears the error buffer, and uses it so we don't get
     80 	 * "unused argument" warnings at compile time.
     81 	 */
     82 	strlcpy(errbuf, "", errbuf_size);
     83 	return (0);
     84 }
     85 
     86 /*
     87  * Clean up anything that ndo_init() did.
     88  */
     89 void
     90 nd_cleanup(void)
     91 {
     92 #ifdef USE_LIBSMI
     93 	/*
     94 	 * This appears, in libsmi 0.4.8, to do nothing if smiInit()
     95 	 * wasn't done or failed, so we call it unconditionally.
     96 	 */
     97 	smiExit();
     98 #endif
     99 
    100 #ifdef _WIN32
    101 	/*
    102 	 * Undo the WSAStartup() call above.
    103 	 */
    104 	WSACleanup();
    105 #endif
    106 }
    107 
    108 int
    109 nd_have_smi_support(void)
    110 {
    111 #ifdef USE_LIBSMI
    112 	return (1);
    113 #else
    114 	return (0);
    115 #endif
    116 }
    117 
    118 /*
    119  * Indicates whether an SMI module has been loaded, so that we can use
    120  * libsmi to translate OIDs.
    121  */
    122 int nd_smi_module_loaded;
    123 
    124 int
    125 nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size)
    126 {
    127 #ifdef USE_LIBSMI
    128 	if (smiLoadModule(module) == 0) {
    129 		snprintf(errbuf, errbuf_size, "could not load MIB module %s",
    130 		    module);
    131 		return (-1);
    132 	}
    133 	nd_smi_module_loaded = 1;
    134 	return (0);
    135 #else
    136 	snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support",
    137 	    module);
    138 	return (-1);
    139 #endif
    140 }
    141 
    142 const char *
    143 nd_smi_version_string(void)
    144 {
    145 #ifdef USE_LIBSMI
    146 	return (smi_version_string);
    147 #else
    148 	return (NULL);
    149 #endif
    150 }
    151 
    152 
    153 int
    154 nd_push_buffer(netdissect_options *ndo, u_char *new_buffer,
    155 	       const u_char *new_packetp, const u_int newlen)
    156 {
    157 	struct netdissect_saved_packet_info *ndspi;
    158 
    159 	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
    160 	if (ndspi == NULL)
    161 		return (0);	/* fail */
    162 	ndspi->ndspi_buffer = new_buffer;
    163 	ndspi->ndspi_packetp = ndo->ndo_packetp;
    164 	ndspi->ndspi_snapend = ndo->ndo_snapend;
    165 	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
    166 
    167 	ndo->ndo_packetp = new_packetp;
    168 	ndo->ndo_snapend = new_packetp + newlen;
    169 	ndo->ndo_packet_info_stack = ndspi;
    170 
    171 	return (1);	/* success */
    172 }
    173 
    174 
    175 /*
    176  * In a given netdissect_options structure:
    177  *
    178  *    push the current packet information onto the packet information
    179  *    stack;
    180  *
    181  *    given a pointer into the packet and a length past that point in
    182  *    the packet, calculate a new snapshot end that's at the lower
    183  *    of the current snapshot end and that point in the packet;
    184  *
    185  *    set the snapshot end to that new value.
    186  */
    187 int
    188 nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
    189 {
    190 	struct netdissect_saved_packet_info *ndspi;
    191 	u_int snaplen_remaining;
    192 
    193 	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
    194 	if (ndspi == NULL)
    195 		return (0);	/* fail */
    196 	ndspi->ndspi_buffer = NULL;	/* no new buffer */
    197 	ndspi->ndspi_packetp = ndo->ndo_packetp;
    198 	ndspi->ndspi_snapend = ndo->ndo_snapend;
    199 	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
    200 
    201 	/*
    202 	 * Push the saved previous data onto the stack.
    203 	 */
    204 	ndo->ndo_packet_info_stack = ndspi;
    205 
    206 	/*
    207 	 * Find out how many bytes remain after the current snapend.
    208 	 *
    209 	 * We're restricted to packets with at most UINT_MAX bytes;
    210 	 * cast the result to u_int, so that we don't get truncation
    211 	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
    212 	 * signed and we want an unsigned difference; the pointer
    213 	 * should at most be equal to snapend, and must *never*
    214 	 * be past snapend.)
    215 	 */
    216 	snaplen_remaining = (u_int)(ndo->ndo_snapend - bp);
    217 
    218 	/*
    219 	 * If the new snapend is smaller than the one calculated
    220 	 * above, set the snapend to that value, otherwise leave
    221 	 * it unchanged.
    222 	 */
    223 	if (newlen <= snaplen_remaining) {
    224 		/* Snapend isn't past the previous snapend */
    225 		ndo->ndo_snapend = bp + newlen;
    226 	}
    227 
    228 	return (1);	/* success */
    229 }
    230 
    231 /*
    232  * In a given netdissect_options structure:
    233  *
    234  *    given a pointer into the packet and a length past that point in
    235  *    the packet, calculate a new snapshot end that's at the lower
    236  *    of the previous snapshot end - or, if there is no previous
    237  *    snapshot end, the current snapshot end - and that point in the
    238  *    packet;
    239  *
    240  *    set the snapshot end to that new value.
    241  *
    242  * This is to change the current snapshot end.  This may increase the
    243  * snapshot end, as it may be used, for example, for a Jumbo Payload
    244  * option in IPv6.  It must not increase it past the snapshot length
    245  * atop which the current one was pushed, however.
    246  */
    247 void
    248 nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
    249 {
    250 	struct netdissect_saved_packet_info *ndspi;
    251 	const u_char *previous_snapend;
    252 	u_int snaplen_remaining;
    253 
    254 	ndspi = ndo->ndo_packet_info_stack;
    255 	if (ndspi->ndspi_prev != NULL)
    256 		previous_snapend = ndspi->ndspi_prev->ndspi_snapend;
    257 	else
    258 		previous_snapend = ndo->ndo_snapend;
    259 
    260 	/*
    261 	 * Find out how many bytes remain after the previous
    262 	 * snapend - or, if there is no previous snapend, after
    263 	 * the current snapend.
    264 	 *
    265 	 * We're restricted to packets with at most UINT_MAX bytes;
    266 	 * cast the result to u_int, so that we don't get truncation
    267 	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
    268 	 * signed and we want an unsigned difference; the pointer
    269 	 * should at most be equal to snapend, and must *never*
    270 	 * be past snapend.)
    271 	 */
    272 	snaplen_remaining = (u_int)(previous_snapend - bp);
    273 
    274 	/*
    275 	 * If the new snapend is smaller than the one calculated
    276 	 * above, set the snapend to that value, otherwise leave
    277 	 * it unchanged.
    278 	 */
    279 	if (newlen <= snaplen_remaining) {
    280 		/* Snapend isn't past the previous snapend */
    281 		ndo->ndo_snapend = bp + newlen;
    282 	}
    283 }
    284 
    285 void
    286 nd_pop_packet_info(netdissect_options *ndo)
    287 {
    288 	struct netdissect_saved_packet_info *ndspi;
    289 
    290 	ndspi = ndo->ndo_packet_info_stack;
    291 	ndo->ndo_packetp = ndspi->ndspi_packetp;
    292 	ndo->ndo_snapend = ndspi->ndspi_snapend;
    293 	ndo->ndo_packet_info_stack = ndspi->ndspi_prev;
    294 
    295 	free(ndspi->ndspi_buffer);
    296 	free(ndspi);
    297 }
    298 
    299 void
    300 nd_pop_all_packet_info(netdissect_options *ndo)
    301 {
    302 	while (ndo->ndo_packet_info_stack != NULL)
    303 		nd_pop_packet_info(ndo);
    304 }
    305 
    306 NORETURN void
    307 nd_trunc_longjmp(netdissect_options *ndo)
    308 {
    309 	longjmp(ndo->ndo_early_end, ND_TRUNCATED);
    310 #ifdef _AIX
    311 	/*
    312 	 * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells
    313 	 * XL C that the function is noreturn, but GCC remains unaware of that and
    314 	 * yields a "'noreturn' function does return" warning.
    315 	 */
    316 	ND_UNREACHABLE
    317 #endif /* _AIX */
    318 }
    319