xref: /freebsd-src/contrib/tcpdump/netdissect.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
13340d773SGleb Smirnoff /*
23340d773SGleb Smirnoff  * Copyright (c) 1988-1997
33340d773SGleb Smirnoff  *	The Regents of the University of California.  All rights reserved.
43340d773SGleb Smirnoff  *
53340d773SGleb Smirnoff  * Copyright (c) 1998-2012  Michael Richardson <mcr@tcpdump.org>
63340d773SGleb Smirnoff  *      The TCPDUMP project
73340d773SGleb Smirnoff  *
83340d773SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
93340d773SGleb Smirnoff  * modification, are permitted provided that: (1) source code distributions
103340d773SGleb Smirnoff  * retain the above copyright notice and this paragraph in its entirety, (2)
113340d773SGleb Smirnoff  * distributions including binary code include the above copyright notice and
123340d773SGleb Smirnoff  * this paragraph in its entirety in the documentation or other materials
133340d773SGleb Smirnoff  * provided with the distribution, and (3) all advertising materials mentioning
143340d773SGleb Smirnoff  * features or use of this software display the following acknowledgement:
153340d773SGleb Smirnoff  * ``This product includes software developed by the University of California,
163340d773SGleb Smirnoff  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
173340d773SGleb Smirnoff  * the University nor the names of its contributors may be used to endorse
183340d773SGleb Smirnoff  * or promote products derived from this software without specific prior
193340d773SGleb Smirnoff  * written permission.
203340d773SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
213340d773SGleb Smirnoff  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
223340d773SGleb Smirnoff  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
233340d773SGleb Smirnoff  */
243340d773SGleb Smirnoff 
25ee67461eSJoseph Mingrone #include <config.h>
263340d773SGleb Smirnoff 
27ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
283340d773SGleb Smirnoff #include "netdissect.h"
293340d773SGleb Smirnoff #include <string.h>
303340d773SGleb Smirnoff #include <stdio.h>
31ee67461eSJoseph Mingrone #include <stdlib.h>
323340d773SGleb Smirnoff 
333340d773SGleb Smirnoff #ifdef USE_LIBSMI
343340d773SGleb Smirnoff #include <smi.h>
353340d773SGleb Smirnoff #endif
363340d773SGleb Smirnoff 
373340d773SGleb Smirnoff /*
383340d773SGleb Smirnoff  * Initialize anything that must be initialized before dissecting
393340d773SGleb Smirnoff  * packets.
403340d773SGleb Smirnoff  *
413340d773SGleb Smirnoff  * This should be called at the beginning of the program; it does
423340d773SGleb Smirnoff  * not need to be called, and should not be called, for every
433340d773SGleb Smirnoff  * netdissect_options structure.
443340d773SGleb Smirnoff  */
453340d773SGleb Smirnoff int
463340d773SGleb Smirnoff nd_init(char *errbuf, size_t errbuf_size)
473340d773SGleb Smirnoff {
483340d773SGleb Smirnoff #ifdef _WIN32
493340d773SGleb Smirnoff 	WORD wVersionRequested;
503340d773SGleb Smirnoff 	WSADATA wsaData;
513340d773SGleb Smirnoff 	int err;
523340d773SGleb Smirnoff 
533340d773SGleb Smirnoff 	/*
543340d773SGleb Smirnoff 	 * Request Winsock 2.2; we expect Winsock 2.
553340d773SGleb Smirnoff 	 */
563340d773SGleb Smirnoff 	wVersionRequested = MAKEWORD(2, 2);
573340d773SGleb Smirnoff 	err = WSAStartup(wVersionRequested, &wsaData);
583340d773SGleb Smirnoff 	if (err != 0) {
593340d773SGleb Smirnoff 		strlcpy(errbuf, "Attempting to initialize Winsock failed",
603340d773SGleb Smirnoff 		    errbuf_size);
613340d773SGleb Smirnoff 		return (-1);
623340d773SGleb Smirnoff 	}
633340d773SGleb Smirnoff #endif /* _WIN32 */
643340d773SGleb Smirnoff 
653340d773SGleb Smirnoff #ifdef USE_LIBSMI
663340d773SGleb Smirnoff 	/*
673340d773SGleb Smirnoff 	 * XXX - should we just fail if this fails?  Some of the
683340d773SGleb Smirnoff 	 * libsmi calls may fail.
693340d773SGleb Smirnoff 	 */
703340d773SGleb Smirnoff 	smiInit("tcpdump");
713340d773SGleb Smirnoff #endif
723340d773SGleb Smirnoff 
733340d773SGleb Smirnoff 	/*
743340d773SGleb Smirnoff 	 * Clears the error buffer, and uses it so we don't get
753340d773SGleb Smirnoff 	 * "unused argument" warnings at compile time.
763340d773SGleb Smirnoff 	 */
773340d773SGleb Smirnoff 	strlcpy(errbuf, "", errbuf_size);
783340d773SGleb Smirnoff 	return (0);
793340d773SGleb Smirnoff }
803340d773SGleb Smirnoff 
813340d773SGleb Smirnoff /*
823340d773SGleb Smirnoff  * Clean up anything that ndo_init() did.
833340d773SGleb Smirnoff  */
843340d773SGleb Smirnoff void
853340d773SGleb Smirnoff nd_cleanup(void)
863340d773SGleb Smirnoff {
873340d773SGleb Smirnoff #ifdef USE_LIBSMI
883340d773SGleb Smirnoff 	/*
893340d773SGleb Smirnoff 	 * This appears, in libsmi 0.4.8, to do nothing if smiInit()
903340d773SGleb Smirnoff 	 * wasn't done or failed, so we call it unconditionally.
913340d773SGleb Smirnoff 	 */
923340d773SGleb Smirnoff 	smiExit();
933340d773SGleb Smirnoff #endif
943340d773SGleb Smirnoff 
953340d773SGleb Smirnoff #ifdef _WIN32
963340d773SGleb Smirnoff 	/*
973340d773SGleb Smirnoff 	 * Undo the WSAStartup() call above.
983340d773SGleb Smirnoff 	 */
993340d773SGleb Smirnoff 	WSACleanup();
1003340d773SGleb Smirnoff #endif
1013340d773SGleb Smirnoff }
1023340d773SGleb Smirnoff 
1033340d773SGleb Smirnoff int
1043340d773SGleb Smirnoff nd_have_smi_support(void)
1053340d773SGleb Smirnoff {
1063340d773SGleb Smirnoff #ifdef USE_LIBSMI
1073340d773SGleb Smirnoff 	return (1);
1083340d773SGleb Smirnoff #else
1093340d773SGleb Smirnoff 	return (0);
1103340d773SGleb Smirnoff #endif
1113340d773SGleb Smirnoff }
1123340d773SGleb Smirnoff 
1133340d773SGleb Smirnoff /*
1143340d773SGleb Smirnoff  * Indicates whether an SMI module has been loaded, so that we can use
1153340d773SGleb Smirnoff  * libsmi to translate OIDs.
1163340d773SGleb Smirnoff  */
1173340d773SGleb Smirnoff int nd_smi_module_loaded;
1183340d773SGleb Smirnoff 
1193340d773SGleb Smirnoff int
1203340d773SGleb Smirnoff nd_load_smi_module(const char *module, char *errbuf, size_t errbuf_size)
1213340d773SGleb Smirnoff {
1223340d773SGleb Smirnoff #ifdef USE_LIBSMI
1233340d773SGleb Smirnoff 	if (smiLoadModule(module) == 0) {
1243340d773SGleb Smirnoff 		snprintf(errbuf, errbuf_size, "could not load MIB module %s",
1253340d773SGleb Smirnoff 		    module);
1263340d773SGleb Smirnoff 		return (-1);
1273340d773SGleb Smirnoff 	}
1283340d773SGleb Smirnoff 	nd_smi_module_loaded = 1;
1293340d773SGleb Smirnoff 	return (0);
1303340d773SGleb Smirnoff #else
1313340d773SGleb Smirnoff 	snprintf(errbuf, errbuf_size, "MIB module %s not loaded: no libsmi support",
1323340d773SGleb Smirnoff 	    module);
1333340d773SGleb Smirnoff 	return (-1);
1343340d773SGleb Smirnoff #endif
1353340d773SGleb Smirnoff }
1363340d773SGleb Smirnoff 
1373340d773SGleb Smirnoff const char *
1383340d773SGleb Smirnoff nd_smi_version_string(void)
1393340d773SGleb Smirnoff {
1403340d773SGleb Smirnoff #ifdef USE_LIBSMI
1413340d773SGleb Smirnoff 	return (smi_version_string);
1423340d773SGleb Smirnoff #else
1433340d773SGleb Smirnoff 	return (NULL);
1443340d773SGleb Smirnoff #endif
1453340d773SGleb Smirnoff }
146ee67461eSJoseph Mingrone 
147ee67461eSJoseph Mingrone 
148ee67461eSJoseph Mingrone int
149ee67461eSJoseph Mingrone nd_push_buffer(netdissect_options *ndo, u_char *new_buffer,
150ee67461eSJoseph Mingrone 	       const u_char *new_packetp, const u_int newlen)
151ee67461eSJoseph Mingrone {
152ee67461eSJoseph Mingrone 	struct netdissect_saved_packet_info *ndspi;
153ee67461eSJoseph Mingrone 
154ee67461eSJoseph Mingrone 	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
155ee67461eSJoseph Mingrone 	if (ndspi == NULL)
156ee67461eSJoseph Mingrone 		return (0);	/* fail */
157ee67461eSJoseph Mingrone 	ndspi->ndspi_buffer = new_buffer;
158ee67461eSJoseph Mingrone 	ndspi->ndspi_packetp = ndo->ndo_packetp;
159ee67461eSJoseph Mingrone 	ndspi->ndspi_snapend = ndo->ndo_snapend;
160ee67461eSJoseph Mingrone 	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
161ee67461eSJoseph Mingrone 
162ee67461eSJoseph Mingrone 	ndo->ndo_packetp = new_packetp;
163ee67461eSJoseph Mingrone 	ndo->ndo_snapend = new_packetp + newlen;
164ee67461eSJoseph Mingrone 	ndo->ndo_packet_info_stack = ndspi;
165ee67461eSJoseph Mingrone 
166ee67461eSJoseph Mingrone 	return (1);	/* success */
167ee67461eSJoseph Mingrone }
168ee67461eSJoseph Mingrone 
169ee67461eSJoseph Mingrone 
170ee67461eSJoseph Mingrone /*
171ee67461eSJoseph Mingrone  * In a given netdissect_options structure:
172ee67461eSJoseph Mingrone  *
173ee67461eSJoseph Mingrone  *    push the current packet information onto the packet information
174ee67461eSJoseph Mingrone  *    stack;
175ee67461eSJoseph Mingrone  *
176ee67461eSJoseph Mingrone  *    given a pointer into the packet and a length past that point in
177ee67461eSJoseph Mingrone  *    the packet, calculate a new snapshot end that's at the lower
178ee67461eSJoseph Mingrone  *    of the current snapshot end and that point in the packet;
179ee67461eSJoseph Mingrone  *
180ee67461eSJoseph Mingrone  *    set the snapshot end to that new value.
181ee67461eSJoseph Mingrone  */
182ee67461eSJoseph Mingrone int
183ee67461eSJoseph Mingrone nd_push_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
184ee67461eSJoseph Mingrone {
185ee67461eSJoseph Mingrone 	struct netdissect_saved_packet_info *ndspi;
186ee67461eSJoseph Mingrone 	u_int snaplen_remaining;
187ee67461eSJoseph Mingrone 
188ee67461eSJoseph Mingrone 	ndspi = (struct netdissect_saved_packet_info *)malloc(sizeof(struct netdissect_saved_packet_info));
189ee67461eSJoseph Mingrone 	if (ndspi == NULL)
190ee67461eSJoseph Mingrone 		return (0);	/* fail */
191ee67461eSJoseph Mingrone 	ndspi->ndspi_buffer = NULL;	/* no new buffer */
192ee67461eSJoseph Mingrone 	ndspi->ndspi_packetp = ndo->ndo_packetp;
193ee67461eSJoseph Mingrone 	ndspi->ndspi_snapend = ndo->ndo_snapend;
194ee67461eSJoseph Mingrone 	ndspi->ndspi_prev = ndo->ndo_packet_info_stack;
195ee67461eSJoseph Mingrone 
196ee67461eSJoseph Mingrone 	/*
197ee67461eSJoseph Mingrone 	 * Push the saved previous data onto the stack.
198ee67461eSJoseph Mingrone 	 */
199ee67461eSJoseph Mingrone 	ndo->ndo_packet_info_stack = ndspi;
200ee67461eSJoseph Mingrone 
201ee67461eSJoseph Mingrone 	/*
202ee67461eSJoseph Mingrone 	 * Find out how many bytes remain after the current snapend.
203ee67461eSJoseph Mingrone 	 *
204ee67461eSJoseph Mingrone 	 * We're restricted to packets with at most UINT_MAX bytes;
205ee67461eSJoseph Mingrone 	 * cast the result to u_int, so that we don't get truncation
206ee67461eSJoseph Mingrone 	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
207ee67461eSJoseph Mingrone 	 * signed and we want an unsigned difference; the pointer
208ee67461eSJoseph Mingrone 	 * should at most be equal to snapend, and must *never*
209ee67461eSJoseph Mingrone 	 * be past snapend.)
210ee67461eSJoseph Mingrone 	 */
211ee67461eSJoseph Mingrone 	snaplen_remaining = (u_int)(ndo->ndo_snapend - bp);
212ee67461eSJoseph Mingrone 
213ee67461eSJoseph Mingrone 	/*
214ee67461eSJoseph Mingrone 	 * If the new snapend is smaller than the one calculated
215ee67461eSJoseph Mingrone 	 * above, set the snapend to that value, otherwise leave
216ee67461eSJoseph Mingrone 	 * it unchanged.
217ee67461eSJoseph Mingrone 	 */
218ee67461eSJoseph Mingrone 	if (newlen <= snaplen_remaining) {
219ee67461eSJoseph Mingrone 		/* Snapend isn't past the previous snapend */
220ee67461eSJoseph Mingrone 		ndo->ndo_snapend = bp + newlen;
221ee67461eSJoseph Mingrone 	}
222ee67461eSJoseph Mingrone 
223ee67461eSJoseph Mingrone 	return (1);	/* success */
224ee67461eSJoseph Mingrone }
225ee67461eSJoseph Mingrone 
226ee67461eSJoseph Mingrone /*
227ee67461eSJoseph Mingrone  * In a given netdissect_options structure:
228ee67461eSJoseph Mingrone  *
229ee67461eSJoseph Mingrone  *    given a pointer into the packet and a length past that point in
230ee67461eSJoseph Mingrone  *    the packet, calculate a new snapshot end that's at the lower
231ee67461eSJoseph Mingrone  *    of the previous snapshot end - or, if there is no previous
232ee67461eSJoseph Mingrone  *    snapshot end, the current snapshot end - and that point in the
233ee67461eSJoseph Mingrone  *    packet;
234ee67461eSJoseph Mingrone  *
235ee67461eSJoseph Mingrone  *    set the snapshot end to that new value.
236ee67461eSJoseph Mingrone  *
237ee67461eSJoseph Mingrone  * This is to change the current snapshot end.  This may increase the
238ee67461eSJoseph Mingrone  * snapshot end, as it may be used, for example, for a Jumbo Payload
239ee67461eSJoseph Mingrone  * option in IPv6.  It must not increase it past the snapshot length
240ee67461eSJoseph Mingrone  * atop which the current one was pushed, however.
241ee67461eSJoseph Mingrone  */
242ee67461eSJoseph Mingrone void
243ee67461eSJoseph Mingrone nd_change_snaplen(netdissect_options *ndo, const u_char *bp, const u_int newlen)
244ee67461eSJoseph Mingrone {
245ee67461eSJoseph Mingrone 	struct netdissect_saved_packet_info *ndspi;
246ee67461eSJoseph Mingrone 	const u_char *previous_snapend;
247ee67461eSJoseph Mingrone 	u_int snaplen_remaining;
248ee67461eSJoseph Mingrone 
249ee67461eSJoseph Mingrone 	ndspi = ndo->ndo_packet_info_stack;
250ee67461eSJoseph Mingrone 	if (ndspi->ndspi_prev != NULL)
251ee67461eSJoseph Mingrone 		previous_snapend = ndspi->ndspi_prev->ndspi_snapend;
252ee67461eSJoseph Mingrone 	else
253ee67461eSJoseph Mingrone 		previous_snapend = ndo->ndo_snapend;
254ee67461eSJoseph Mingrone 
255ee67461eSJoseph Mingrone 	/*
256ee67461eSJoseph Mingrone 	 * Find out how many bytes remain after the previous
257ee67461eSJoseph Mingrone 	 * snapend - or, if there is no previous snapend, after
258ee67461eSJoseph Mingrone 	 * the current snapend.
259ee67461eSJoseph Mingrone 	 *
260ee67461eSJoseph Mingrone 	 * We're restricted to packets with at most UINT_MAX bytes;
261ee67461eSJoseph Mingrone 	 * cast the result to u_int, so that we don't get truncation
262ee67461eSJoseph Mingrone 	 * warnings on LP64 and LLP64 platforms.  (ptrdiff_t is
263ee67461eSJoseph Mingrone 	 * signed and we want an unsigned difference; the pointer
264ee67461eSJoseph Mingrone 	 * should at most be equal to snapend, and must *never*
265ee67461eSJoseph Mingrone 	 * be past snapend.)
266ee67461eSJoseph Mingrone 	 */
267ee67461eSJoseph Mingrone 	snaplen_remaining = (u_int)(previous_snapend - bp);
268ee67461eSJoseph Mingrone 
269ee67461eSJoseph Mingrone 	/*
270ee67461eSJoseph Mingrone 	 * If the new snapend is smaller than the one calculated
271ee67461eSJoseph Mingrone 	 * above, set the snapend to that value, otherwise leave
272ee67461eSJoseph Mingrone 	 * it unchanged.
273ee67461eSJoseph Mingrone 	 */
274ee67461eSJoseph Mingrone 	if (newlen <= snaplen_remaining) {
275ee67461eSJoseph Mingrone 		/* Snapend isn't past the previous snapend */
276ee67461eSJoseph Mingrone 		ndo->ndo_snapend = bp + newlen;
277ee67461eSJoseph Mingrone 	}
278ee67461eSJoseph Mingrone }
279ee67461eSJoseph Mingrone 
280ee67461eSJoseph Mingrone void
281ee67461eSJoseph Mingrone nd_pop_packet_info(netdissect_options *ndo)
282ee67461eSJoseph Mingrone {
283ee67461eSJoseph Mingrone 	struct netdissect_saved_packet_info *ndspi;
284ee67461eSJoseph Mingrone 
285ee67461eSJoseph Mingrone 	ndspi = ndo->ndo_packet_info_stack;
286ee67461eSJoseph Mingrone 	ndo->ndo_packetp = ndspi->ndspi_packetp;
287ee67461eSJoseph Mingrone 	ndo->ndo_snapend = ndspi->ndspi_snapend;
288ee67461eSJoseph Mingrone 	ndo->ndo_packet_info_stack = ndspi->ndspi_prev;
289ee67461eSJoseph Mingrone 
290ee67461eSJoseph Mingrone 	free(ndspi->ndspi_buffer);
291ee67461eSJoseph Mingrone 	free(ndspi);
292ee67461eSJoseph Mingrone }
293ee67461eSJoseph Mingrone 
294ee67461eSJoseph Mingrone void
295ee67461eSJoseph Mingrone nd_pop_all_packet_info(netdissect_options *ndo)
296ee67461eSJoseph Mingrone {
297ee67461eSJoseph Mingrone 	while (ndo->ndo_packet_info_stack != NULL)
298ee67461eSJoseph Mingrone 		nd_pop_packet_info(ndo);
299ee67461eSJoseph Mingrone }
300*0a7e5f1fSJoseph Mingrone 
301*0a7e5f1fSJoseph Mingrone NORETURN void
302*0a7e5f1fSJoseph Mingrone nd_trunc_longjmp(netdissect_options *ndo)
303*0a7e5f1fSJoseph Mingrone {
304*0a7e5f1fSJoseph Mingrone 	longjmp(ndo->ndo_early_end, ND_TRUNCATED);
305*0a7e5f1fSJoseph Mingrone #ifdef _AIX
306*0a7e5f1fSJoseph Mingrone 	/*
307*0a7e5f1fSJoseph Mingrone 	 * In AIX <setjmp.h> decorates longjmp() with "#pragma leaves", which tells
308*0a7e5f1fSJoseph Mingrone 	 * XL C that the function is noreturn, but GCC remains unaware of that and
309*0a7e5f1fSJoseph Mingrone 	 * yields a "'noreturn' function does return" warning.
310*0a7e5f1fSJoseph Mingrone 	 */
311*0a7e5f1fSJoseph Mingrone 	ND_UNREACHABLE
312*0a7e5f1fSJoseph Mingrone #endif /* _AIX */
313*0a7e5f1fSJoseph Mingrone }
314