xref: /netbsd-src/external/bsd/tcpdump/dist/netdissect.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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