Skip to content

Commit

Permalink
Adding support to spoof ipv6
Browse files Browse the repository at this point in the history
Samplicator can not spoof IPv6 packes as well as IPv4 packets.
  • Loading branch information
dkhenry authored and Koz committed Jul 7, 2016
1 parent 7b4e009 commit 76bdfae
Showing 1 changed file with 206 additions and 98 deletions.
304 changes: 206 additions & 98 deletions rawsend.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,16 @@
#include <netinet/in_systm.h>
#endif
#include <sys/socket.h>

#ifndef __APPLE_USE_RFC_3542
#define __APPLE_USE_RFC_3542
#endif

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <sys/uio.h>
#include <sys/ioctl.h>

/* make uh_... slot names available under Linux */
#define __FAVOR_BSD 1
Expand All @@ -49,6 +56,7 @@

static unsigned ip_header_checksum (const void * header);
static uint16_t udp_sum_calc (uint16_t, uint32_t, uint16_t, uint32_t, uint16_t, const void *);
static uint16_t udp_sum_calc_v6 (struct in6_addr, uint16_t, struct in6_addr, uint16_t, uint16_t, const char *);

int
raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
Expand All @@ -61,37 +69,44 @@ raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
int flags;
#define saddr ((struct sockaddr_in *) saddr_generic)
#define daddr ((struct sockaddr_in *) daddr_generic)
#define saddr_v6 ((struct sockaddr_in6 *) saddr_generic)
#define daddr_v6 ((struct sockaddr_in6 *) daddr_generic)
#define ipv6 (saddr_generic->sa_family == AF_INET6 && daddr_generic->sa_family == AF_INET6)
{
int length;
int sockerr;
socklen_t sockerr_size = sizeof sockerr;
struct sockaddr_in dest_a;
struct sockaddr_storage dest_a;
struct ip ih;
struct udphdr uh;

#ifdef HAVE_SYS_UIO_H
struct msghdr mh;
struct msghdr mh = {};
struct iovec iov[3];
#else /* not HAVE_SYS_UIO_H */
int flags = 0;
flags = 0;
static char *msgbuf = 0;
static size_t msgbuflen = 0;
static size_t next_alloc_size = 1;
#endif /* not HAVE_SYS_UIO_H */

uh.uh_sport = saddr->sin_port;
uh.uh_dport = daddr->sin_port;
if( ipv6 ) {
length = msglen;
} else {
uh.uh_sport = saddr->sin_port;
uh.uh_dport = daddr->sin_port;
uh.uh_sum = flags & RAWSEND_COMPUTE_UDP_CHECKSUM
? udp_sum_calc (msglen,
ntohl(saddr->sin_addr.s_addr),
ntohs(saddr->sin_port),
ntohl(daddr->sin_addr.s_addr),
ntohs(daddr->sin_port),
msg)
: 0;
length = msglen + sizeof uh + sizeof ih;
}
uh.uh_ulen = htons (msglen + sizeof uh);
uh.uh_sum = flags & RAWSEND_COMPUTE_UDP_CHECKSUM
? udp_sum_calc (msglen,
ntohl(saddr->sin_addr.s_addr),
ntohs(saddr->sin_port),
ntohl(daddr->sin_addr.s_addr),
ntohs(daddr->sin_port),
msg)
: 0;

length = msglen + sizeof uh + sizeof ih;

#ifndef HAVE_SYS_UIO_H
if (length > msgbuflen)
{
Expand All @@ -112,114 +127,142 @@ raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
next_alloc_size *= 2;
}
#endif /* not HAVE_SYS_UIO_H */
ih.ip_hl = (sizeof ih+3)/4;
ih.ip_v = 4;
ih.ip_tos = 0;
/* Depending on the target platform, te ip_off and ip_len fields
should be in either host or network byte order. Usually
BSD-derivatives require host byte order, but at least OpenBSD
since version 2.1 uses network byte order. Linux uses network
byte order for all IP header fields. */

if( ipv6 ) {
((struct sockaddr_in6*) &dest_a)->sin6_family = AF_INET6;
((struct sockaddr_in6*) &dest_a)->sin6_port = daddr_v6->sin6_port;
((struct sockaddr_in6*) &dest_a)->sin6_addr = daddr_v6->sin6_addr;
} else {
ih.ip_hl = (sizeof ih+3)/4;
ih.ip_v = 4;
ih.ip_tos = 0;

/* Depending on the target platform, te ip_off and ip_len fields
should be in either host or network byte order. Usually
BSD-derivatives require host byte order, but at least OpenBSD
since version 2.1 uses network byte order. Linux uses network
byte order for all IP header fields. */
#if defined (__linux__) || (defined (__OpenBSD__) && (OpenBSD > 199702))
ih.ip_len = htons (length);
ih.ip_off = htons (0);
ih.ip_len = htons (length);
ih.ip_off = htons (0);
#else
ih.ip_len = length;
ih.ip_off = 0;
ih.ip_len = length;
ih.ip_off = 0;
#endif
ih.ip_id = htons (0);
ih.ip_ttl = ttl;
ih.ip_p = 17;
ih.ip_sum = htons (0);
ih.ip_src.s_addr = saddr->sin_addr.s_addr;
ih.ip_dst.s_addr = daddr->sin_addr.s_addr;

/* At least on Solaris, it seems clear that even the raw IP datagram
transmission code will actually compute the IP header checksum
for us. Probably this is the case for all other systems on which
this code works, so maybe we should just set the checksum to zero
to avoid duplicate work. I'm not even sure whether my IP
checksum computation in ip_header_checksum() below is correct. */
ih.ip_sum = ip_header_checksum (&ih);

dest_a.sin_family = AF_INET;
dest_a.sin_port = daddr->sin_port;
dest_a.sin_addr.s_addr = daddr->sin_addr.s_addr;

ih.ip_id = htons (0);
ih.ip_ttl = ttl;
ih.ip_p = 17;
ih.ip_sum = htons (0);
ih.ip_src.s_addr = saddr->sin_addr.s_addr;
ih.ip_dst.s_addr = daddr->sin_addr.s_addr;

/* At least on Solaris, it seems clear that even the raw IP datagram
transmission code will actually compute the IP header checksum
for us. Probably this is the case for all other systems on which
this code works, so maybe we should just set the checksum to zero
to avoid duplicate work. I'm not even sure whether my IP
checksum computation in ip_header_checksum() below is correct. */
ih.ip_sum = ip_header_checksum (&ih);

((struct sockaddr_in*) &dest_a)->sin_family = AF_INET;
((struct sockaddr_in*) &dest_a)->sin_port = daddr->sin_port;
((struct sockaddr_in*) &dest_a)->sin_addr.s_addr = daddr->sin_addr.s_addr;
}
int err = 0;
#ifdef HAVE_SYS_UIO_H
iov[0].iov_base = (char *) &ih;
iov[0].iov_len = sizeof ih;
iov[1].iov_base = (char *) &uh;
iov[1].iov_len = sizeof uh;
iov[2].iov_base = (char *) msg;
iov[2].iov_len = msglen;

bzero ((char *) &mh, sizeof mh);

if( ipv6 ) {
iov[0].iov_base = (char *) msg;
iov[0].iov_len = msglen;
mh.msg_iovlen = 1;

// Set the PKT information to spoof the source
size_t cmsglen = CMSG_SPACE (sizeof (struct in6_pktinfo));
mh.msg_control = calloc (1,cmsglen);
mh.msg_controllen = cmsglen;

struct cmsghdr *hdr1 = CMSG_FIRSTHDR(&mh);
hdr1->cmsg_level = IPPROTO_IPV6;
hdr1->cmsg_type = IPV6_PKTINFO;
hdr1->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA (hdr1);
pktinfo->ipi6_ifindex = 0;
pktinfo->ipi6_addr = saddr_v6->sin6_addr;
} else {
iov[0].iov_base = (char *) &ih;
iov[0].iov_len = sizeof ih;
iov[1].iov_base = (char *) &uh;
iov[1].iov_len = sizeof uh;
iov[2].iov_base = (char *) msg;
iov[2].iov_len = msglen;
mh.msg_iovlen = 3;
}


mh.msg_name = (char *)&dest_a;
mh.msg_namelen = sizeof dest_a;
mh.msg_iov = iov;
mh.msg_iovlen = 3;

if (sendmsg (s, &mh, 0) == -1)
if( sendmsg (s, &mh, 0) == -1 ) {
#else /* not HAVE_SYS_UIO_H */
memcpy (msgbuf+sizeof ih+sizeof uh, msg, msglen);
memcpy (msgbuf+sizeof ih, & uh, sizeof uh);
memcpy (msgbuf, & ih, sizeof ih);

if (sendto (s, msgbuf, length, flags,
(struct sockaddr *)&dest_a, sizeof dest_a) == -1)
if( ipv6 ) {
memcpy (msgbuf, msg, msglen);
} else {
memcpy (msgbuf+sizeof ih+sizeof uh, msg, msglen);
memcpy (msgbuf+sizeof ih, & uh, sizeof uh);
memcpy (msgbuf, & ih, sizeof ih);
}

if( sendto (s, msgbuf, length, flags,
(struct sockaddr *)&dest_a, sizeof dest_a) == -1 ) {
#endif /* not HAVE_SYS_UIO_H */
{
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &sockerr, &sockerr_size) == 0)
{
fprintf (stderr, "socket error: %d\n", sockerr);
fprintf (stderr, "socket: %s\n",
strerror (errno));
}
return -1;
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &sockerr, &sockerr_size) == 0)
{
fprintf (stderr, "socket error: %d\n", sockerr);
fprintf (stderr, "socket: %s\n",
strerror (errno));
}
return -1;
}
return 0;
}
#undef saddr
#undef daddr
#undef saddr_v6
#undef daddr_v6

extern int
make_raw_udp_socket (sockbuflen, af)
size_t sockbuflen;
int af;
{
int s;
if (af == AF_INET6)
{
fprintf (stderr, "Spoofing not supported for IPv6\n");
return -1;
}
if ((s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
return s;
int i=0;
if ((s = socket ( af == AF_INET ? PF_INET : PF_INET6 , SOCK_DGRAM, af == AF_INET ? IPPROTO_RAW : IPPROTO_UDP)) == -1)
return s;
if (sockbuflen != -1)
{
if (setsockopt (s, SOL_SOCKET, SO_SNDBUF,
(char *) &sockbuflen, sizeof sockbuflen) == -1)
{
fprintf (stderr, "setsockopt(SO_SNDBUF,%ld): %s\n",
sockbuflen, strerror (errno));
}
}

{
if (setsockopt (s, SOL_SOCKET, SO_SNDBUF,
(char *) &sockbuflen, sizeof sockbuflen) == -1)
{
fprintf (stderr, "setsockopt(SO_SNDBUF,%ld): %s\n",
sockbuflen, strerror (errno));
}
}
#ifdef IP_HDRINCL
/* Some BSD-derived systems require the IP_HDRINCL socket option for
header spoofing. Contributed by Vladimir A. Jakovenko
<vovik@lucky.net> */
{
int on = 1;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0)
{
fprintf (stderr, "setsockopt(IP_HDRINCL,%d): %s\n",
on, strerror (errno));
}
}
/* Some BSD-derived systems require the IP_HDRINCL socket option for
header spoofing. Contributed by Vladimir A. Jakovenko
<vovik@lucky.net> */
if (af == AF_INET )
{
int on = 1;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0)
{
fprintf (stderr, "setsockopt(IP_HDRINCL,%d): %s\n",
on, strerror (errno));
}
}
#endif /* IP_HDRINCL */

return s;
}

Expand Down Expand Up @@ -253,6 +296,71 @@ ip_header_checksum (const void * header)
return ~csum & 0xffff;
}

/* IPv6 UDP header as per RFC 2460 */
struct udp_v6_pseudo_header {
struct in6_addr src_addr;
struct in6_addr dest_addr;
uint32_t len_udp;
uint32_t zeros:24 ;
uint8_t next_header;
uint16_t src_port;
uint16_t dest_port;
uint16_t len;
} __attribute__((packed));

/* This union will allow us to calculate the header with a simple for loop */
union udp_v6_sum {
struct udp_v6_pseudo_header p_hdr;
uint16_t hdr[23];
};

uint16_t udp_sum_calc_v6(
struct in6_addr src_addr,
uint16_t src_port,
struct in6_addr dest_addr,
uint16_t dest_port,
uint16_t len_udp,
const char *buff
)
{
union udp_v6_sum sum;
uint16_t pad = 0;
uint32_t csum = 0;
size_t i = 0;

bzero ( &sum , sizeof (union udp_v6_sum));
sum.p_hdr.src_addr=src_addr;
sum.p_hdr.dest_addr=dest_addr;
sum.p_hdr.len_udp = htons(len_udp+8);
sum.p_hdr.next_header = 17;
sum.p_hdr.src_port = src_port;
sum.p_hdr.dest_port = dest_port;
sum.p_hdr.len = htons(len_udp+8);

for( i = 0; i < 24 ; i++ ) {
csum += (uint32_t)ntohs(sum.hdr[i]);
}

if( len_udp%2 != 0 ) {
pad = 1;
}

for( i=0; i< ( len_udp - pad ); i+=2 ) {
csum += (uint32_t) ntohs(*(uint16_t*) buff);
buff += 2;
}

if( pad ) {
csum += (uint32_t) ( *(uint8_t *) buff );
}

while ( csum>>16 ) {
csum = ( csum & 0xFFFF ) + ( csum >> 16 );
}

return htons((uint16_t) ~csum) ;
}

uint16_t udp_sum_calc( uint16_t len_udp,
uint32_t src_addr,
uint16_t src_port,
Expand Down

0 comments on commit 76bdfae

Please sign in to comment.