1 /*
2  *  $Id: libnet_write.c,v 1.14 2004/11/09 07:05:07 mike 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 #include <netinet/in.h>
36 #include <sys/types.h>
37 #include <netinet/udp.h>
38 
39 #if (HAVE_CONFIG_H)
40 #include "../include/config.h"
41 #endif
42 #if (!(_WIN32) || (__CYGWIN__))
43 #include "../include/libnet.h"
44 #else
45 #include "../include/win32/libnet.h"
46 #include "../include/win32/config.h"
47 #include "packet32.h"
48 #include "Ntddndis.h"
49 #endif
50 
51 int
libnet_write(libnet_t * l)52 libnet_write(libnet_t *l)
53 {
54     int c;
55     uint32_t len;
56     uint8_t *packet = NULL;
57 
58     if (l == NULL)
59     {
60         return (-1);
61     }
62 
63     c = libnet_pblock_coalesce(l, &packet, &len);
64     if (c == - 1)
65     {
66         /* err msg set in libnet_pblock_coalesce() */
67         return (-1);
68     }
69 
70     /* assume error */
71     c = -1;
72     switch (l->injection_type)
73     {
74         case LIBNET_RAW4:
75         case LIBNET_RAW4_ADV:
76             if (len > LIBNET_MAX_PACKET)
77             {
78                 snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
79                         "%s(): packet is too large (%d bytes)\n",
80                         __func__, len);
81                 goto done;
82             }
83             c = libnet_write_raw_ipv4(l, packet, len);
84             break;
85         case LIBNET_RAW6:
86         case LIBNET_RAW6_ADV:
87             c = libnet_write_raw_ipv6(l, packet, len);
88             break;
89         case LIBNET_LINK:
90         case LIBNET_LINK_ADV:
91             c = libnet_write_link(l, packet, len);
92             break;
93         default:
94             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
95                         "%s(): unsuported injection type\n", __func__);
96             goto done;
97     }
98 
99     /* do statistics */
100     if (c == len)
101     {
102         l->stats.packets_sent++;
103         l->stats.bytes_written += c;
104     }
105     else
106     {
107         l->stats.packet_errors++;
108         /*
109          *  XXX - we probably should have a way to retrieve the number of
110          *  bytes actually written (since we might have written something).
111          */
112         if (c > 0)
113         {
114             l->stats.bytes_written += c;
115         }
116     }
117 done:
118     /*
119      *  Restore original pointer address so free won't complain about a
120      *  modified chunk pointer.
121      */
122     if (l->aligner > 0)
123     {
124         packet = packet - l->aligner;
125     }
126     free(packet);
127     return (c);
128 }
129 
130 #if defined (__WIN32__)
131 libnet_ptag_t
libnet_win32_build_fake_ethernet(uint8_t * dst,uint8_t * src,uint16_t type,uint8_t * payload,uint32_t payload_s,uint8_t * packet,libnet_t * l,libnet_ptag_t ptag)132 libnet_win32_build_fake_ethernet(uint8_t *dst, uint8_t *src, uint16_t type,
133 uint8_t *payload, uint32_t payload_s, uint8_t *packet, libnet_t *l,
134 libnet_ptag_t ptag)
135 {
136     struct libnet_ethernet_hdr eth_hdr;
137 
138     if (!packet)
139     {
140         return (-1);
141     }
142 
143     memset(&eth_hdr, 0, sizeof(eth_hdr));
144     eth_hdr.ether_type = htons(type);
145     memcpy(eth_hdr.ether_dhost, dst, ETHER_ADDR_LEN);  /* destination address */
146     memcpy(eth_hdr.ether_shost, src, ETHER_ADDR_LEN);  /* source address */
147 
148     if (payload && payload_s)
149     {
150         /*
151          *  Unchecked runtime error for buf + ETH_H payload to be greater than
152          *  the allocated heap memory.
153          */
154         memcpy(packet + LIBNET_ETH_H, payload, payload_s);
155     }
156     memcpy(packet, &eth_hdr, sizeof(eth_hdr));
157     return (1);
158 }
159 
160 libnet_ptag_t
libnet_win32_build_fake_token(uint8_t * dst,uint8_t * src,uint16_t type,uint8_t * payload,uint32_t payload_s,uint8_t * packet,libnet_t * l,libnet_ptag_t ptag)161 libnet_win32_build_fake_token(uint8_t *dst, uint8_t *src, uint16_t type,
162 uint8_t *payload, uint32_t payload_s, uint8_t *packet, libnet_t *l,
163 libnet_ptag_t ptag)
164 {
165     struct libnet_token_ring_hdr token_ring_hdr;
166 
167     if (!packet)
168     {
169         return (-1);
170     }
171 
172     memset(&token_ring_hdr, 0, sizeof(token_ring_hdr));
173     token_ring_hdr.token_ring_access_control    = 0x10;
174     token_ring_hdr.token_ring_frame_control     = 0x40;
175     token_ring_hdr.token_ring_llc_dsap          = 0xaa;
176     token_ring_hdr.token_ring_llc_ssap          = 0xaa;
177     token_ring_hdr.token_ring_llc_control_field = 0x03;
178     token_ring_hdr.token_ring_type              = htons(type);
179     memcpy(token_ring_hdr.token_ring_dhost, dst, ETHER_ADDR_LEN);
180     memcpy(token_ring_hdr.token_ring_shost, libnet_get_hwaddr(l),
181            ETHER_ADDR_LEN);
182 
183     if (payload && payload_s)
184     {
185         /*
186          *  Unchecked runtime error for buf + ETH_H payload to be greater than
187          *  the allocated heap memory.
188          */
189         memcpy(packet + LIBNET_TOKEN_RING_H, payload, payload_s);
190     }
191     memcpy(packet, &token_ring_hdr, sizeof(token_ring_hdr));
192     return (1);
193 }
194 
195 int
libnet_win32_write_raw_ipv4(libnet_t * l,const uint8_t * payload,uint32_t payload_s)196 libnet_win32_write_raw_ipv4(libnet_t *l, const uint8_t *payload, uint32_t payload_s)
197 {
198     static BYTE dst[ETHER_ADDR_LEN];
199     static BYTE src[ETHER_ADDR_LEN];
200 
201     uint8_t *packet      = NULL;
202     uint32_t packet_s;
203 
204     LPPACKET lpPacket   = NULL;
205     DWORD remoteip      = 0;
206     DWORD BytesTransfered;
207     NetType type;
208     struct libnet_ipv4_hdr *ip_hdr = NULL;
209 
210     memset(dst, 0, sizeof(dst));
211     memset(src, 0, sizeof(src));
212 
213     packet_s = payload_s + l->link_offset;
214     packet = (uint8_t *)malloc(packet_s);
215     if (packet == NULL)
216     {
217         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
218                 "%s(): failed to allocate packet\n", __func__);
219         return (-1);
220     }
221 
222     /* we have to do the IP checksum  */
223     if (libnet_do_checksum(l, payload, IPPROTO_IP, LIBNET_IPV4_H) == -1)
224     {
225         /* error msg set in libnet_do_checksum */
226         return (-1);
227     }
228 
229     /* MACs, IPs and other stuff... */
230     ip_hdr = (struct libnet_ipv4_hdr *)payload;
231     memcpy(src, libnet_get_hwaddr(l), sizeof(src));
232     remoteip = ip_hdr->ip_dst.S_un.S_addr;
233 
234     /* check if the remote station is the local station */
235     if (remoteip == libnet_get_ipaddr4(l))
236     {
237         memcpy(dst, src, sizeof(dst));
238     }
239     else
240     {
241         memcpy(dst, libnet_win32_get_remote_mac(l, remoteip), sizeof(dst));
242     }
243 
244     PacketGetNetType(l->lpAdapter, &type);
245 
246     switch(type.LinkType)
247     {
248         case NdisMedium802_3:
249             libnet_win32_build_fake_ethernet(dst, src, ETHERTYPE_IP, payload,
250                     payload_s, packet, l , 0);
251             break;
252         case NdisMedium802_5:
253             libnet_win32_build_fake_token(dst, src, ETHERTYPE_IP, payload,
254                     payload_s, packet, l, 0);
255             break;
256         case NdisMediumFddi:
257             break;
258         case NdisMediumWan:
259         case NdisMediumAtm:
260         case NdisMediumArcnet878_2:
261         default:
262             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
263                 "%s(): network type (%d) is not supported\n", __func__,
264                 type.LinkType);
265             return (-1);
266             break;
267     }
268 
269     BytesTransfered = -1;
270     if ((lpPacket = PacketAllocatePacket()) == NULL)
271     {
272         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
273                 "%s(): failed to allocate the LPPACKET structure\n", __func__);
274 	    return (-1);
275     }
276 
277     PacketInitPacket(lpPacket, packet, packet_s);
278 
279     /* PacketSendPacket returns a BOOLEAN */
280     if (PacketSendPacket(l->lpAdapter, lpPacket, TRUE))
281     {
282         BytesTransfered = packet_s;
283     }
284 
285     PacketFreePacket(lpPacket);
286     free(packet);
287 
288     return (BytesTransfered);
289 }
290 
291 int
libnet_write_raw_ipv4(libnet_t * l,const uint8_t * packet,uint32_t size)292 libnet_write_raw_ipv4(libnet_t *l, const uint8_t *packet, uint32_t size)
293 {
294     return (libnet_win32_write_raw_ipv4(l, packet, size));
295 }
296 
297 int
libnet_write_raw_ipv6(libnet_t * l,const uint8_t * packet,uint32_t size)298 libnet_write_raw_ipv6(libnet_t *l, const uint8_t *packet, uint32_t size)
299 {
300     /* no difference in win32 */
301     return (libnet_write_raw_ipv4(l, packet, size));
302 }
303 
304 #else /* __WIN32__ */
305 
306 int
libnet_write_raw_ipv4(libnet_t * l,const uint8_t * packet,uint32_t size)307 libnet_write_raw_ipv4(libnet_t *l, const uint8_t *packet, uint32_t size)
308 {
309     int c;
310     struct sockaddr_in sin;
311     struct libnet_ipv4_hdr *ip_hdr;
312 
313     if (l == NULL)
314     {
315         return (-1);
316     }
317 
318     ip_hdr = (struct libnet_ipv4_hdr *)packet;
319 
320 #if (LIBNET_BSD_BYTE_SWAP)
321     /*
322      *  For link access, we don't need to worry about the inconsistencies of
323      *  certain BSD kernels.  However, raw socket nuances abound.  Certain
324      *  BSD implmentations require the ip_len and ip_off fields to be in host
325      *  byte order.
326      */
327     ip_hdr->ip_len = FIX(ip_hdr->ip_len);
328     ip_hdr->ip_off = FIX(ip_hdr->ip_off);
329 #endif /* LIBNET_BSD_BYTE_SWAP */
330 
331     memset(&sin, 0, sizeof(sin));
332     sin.sin_family  = AF_INET;
333     sin.sin_addr.s_addr = ip_hdr->ip_dst.s_addr;
334 #if (__WIN32__)
335     /* set port for TCP */
336     /*
337      *  XXX - should first check to see if there's a pblock for a TCP
338      *  header, if not we can use a dummy value for the port.
339      */
340     if (ip_hdr->ip_p == 6)
341     {
342         struct libnet_tcp_hdr *tcph_p =
343                 (struct libnet_tcp_hdr *)(packet + (ip_hdr->ip_hl << 2));
344         sin.sin_port = tcph_p->th_dport;
345     }
346     /* set port for UDP */
347     /*
348      *  XXX - should first check to see if there's a pblock for a UDP
349      *  header, if not we can use a dummy value for the port.
350      */
351     else if (ip_hdr->ip_p == 17)
352     {
353         struct libnet_udp_hdr *udph_p =
354                 (struct libnet_udp_hdr *)(packet + (ip_hdr->ip_hl << 2));
355        sin.sin_port = udph_p->uh_dport;
356     }
357 #endif /* __WIN32__ */
358 
359     c = sendto(l->fd, packet, size, 0, (struct sockaddr *)&sin,
360             sizeof(sin));
361 
362 #if (LIBNET_BSD_BYTE_SWAP)
363     ip_hdr->ip_len = UNFIX(ip_hdr->ip_len);
364     ip_hdr->ip_off = UNFIX(ip_hdr->ip_off);
365 #endif /* LIBNET_BSD_BYTE_SWAP */
366 
367     if (c != size)
368     {
369 #if !(__WIN32__)
370         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
371                 "%s(): %d bytes written (%s)\n", __func__, c,
372                 strerror(errno));
373 #else /* __WIN32__ */
374         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
375                 "%s(): %d bytes written (%d)\n", __func__, c,
376                 WSAGetLastError());
377 #endif /* !__WIN32__ */
378     }
379     return (c);
380 }
381 
382 int
libnet_write_raw_ipv6(libnet_t * l,const uint8_t * packet,uint32_t size)383 libnet_write_raw_ipv6(libnet_t *l, const uint8_t *packet, uint32_t size)
384 {
385 #if defined HAVE_SOLARIS && !defined HAVE_SOLARIS_IPV6
386     snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): no IPv6 support\n",
387             __func__, strerror(errno));
388     return (-1);
389 }
390 #else
391     int c;
392     struct sockaddr_in6 sin;
393     struct libnet_ipv6_hdr *ip_hdr;
394 
395     if (l == NULL)
396     {
397         return (-1);
398     }
399 
400     ip_hdr = (struct libnet_ipv6_hdr *)packet;
401 
402     memset(&sin, 0, sizeof(sin));
403     sin.sin6_family  = AF_INET6;
404     memcpy(sin.sin6_addr.s6_addr, ip_hdr->ip_dst.libnet_s6_addr,
405             sizeof(ip_hdr->ip_dst.libnet_s6_addr));
406 
407     c = sendto(l->fd, packet, size, 0, (struct sockaddr *)&sin, sizeof(sin));
408     if (c != size)
409     {
410 #if !(__WIN32__)
411         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
412                 "%s(): %d bytes written (%s)\n", __func__, c,
413                 strerror(errno));
414 #else /* __WIN32__ */
415         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
416                 "%s(): %d bytes written (%d)\n", __func__, c,
417                 WSAGetLastError());
418 #endif /* !__WIN32__ */
419     }
420     return (c);
421 }
422 #endif
423 #endif
424 /* EOF */
425