* $Id: libnet_pblock.c,v 1.20 2005/11/29 22:34:37 carlosc Exp $
* libnet_pblock.c - Memory protocol block routines.
* Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#include "../include/config.h"
#if (!(_WIN32) || (__CYGWIN__))
#include "../include/libnet.h"
#include "../include/win32/libnet.h"
libnet_pblock_probe(libnet_t
*l
, libnet_ptag_t ptag
, u_int32_t n
, u_int8_t type
)
if (ptag
== LIBNET_PTAG_INITIALIZER
)
* Create a new pblock and enough buffer space for the packet.
p
= libnet_pblock_new(l
, n
);
/* err msg set in libnet_pblock_new() */
* Update this pblock, don't create a new one. Note that if the
* new packet size is larger than the old one we will do a malloc.
p
= libnet_pblock_find(l
, ptag
);
/* err msg set in libnet_pblock_find() */
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): ptag refers to different type than expected (%d != %d)",
__func__
, p
->type
, type
);
* If size is greater than the original block of memory, we need
* to malloc more memory. Should we use realloc?
offset
= n
- p
->b_len
; /* how many bytes larger new pblock is */
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): can't resize pblock buffer: %s\n", __func__
,
p
->h_len
+= offset
; /* new length for checksums */
p
->b_len
= n
; /* new buf len */
p
->h_len
-= offset
; /* new length for checksums */
p
->b_len
= n
; /* new buf len */
p
->copied
= 0; /* reset copied counter */
libnet_pblock_new(libnet_t
*l
, u_int32_t size
)
* Should we do error checking the size of the pblock here, or
* should we rely on the underlying operating system to complain when
* the user tries to write some ridiculously huge packet?
/* make the head node if it doesn't exist */
if (l
->protocol_blocks
== NULL
)
p
= l
->protocol_blocks
= malloc(sizeof (libnet_pblock_t
));
memset(p
, 0, sizeof (libnet_pblock_t
));
p
->next
= malloc(sizeof (libnet_pblock_t
));
memset(p
->next
, 0, sizeof (libnet_pblock_t
));
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
, "%s(): malloc(): %s\n", __func__
,
libnet_pblock_swap(libnet_t
*l
, libnet_ptag_t ptag1
, libnet_ptag_t ptag2
)
libnet_pblock_t
*p1
, *p2
;
p1
= libnet_pblock_find(l
, ptag1
);
p2
= libnet_pblock_find(l
, ptag2
);
if (p1
== NULL
|| p2
== NULL
)
/* error set elsewhere */
/* first node on the list */
libnet_pblock_insert_before(libnet_t
*l
, libnet_ptag_t ptag1
,
libnet_pblock_t
*p1
, *p2
;
p1
= libnet_pblock_find(l
, ptag1
);
p2
= libnet_pblock_find(l
, ptag2
);
if (p1
== NULL
|| p2
== NULL
)
/* error set elsewhere */
/* first node on the list */
libnet_pblock_find(libnet_t
*l
, libnet_ptag_t ptag
)
for (p
= l
->protocol_blocks
; p
; p
= p
->next
)
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): couldn't find protocol block\n", __func__
);
libnet_pblock_append(libnet_t
*l
, libnet_pblock_t
*p
, u_int8_t
*buf
,
if (p
->copied
+ len
> p
->b_len
)
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): memcpy would overflow buffer\n", __func__
);
memcpy(p
->buf
+ p
->copied
, buf
, len
);
libnet_pblock_setflags(libnet_pblock_t
*p
, u_int8_t flags
)
libnet_pblock_update(libnet_t
*l
, libnet_pblock_t
*p
, u_int32_t h
,
p
->ptag
= ++(l
->ptag_state
);
l
->pblock_end
= p
; /* point end of pblock list here */
libnet_pblock_coalesce(libnet_t
*l
, u_int8_t
**packet
, u_int32_t
*size
)
* Determine the offset required to keep memory aligned (strict
* architectures like solaris enforce this, but's a good practice
* either way). This is only required on the link layer with the
* 14 byte ethernet offset (others are similarly unkind).
if (l
->injection_type
== LIBNET_LINK
||
l
->injection_type
== LIBNET_LINK_ADV
)
/* 8 byte alignment should work */
l
->aligner
= 8 - (l
->link_offset
% 8);
*packet
= malloc(l
->aligner
+ l
->total_size
);
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
, "%s(): malloc(): %s\n",
__func__
, strerror(errno
));
memset(*packet
, 0, l
->aligner
+ l
->total_size
);
if (l
->injection_type
== LIBNET_RAW4
&&
l
->pblock_end
->type
== LIBNET_PBLOCK_IPV4_H
)
libnet_pblock_setflags(l
->pblock_end
, LIBNET_PBLOCK_DO_CHECKSUM
);
/* additional sanity checks to perform if we're not in advanced mode */
if (!(l
->injection_type
& LIBNET_ADV_MASK
))
switch (l
->injection_type
)
if ((l
->pblock_end
->type
!= LIBNET_PBLOCK_TOKEN_RING_H
) &&
(l
->pblock_end
->type
!= LIBNET_PBLOCK_FDDI_H
) &&
(l
->pblock_end
->type
!= LIBNET_PBLOCK_ETH_H
) &&
(l
->pblock_end
->type
!= LIBNET_PBLOCK_802_1Q_H
) &&
(l
->pblock_end
->type
!= LIBNET_PBLOCK_ISL_H
) &&
(l
->pblock_end
->type
!= LIBNET_PBLOCK_802_3_H
))
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): packet assembly cannot find a layer 2 header\n",
if ((l
->pblock_end
->type
!= LIBNET_PBLOCK_IPV4_H
))
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): packet assembly cannot find an IPv4 header\n",
if ((l
->pblock_end
->type
!= LIBNET_PBLOCK_IPV6_H
))
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): packet assembly cannot find an IPv6 header\n",
/* we should not end up here ever */
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): suddenly the dungeon collapses -- you die\n",
for (n
= l
->aligner
+ l
->total_size
, p
= l
->protocol_blocks
; p
|| q
; )
/* copy over the packet chunk */
memcpy(*packet
+ n
, p
->buf
, p
->b_len
);
if (p
== NULL
|| ((p
->flags
) & LIBNET_PBLOCK_DO_CHECKSUM
))
if ((q
->flags
) & LIBNET_PBLOCK_DO_CHECKSUM
)
int offset
= (l
->total_size
+ l
->aligner
) - q
->ip_offset
;
c
= libnet_do_checksum(l
, *packet
+ offset
,
libnet_pblock_p2p(q
->type
), q
->h_len
);
/* err msg set in libnet_do_checksum() */
*size
= l
->aligner
+ l
->total_size
;
* Set the packet pointer to the true beginning of the packet and set
* the size for transmission.
if ((l
->injection_type
== LIBNET_LINK
||
l
->injection_type
== LIBNET_LINK_ADV
) && l
->aligner
)
libnet_pblock_delete(libnet_t
*l
, libnet_pblock_t
*p
)
l
->total_size
-= p
->b_len
;
l
->protocol_blocks
= p
->next
;
libnet_pblock_p2p(u_int8_t type
)
/* for checksum; return the protocol number given a pblock type*/
case LIBNET_PBLOCK_CDP_H
:
return (LIBNET_PROTO_CDP
);
case LIBNET_PBLOCK_ICMPV4_H
:
case LIBNET_PBLOCK_ICMPV4_ECHO_H
:
case LIBNET_PBLOCK_ICMPV4_MASK_H
:
case LIBNET_PBLOCK_ICMPV4_UNREACH_H
:
case LIBNET_PBLOCK_ICMPV4_TIMXCEED_H
:
case LIBNET_PBLOCK_ICMPV4_REDIRECT_H
:
case LIBNET_PBLOCK_ICMPV4_TS_H
:
case LIBNET_PBLOCK_IGMP_H
:
case LIBNET_PBLOCK_IPV4_H
:
return (LIBNET_PROTO_ISL
);
case LIBNET_PBLOCK_OSPF_H
:
case LIBNET_PBLOCK_LS_RTR_H
:
return (IPPROTO_OSPF_LSA
);
case LIBNET_PBLOCK_TCP_H
:
case LIBNET_PBLOCK_UDP_H
:
case LIBNET_PBLOCK_VRRP_H
:
case LIBNET_PBLOCK_GRE_H
:
case LIBNET_PBLOCK_SCTP_H
:
case LIBNET_PBLOCK_PIM_H
:
case LIBNET_PBLOCK_RSVP_H
:
libnet_pblock_record_ip_offset(libnet_t
*l
, u_int32_t offset
)
libnet_pblock_t
*p
= l
->pblock_end
;
} while (p
&& p
->type
!= LIBNET_PBLOCK_IPV4_H
&& p
->type
!= LIBNET_PBLOCK_IPV6_H
);