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@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
nd_init(char * errbuf,size_t errbuf_size)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
nd_cleanup(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
nd_have_smi_support(void)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
nd_load_smi_module(const char * module,char * errbuf,size_t errbuf_size)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 *
nd_smi_version_string(void)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
nd_push_buffer(netdissect_options * ndo,u_char * new_buffer,const u_char * new_packetp,const u_int newlen)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
nd_push_snaplen(netdissect_options * ndo,const u_char * bp,const u_int newlen)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
nd_change_snaplen(netdissect_options * ndo,const u_char * bp,const u_int newlen)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
nd_pop_packet_info(netdissect_options * ndo)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
nd_pop_all_packet_info(netdissect_options * ndo)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
nd_trunc_longjmp(netdissect_options * ndo)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