Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | /* |
2 | * $Id: libnet_write.c,v 1.21 2005/11/29 21:52:41 carlosc Exp $ | |
3 | * | |
4 | * libnet | |
5 | * libnet_write.c - writes a prebuilt packet to the network | |
6 | * | |
7 | * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com> | |
8 | * All rights reserved. | |
9 | * win32 specific code | |
10 | * Copyright (c) 2002 - 2003 Roberto Larcher <roberto.larcher@libero.it> | |
11 | * | |
12 | * Redistribution and use in source and binary forms, with or without | |
13 | * modification, are permitted provided that the following conditions | |
14 | * are met: | |
15 | * 1. Redistributions of source code must retain the above copyright | |
16 | * notice, this list of conditions and the following disclaimer. | |
17 | * 2. Redistributions in binary form must reproduce the above copyright | |
18 | * notice, this list of conditions and the following disclaimer in the | |
19 | * documentation and/or other materials provided with the distribution. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | */ | |
34 | ||
35 | #if (HAVE_CONFIG_H) | |
36 | #include "../include/config.h" | |
37 | #endif | |
38 | #if (!(_WIN32) || (__CYGWIN__)) | |
39 | #include "../include/libnet.h" | |
40 | #else | |
41 | #include "../include/win32/libnet.h" | |
42 | #include "../include/win32/config.h" | |
43 | #include "packet32.h" | |
44 | #include "Ntddndis.h" | |
45 | #endif | |
46 | ||
47 | int | |
48 | libnet_write(libnet_t *l) | |
49 | { | |
50 | int c; | |
51 | u_int32_t len; | |
52 | u_int8_t *packet = NULL; | |
53 | ||
54 | if (l == NULL) | |
55 | { | |
56 | return (-1); | |
57 | } | |
58 | ||
59 | c = libnet_pblock_coalesce(l, &packet, &len); | |
60 | if (c == - 1) | |
61 | { | |
62 | /* err msg set in libnet_pblock_coalesce() */ | |
63 | return (-1); | |
64 | } | |
65 | ||
66 | /* assume error */ | |
67 | c = -1; | |
68 | switch (l->injection_type) | |
69 | { | |
70 | case LIBNET_RAW4: | |
71 | case LIBNET_RAW4_ADV: | |
72 | if (len > LIBNET_MAX_PACKET) | |
73 | { | |
74 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
75 | "%s(): packet is too large (%d bytes)\n", | |
76 | __func__, len); | |
77 | goto done; | |
78 | } | |
79 | c = libnet_write_raw_ipv4(l, packet, len); | |
80 | break; | |
81 | case LIBNET_RAW6: | |
82 | case LIBNET_RAW6_ADV: | |
83 | c = libnet_write_raw_ipv6(l, packet, len); | |
84 | break; | |
85 | case LIBNET_LINK: | |
86 | case LIBNET_LINK_ADV: | |
87 | c = libnet_write_link(l, packet, len); | |
88 | break; | |
89 | default: | |
90 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
91 | "%s(): unsuported injection type\n", __func__); | |
92 | goto done; | |
93 | } | |
94 | ||
95 | /* do statistics */ | |
96 | if (c == len) | |
97 | { | |
98 | l->stats.packets_sent++; | |
99 | l->stats.bytes_written += c; | |
100 | } | |
101 | else | |
102 | { | |
103 | l->stats.packet_errors++; | |
104 | /* | |
105 | * XXX - we probably should have a way to retrieve the number of | |
106 | * bytes actually written (since we might have written something). | |
107 | */ | |
108 | if (c > 0) | |
109 | { | |
110 | l->stats.bytes_written += c; | |
111 | } | |
112 | } | |
113 | done: | |
114 | /* | |
115 | * Restore original pointer address so free won't complain about a | |
116 | * modified chunk pointer. | |
117 | */ | |
118 | if (l->aligner > 0) | |
119 | { | |
120 | packet = packet - l->aligner; | |
121 | } | |
122 | free(packet); | |
123 | return (c); | |
124 | } | |
125 | ||
126 | #if defined (__WIN32__) | |
127 | libnet_ptag_t | |
128 | libnet_win32_build_fake_ethernet(u_int8_t *dst, u_int8_t *src, u_int16_t type, | |
129 | u_int8_t *payload, u_int32_t payload_s, u_int8_t *packet, libnet_t *l, | |
130 | libnet_ptag_t ptag) | |
131 | { | |
132 | struct libnet_ethernet_hdr eth_hdr; | |
133 | ||
134 | if (!packet) | |
135 | { | |
136 | return (-1); | |
137 | } | |
138 | ||
139 | memset(ð_hdr, 0, sizeof(eth_hdr)); | |
140 | eth_hdr.ether_type = htons(type); | |
141 | memcpy(eth_hdr.ether_dhost, dst, ETHER_ADDR_LEN); /* destination address */ | |
142 | memcpy(eth_hdr.ether_shost, src, ETHER_ADDR_LEN); /* source address */ | |
143 | ||
144 | if (payload && payload_s) | |
145 | { | |
146 | /* | |
147 | * Unchecked runtime error for buf + ETH_H payload to be greater than | |
148 | * the allocated heap memory. | |
149 | */ | |
150 | memcpy(packet + LIBNET_ETH_H, payload, payload_s); | |
151 | } | |
152 | memcpy(packet, ð_hdr, sizeof(eth_hdr)); | |
153 | return (1); | |
154 | } | |
155 | ||
156 | libnet_ptag_t | |
157 | libnet_win32_build_fake_token(u_int8_t *dst, u_int8_t *src, u_int16_t type, | |
158 | u_int8_t *payload, u_int32_t payload_s, u_int8_t *packet, libnet_t *l, | |
159 | libnet_ptag_t ptag) | |
160 | { | |
161 | struct libnet_token_ring_hdr token_ring_hdr; | |
162 | ||
163 | if (!packet) | |
164 | { | |
165 | return (-1); | |
166 | } | |
167 | ||
168 | memset(&token_ring_hdr, 0, sizeof(token_ring_hdr)); | |
169 | token_ring_hdr.token_ring_access_control = 0x10; | |
170 | token_ring_hdr.token_ring_frame_control = 0x40; | |
171 | token_ring_hdr.token_ring_llc_dsap = 0xaa; | |
172 | token_ring_hdr.token_ring_llc_ssap = 0xaa; | |
173 | token_ring_hdr.token_ring_llc_control_field = 0x03; | |
174 | token_ring_hdr.token_ring_type = htons(type); | |
175 | memcpy(token_ring_hdr.token_ring_dhost, dst, ETHER_ADDR_LEN); | |
176 | memcpy(token_ring_hdr.token_ring_shost, libnet_get_hwaddr(l), | |
177 | ETHER_ADDR_LEN); | |
178 | ||
179 | if (payload && payload_s) | |
180 | { | |
181 | /* | |
182 | * Unchecked runtime error for buf + ETH_H payload to be greater than | |
183 | * the allocated heap memory. | |
184 | */ | |
185 | memcpy(packet + LIBNET_TOKEN_RING_H, payload, payload_s); | |
186 | } | |
187 | memcpy(packet, &token_ring_hdr, sizeof(token_ring_hdr)); | |
188 | return (1); | |
189 | } | |
190 | ||
191 | ||
192 | int | |
193 | libnet_win32_write_raw_ipv4(libnet_t *l, u_int8_t *payload, u_int32_t payload_s) | |
194 | { | |
195 | static BYTE dst[ETHER_ADDR_LEN]; | |
196 | static BYTE src[ETHER_ADDR_LEN]; | |
197 | ||
198 | u_int8_t *packet = NULL; | |
199 | u_int32_t packet_s; | |
200 | ||
201 | LPPACKET lpPacket = NULL; | |
202 | DWORD remoteip = 0; | |
203 | DWORD BytesTransfered; | |
204 | NetType type; | |
205 | struct libnet_ipv4_hdr *ip_hdr = NULL; | |
206 | ||
207 | memset(dst, 0, sizeof(dst)); | |
208 | memset(src, 0, sizeof(src)); | |
209 | ||
210 | packet_s = payload_s + l->link_offset; | |
211 | packet = (u_int8_t *)malloc(packet_s); | |
212 | if (packet == NULL) | |
213 | { | |
214 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
215 | "%s(): failed to allocate packet\n", __func__); | |
216 | return (-1); | |
217 | } | |
218 | ||
219 | /* we have to do the IP checksum */ | |
220 | if (libnet_do_checksum(l, payload, IPPROTO_IP, LIBNET_IPV4_H) == -1) | |
221 | { | |
222 | /* error msg set in libnet_do_checksum */ | |
223 | return (-1); | |
224 | } | |
225 | ||
226 | /* MACs, IPs and other stuff... */ | |
227 | ip_hdr = (struct libnet_ipv4_hdr *)payload; | |
228 | memcpy(src, libnet_get_hwaddr(l), sizeof(src)); | |
229 | remoteip = ip_hdr->ip_dst.S_un.S_addr; | |
230 | ||
231 | /* check if the remote station is the local station */ | |
232 | if (remoteip == libnet_get_ipaddr4(l)) | |
233 | { | |
234 | memcpy(dst, src, sizeof(dst)); | |
235 | } | |
236 | else | |
237 | { | |
238 | memcpy(dst, libnet_win32_get_remote_mac(l, remoteip), sizeof(dst)); | |
239 | } | |
240 | ||
241 | PacketGetNetType(l->lpAdapter, &type); | |
242 | ||
243 | switch(type.LinkType) | |
244 | { | |
245 | case NdisMedium802_3: | |
246 | libnet_win32_build_fake_ethernet(dst, src, ETHERTYPE_IP, payload, | |
247 | payload_s, packet, l , 0); | |
248 | break; | |
249 | case NdisMedium802_5: | |
250 | libnet_win32_build_fake_token(dst, src, ETHERTYPE_IP, payload, | |
251 | payload_s, packet, l, 0); | |
252 | break; | |
253 | case NdisMediumFddi: | |
254 | break; | |
255 | case NdisMediumWan: | |
256 | case NdisMediumAtm: | |
257 | case NdisMediumArcnet878_2: | |
258 | default: | |
259 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
260 | "%s(): network type (%d) is not supported\n", __func__, | |
261 | type.LinkType); | |
262 | return (-1); | |
263 | break; | |
264 | } | |
265 | ||
266 | BytesTransfered = -1; | |
267 | if ((lpPacket = PacketAllocatePacket()) == NULL) | |
268 | { | |
269 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
270 | "%s(): failed to allocate the LPPACKET structure\n", __func__); | |
271 | return (-1); | |
272 | } | |
273 | ||
274 | PacketInitPacket(lpPacket, packet, packet_s); | |
275 | ||
276 | /* PacketSendPacket returns a BOOLEAN */ | |
277 | if (PacketSendPacket(l->lpAdapter, lpPacket, TRUE)) | |
278 | { | |
279 | BytesTransfered = packet_s; | |
280 | } | |
281 | ||
282 | PacketFreePacket(lpPacket); | |
283 | free(packet); | |
284 | ||
285 | return (BytesTransfered); | |
286 | } | |
287 | ||
288 | int | |
289 | libnet_write_raw_ipv4(libnet_t *l, u_int8_t *packet, u_int32_t size) | |
290 | { | |
291 | return (libnet_win32_write_raw_ipv4(l, packet, size)); | |
292 | } | |
293 | ||
294 | int | |
295 | libnet_write_raw_ipv6(libnet_t *l, u_int8_t *packet, u_int32_t size) | |
296 | { | |
297 | /* no difference in win32 */ | |
298 | return (libnet_write_raw_ipv4(l, packet, size)); | |
299 | } | |
300 | ||
301 | #else /* __WIN32__ */ | |
302 | ||
303 | int | |
304 | libnet_write_raw_ipv4(libnet_t *l, u_int8_t *packet, u_int32_t size) | |
305 | { | |
306 | int c; | |
307 | struct sockaddr_in sin; | |
308 | struct libnet_ipv4_hdr *ip_hdr; | |
309 | ||
310 | if (l == NULL) | |
311 | { | |
312 | return (-1); | |
313 | } | |
314 | ||
315 | ip_hdr = (struct libnet_ipv4_hdr *)packet; | |
316 | ||
317 | #if (LIBNET_BSD_BYTE_SWAP) | |
318 | /* | |
319 | * For link access, we don't need to worry about the inconsistencies of | |
320 | * certain BSD kernels. However, raw socket nuances abound. Certain | |
321 | * BSD implmentations require the ip_len and ip_off fields to be in host | |
322 | * byte order. | |
323 | */ | |
324 | ip_hdr->ip_len = FIX(ip_hdr->ip_len); | |
325 | ip_hdr->ip_off = FIX(ip_hdr->ip_off); | |
326 | #endif /* LIBNET_BSD_BYTE_SWAP */ | |
327 | ||
328 | memset(&sin, 0, sizeof(sin)); | |
329 | sin.sin_family = AF_INET; | |
330 | sin.sin_addr.s_addr = ip_hdr->ip_dst.s_addr; | |
331 | #if (__WIN32__) | |
332 | /* set port for TCP */ | |
333 | /* | |
334 | * XXX - should first check to see if there's a pblock for a TCP | |
335 | * header, if not we can use a dummy value for the port. | |
336 | */ | |
337 | if (ip_hdr->ip_p == 6) | |
338 | { | |
339 | struct libnet_tcp_hdr *tcph_p = | |
340 | (struct libnet_tcp_hdr *)(packet + (ip_hdr->ip_hl << 2)); | |
341 | sin.sin_port = tcph_p->th_dport; | |
342 | } | |
343 | /* set port for UDP */ | |
344 | /* | |
345 | * XXX - should first check to see if there's a pblock for a UDP | |
346 | * header, if not we can use a dummy value for the port. | |
347 | */ | |
348 | else if (ip_hdr->ip_p == 17) | |
349 | { | |
350 | struct libnet_udp_hdr *udph_p = | |
351 | (struct libnet_udp_hdr *)(packet + (ip_hdr->ip_hl << 2)); | |
352 | sin.sin_port = udph_p->uh_dport; | |
353 | } | |
354 | #endif /* __WIN32__ */ | |
355 | ||
356 | c = sendto(l->fd, packet, size, 0, (struct sockaddr *)&sin, | |
357 | sizeof(struct sockaddr)); | |
358 | ||
359 | #if (LIBNET_BSD_BYTE_SWAP) | |
360 | ip_hdr->ip_len = UNFIX(ip_hdr->ip_len); | |
361 | ip_hdr->ip_off = UNFIX(ip_hdr->ip_off); | |
362 | #endif /* LIBNET_BSD_BYTE_SWAP */ | |
363 | ||
364 | if (c != size) | |
365 | { | |
366 | #if !(__WIN32__) | |
367 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
368 | "%s(): %d bytes written (%s)\n", __func__, c, | |
369 | strerror(errno)); | |
370 | #else /* __WIN32__ */ | |
371 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
372 | "%s(): %d bytes written (%d)\n", __func__, c, | |
373 | WSAGetLastError()); | |
374 | #endif /* !__WIN32__ */ | |
375 | } | |
376 | return (c); | |
377 | } | |
378 | ||
379 | int | |
380 | libnet_write_raw_ipv6(libnet_t *l, u_int8_t *packet, u_int32_t size) | |
381 | { | |
382 | #if defined HAVE_SOLARIS && !defined HAVE_SOLARIS_IPV6 | |
383 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): no IPv6 support\n", | |
384 | __func__, strerror(errno)); | |
385 | return (-1); | |
386 | } | |
387 | #else | |
388 | int c; | |
389 | struct sockaddr_in6 sin; | |
390 | struct libnet_ipv6_hdr *ip_hdr; | |
391 | ||
392 | if (l == NULL) | |
393 | { | |
394 | return (-1); | |
395 | } | |
396 | ||
397 | ip_hdr = (struct libnet_ipv6_hdr *)packet; | |
398 | ||
399 | memset(&sin, 0, sizeof(sin)); | |
400 | sin.sin6_family = AF_INET6; | |
401 | memcpy(sin.sin6_addr.s6_addr, ip_hdr->ip_dst.libnet_s6_addr, | |
402 | sizeof(ip_hdr->ip_dst.libnet_s6_addr)); | |
403 | ||
404 | c = sendto(l->fd, packet, size, 0, (struct sockaddr *)&sin, sizeof(sin)); | |
405 | if (c != size) | |
406 | { | |
407 | #if !(__WIN32__) | |
408 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
409 | "%s(): %d bytes written (%s)\n", __func__, c, | |
410 | strerror(errno)); | |
411 | #else /* __WIN32__ */ | |
412 | snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, | |
413 | "%s(): %d bytes written (%d)\n", __func__, c, | |
414 | WSAGetLastError()); | |
415 | #endif /* !__WIN32__ */ | |
416 | } | |
417 | return (c); | |
418 | } | |
419 | #endif | |
420 | #endif | |
421 | /* EOF */ |