Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /* |
2 | * $Id: libnet_pkt.c,v 1.19 2005/11/29 22:48:29 carlosc Exp $ | |
3 | * | |
4 | * libnet | |
5 | * libnet_pkt.c - routines. | |
6 | * | |
7 | * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com> | |
8 | * All rights reserved. | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | |
30 | * | |
31 | */ | |
32 | ||
33 | #if (HAVE_CONFIG_H) | |
34 | #include "../include/config.h" | |
35 | #endif | |
36 | #if (!(_WIN32) || (__CYGWIN__)) | |
37 | #include "../include/libnet.h" | |
38 | #else | |
39 | #include "../include/win32/libnet.h" | |
40 | #endif | |
41 | ||
42 | libnet_t * | |
43 | libnet_init_pkt(int injection_type, char *device, char *err_buf) | |
44 | { | |
45 | libnet_t *l = NULL; | |
46 | ||
47 | #if 0 | |
48 | #if !defined(__WIN32__) | |
49 | if (getuid() && geteuid()) | |
50 | { | |
51 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, | |
52 | "%s(): UID or EUID of 0 required\n", __func__); | |
53 | goto bad; | |
54 | } | |
55 | #else | |
56 | WSADATA wsaData; | |
57 | ||
58 | if ((WSAStartup(0x0202, &wsaData)) != 0) | |
59 | { | |
60 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, | |
61 | "%s(): unable to initialize winsock 2\n", __func__); | |
62 | goto bad; | |
63 | } | |
64 | #endif | |
65 | #endif | |
66 | ||
67 | l = (libnet_t *)malloc(sizeof (libnet_t)); | |
68 | if (l == NULL) | |
69 | { | |
70 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", __func__, | |
71 | strerror(errno)); | |
72 | goto bad; | |
73 | } | |
74 | ||
75 | memset(l, 0, sizeof (*l)); | |
76 | ||
77 | l->injection_type = injection_type; | |
78 | l->ptag_state = LIBNET_PTAG_INITIALIZER; | |
79 | l->device = (device ? strdup(device) : NULL); | |
80 | ||
81 | strncpy(l->label, LIBNET_LABEL_DEFAULT, LIBNET_LABEL_SIZE); | |
82 | l->label[sizeof(l->label)] = '\0'; | |
83 | ||
84 | #if 0 | |
85 | switch (l->injection_type) | |
86 | { | |
87 | case LIBNET_LINK: | |
88 | case LIBNET_LINK_ADV: | |
89 | if (libnet_select_device(l) == -1) | |
90 | { | |
91 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, l->err_buf); | |
92 | goto bad; | |
93 | } | |
94 | if (libnet_open_link(l) == -1) | |
95 | { | |
96 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, l->err_buf); | |
97 | goto bad; | |
98 | } | |
99 | break; | |
100 | case LIBNET_RAW4: | |
101 | case LIBNET_RAW4_ADV: | |
102 | if (libnet_open_raw4(l) == -1) | |
103 | { | |
104 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, l->err_buf); | |
105 | goto bad; | |
106 | } | |
107 | break; | |
108 | case LIBNET_RAW6: | |
109 | case LIBNET_RAW6_ADV: | |
110 | if (libnet_open_raw6(l) == -1) | |
111 | { | |
112 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, l->err_buf); | |
113 | goto bad; | |
114 | } | |
115 | break; | |
116 | default: | |
117 | snprintf(err_buf, LIBNET_ERRBUF_SIZE, | |
118 | "%s(): unsupported injection type\n", __func__); | |
119 | goto bad; | |
120 | break; | |
121 | } | |
122 | #endif | |
123 | ||
124 | return (l); | |
125 | ||
126 | bad: | |
127 | if (l) | |
128 | { | |
129 | libnet_destroy(l); | |
130 | } | |
131 | return (NULL); | |
132 | } | |
133 | ||
134 | ||
135 | ||
136 | int | |
137 | libnet_pblock_coalesce_pkt(libnet_t *l, u_int8_t **packet, u_int32_t *size, u_int32_t align); | |
138 | ||
139 | void | |
140 | libnet_print_pkt(u_int8_t *pktbuf, u_int32_t pktlen) | |
141 | { | |
142 | int i; | |
143 | ||
144 | fprintf(stderr, "pktbuf = 0x%p, pktlen = %d\n", pktbuf, pktlen); | |
145 | for (i=0; i<pktlen; i++) { | |
146 | if(!(i%16)) fprintf (stderr,"\n %06d\t\t",i); | |
147 | fprintf(stderr,"%02x ", pktbuf[i]); | |
148 | } | |
149 | fprintf (stderr,"\n"); | |
150 | } | |
151 | ||
152 | ||
153 | int | |
154 | libnet_write_pkt(libnet_t *l, u_int8_t **packet, u_int32_t *len, u_int32_t align) | |
155 | { | |
156 | int c; | |
157 | #if 0 | |
158 | u_int32_t len; | |
159 | u_int8_t *packet = NULL; | |
160 | #endif | |
161 | ||
162 | if (l == NULL) | |
163 | { | |
164 | return (-1); | |
165 | } | |
166 | ||
167 | c = libnet_pblock_coalesce_pkt(l, packet, len, align); | |
168 | if (c == - 1) | |
169 | { | |
170 | /* err msg set in libnet_pblock_coalesce() */ | |
171 | return (-1); | |
172 | } | |
173 | ||
174 | #if 0 | |
175 | /* assume error */ | |
176 | c = -1; | |
177 | switch (l->injection_type) | |
178 | { | |
179 | case LIBNET_RAW4: | |
180 | case LIBNET_RAW4_ADV: | |
181 | if (len > LIBNET_MAX_PACKET) | |
182 | { | |
183 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
184 | "%s(): packet is too large (%d bytes)\n", | |
185 | __func__, len); | |
186 | goto done; | |
187 | } | |
188 | c = libnet_write_raw_ipv4(l, packet, len); | |
189 | break; | |
190 | case LIBNET_RAW6: | |
191 | case LIBNET_RAW6_ADV: | |
192 | c = libnet_write_raw_ipv6(l, packet, len); | |
193 | break; | |
194 | case LIBNET_LINK: | |
195 | case LIBNET_LINK_ADV: | |
196 | c = libnet_write_link(l, packet, len); | |
197 | break; | |
198 | default: | |
199 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
200 | "%s(): unsuported injection type\n", __func__); | |
201 | goto done; | |
202 | } | |
203 | #endif | |
204 | ||
205 | /* do statistics */ | |
206 | if (c == *len) | |
207 | { | |
208 | l->stats.packets_sent++; | |
209 | l->stats.bytes_written += c; | |
210 | } | |
211 | else | |
212 | { | |
213 | l->stats.packet_errors++; | |
214 | /* | |
215 | * XXX - we probably should have a way to retrieve the number of | |
216 | * bytes actually written (since we might have written something). | |
217 | */ | |
218 | if (c > 0) | |
219 | { | |
220 | l->stats.bytes_written += c; | |
221 | } | |
222 | } | |
223 | done: | |
224 | #if 0 | |
225 | /* | |
226 | * Restore original pointer address so free won't complain about a | |
227 | * modified chunk pointer. | |
228 | */ | |
229 | if (l->aligner > 0) | |
230 | { | |
231 | *packet = *packet - l->aligner; | |
232 | } | |
233 | ||
234 | free(packet); | |
235 | #endif | |
236 | return (c); | |
237 | } | |
238 | ||
239 | ||
240 | int | |
241 | libnet_pblock_coalesce_pkt(libnet_t *l, u_int8_t **packet, u_int32_t *size, u_int32_t align) | |
242 | { | |
243 | libnet_pblock_t *p, *q; | |
244 | u_int32_t c, n; | |
245 | ||
246 | /* | |
247 | * Determine the offset required to keep memory aligned (strict | |
248 | * architectures like solaris enforce this, but's a good practice | |
249 | * either way). This is only required on the link layer with the | |
250 | * 14 byte ethernet offset (others are similarly unkind). | |
251 | */ | |
252 | #if 1 | |
253 | if (l->injection_type == LIBNET_LINK || | |
254 | l->injection_type == LIBNET_LINK_ADV) | |
255 | { | |
256 | /* 8 byte alignment should work */ | |
257 | if (align) | |
258 | l->aligner = align - (l->link_offset % align); | |
259 | else | |
260 | l->aligner = 0; | |
261 | } | |
262 | else | |
263 | { | |
264 | l->aligner = 0; | |
265 | } | |
266 | #else | |
267 | l->aligner = align; | |
268 | #endif | |
269 | ||
270 | /********** fprintf(stderr, "libnet_pblock_coalesce_pkt: aligner = %d\n", l->aligner);***/ | |
271 | ||
272 | *packet = malloc(l->aligner + l->total_size); | |
273 | if (*packet == NULL) | |
274 | { | |
275 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n", | |
276 | __func__, strerror(errno)); | |
277 | return (-1); | |
278 | } | |
279 | ||
280 | memset(*packet, 0, l->aligner + l->total_size); | |
281 | ||
282 | if (l->injection_type == LIBNET_RAW4 && | |
283 | l->pblock_end->type == LIBNET_PBLOCK_IPV4_H) | |
284 | { | |
285 | libnet_pblock_setflags(l->pblock_end, LIBNET_PBLOCK_DO_CHECKSUM); | |
286 | #if 0 | |
287 | libnet_pblock_setflags(l->pblock_end, 0x0); | |
288 | #endif | |
289 | } | |
290 | ||
291 | /* additional sanity checks to perform if we're not in advanced mode */ | |
292 | if (!(l->injection_type & LIBNET_ADV_MASK)) | |
293 | { | |
294 | switch (l->injection_type) | |
295 | { | |
296 | case LIBNET_LINK: | |
297 | if ((l->pblock_end->type != LIBNET_PBLOCK_TOKEN_RING_H) && | |
298 | (l->pblock_end->type != LIBNET_PBLOCK_FDDI_H) && | |
299 | (l->pblock_end->type != LIBNET_PBLOCK_ETH_H) && | |
300 | (l->pblock_end->type != LIBNET_PBLOCK_802_1Q_H) && | |
301 | (l->pblock_end->type != LIBNET_PBLOCK_ISL_H) && | |
302 | (l->pblock_end->type != LIBNET_PBLOCK_802_3_H)) | |
303 | { | |
304 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
305 | "%s(): packet assembly cannot find a layer 2 header\n", | |
306 | __func__); | |
307 | return (-1); | |
308 | } | |
309 | break; | |
310 | case LIBNET_RAW4: | |
311 | if ((l->pblock_end->type != LIBNET_PBLOCK_IPV4_H)) | |
312 | { | |
313 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
314 | "%s(): packet assembly cannot find an IPv4 header\n", | |
315 | __func__); | |
316 | return (-1); | |
317 | } | |
318 | break; | |
319 | case LIBNET_RAW6: | |
320 | if ((l->pblock_end->type != LIBNET_PBLOCK_IPV6_H)) | |
321 | { | |
322 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
323 | "%s(): packet assembly cannot find an IPv6 header\n", | |
324 | __func__); | |
325 | return (-1); | |
326 | } | |
327 | break; | |
328 | default: | |
329 | /* we should not end up here ever */ | |
330 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
331 | "%s(): suddenly the dungeon collapses -- you die\n", | |
332 | __func__); | |
333 | return (-1); | |
334 | break; | |
335 | } | |
336 | } | |
337 | ||
338 | q = NULL; | |
339 | for (n = l->aligner + l->total_size, p = l->protocol_blocks; p || q; ) | |
340 | { | |
341 | ||
342 | if (q) | |
343 | { | |
344 | p = p->next; | |
345 | } | |
346 | #if 0 | |
347 | if (p != NULL) { | |
348 | /***********/fprintf(stderr, "libnet_pblock_coalesce_pkt: p(%d) proto=%d, p->next(%d)\n", p, libnet_pblock_p2p(p->type), p->next); | |
349 | } else { | |
350 | fprintf(stderr, "libnet_pblock_coalesce_pkt: p is null"); | |
351 | } | |
352 | #endif | |
353 | if (p) | |
354 | { | |
355 | n -= p->b_len; | |
356 | /* copy over the packet chunk */ | |
357 | memcpy(*packet + n, p->buf, p->b_len); | |
358 | /*************fprintf(stderr, "libnet_pblock_coalesce_pkt: Copying over %d bytes from the end\n", p->b_len);*/ | |
359 | } | |
360 | if (q) | |
361 | { | |
362 | if (p == NULL || ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)) | |
363 | #if 0 | |
364 | if (p == NULL || ((p->flags) & 0x0)) | |
365 | #endif | |
366 | { | |
367 | if ((q->flags) & LIBNET_PBLOCK_DO_CHECKSUM) | |
368 | #if 0 | |
369 | if ((q->flags) & 0x0) | |
370 | #endif | |
371 | { | |
372 | int offset = (l->total_size + l->aligner) - q->ip_offset; | |
373 | /******fprintf(stderr, "libnet_pblock_coalesce_pkt: Calling libnet_do_checksum with the packet offset set at %d, ip_offset being %d, and buf %d, proto %d, len %d\n", offset, q->ip_offset, (unsigned int)(*packet + offset), libnet_pblock_p2p(q->type), q->h_len);*/ | |
374 | ||
375 | c = libnet_do_checksum(l, *packet + offset, | |
376 | libnet_pblock_p2p(q->type), q->h_len); | |
377 | if (c == -1) | |
378 | { | |
379 | /* err msg set in libnet_do_checksum() */ | |
380 | return (-1); | |
381 | } | |
382 | } | |
383 | q = p; | |
384 | } | |
385 | } | |
386 | else | |
387 | { | |
388 | q = p; | |
389 | } | |
390 | } | |
391 | *size = l->aligner + l->total_size; | |
392 | ||
393 | /* | |
394 | * Set the packet pointer to the true beginning of the packet and set | |
395 | * the size for transmission. | |
396 | */ | |
397 | if ((l->injection_type == LIBNET_LINK || | |
398 | l->injection_type == LIBNET_LINK_ADV) && l->aligner) | |
399 | { | |
400 | *packet += l->aligner; | |
401 | *size -= l->aligner; | |
402 | } | |
403 | #if 0 | |
404 | return (1); | |
405 | #endif | |
406 | return (*size); | |
407 | } | |
408 | ||
409 | /* EOF */ |