Skip to content

Commit 76bdfae

Browse files
dkhenryKoz
authored andcommitted
Adding support to spoof ipv6
Samplicator can not spoof IPv6 packes as well as IPv4 packets.
1 parent 7b4e009 commit 76bdfae

File tree

1 file changed

+206
-98
lines changed

1 file changed

+206
-98
lines changed

rawsend.c

Lines changed: 206 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,16 @@
3030
#include <netinet/in_systm.h>
3131
#endif
3232
#include <sys/socket.h>
33+
34+
#ifndef __APPLE_USE_RFC_3542
35+
#define __APPLE_USE_RFC_3542
36+
#endif
37+
3338
#include <netinet/in.h>
3439
#include <netinet/ip.h>
40+
#include <netinet/ip6.h>
3541
#include <sys/uio.h>
42+
#include <sys/ioctl.h>
3643

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

5057
static unsigned ip_header_checksum (const void * header);
5158
static uint16_t udp_sum_calc (uint16_t, uint32_t, uint16_t, uint32_t, uint16_t, const void *);
59+
static uint16_t udp_sum_calc_v6 (struct in6_addr, uint16_t, struct in6_addr, uint16_t, uint16_t, const char *);
5260

5361
int
5462
raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
@@ -61,37 +69,44 @@ raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
6169
int flags;
6270
#define saddr ((struct sockaddr_in *) saddr_generic)
6371
#define daddr ((struct sockaddr_in *) daddr_generic)
72+
#define saddr_v6 ((struct sockaddr_in6 *) saddr_generic)
73+
#define daddr_v6 ((struct sockaddr_in6 *) daddr_generic)
74+
#define ipv6 (saddr_generic->sa_family == AF_INET6 && daddr_generic->sa_family == AF_INET6)
6475
{
6576
int length;
6677
int sockerr;
6778
socklen_t sockerr_size = sizeof sockerr;
68-
struct sockaddr_in dest_a;
79+
struct sockaddr_storage dest_a;
6980
struct ip ih;
7081
struct udphdr uh;
7182

7283
#ifdef HAVE_SYS_UIO_H
73-
struct msghdr mh;
84+
struct msghdr mh = {};
7485
struct iovec iov[3];
7586
#else /* not HAVE_SYS_UIO_H */
76-
int flags = 0;
87+
flags = 0;
7788
static char *msgbuf = 0;
7889
static size_t msgbuflen = 0;
7990
static size_t next_alloc_size = 1;
8091
#endif /* not HAVE_SYS_UIO_H */
8192

82-
uh.uh_sport = saddr->sin_port;
83-
uh.uh_dport = daddr->sin_port;
93+
if( ipv6 ) {
94+
length = msglen;
95+
} else {
96+
uh.uh_sport = saddr->sin_port;
97+
uh.uh_dport = daddr->sin_port;
98+
uh.uh_sum = flags & RAWSEND_COMPUTE_UDP_CHECKSUM
99+
? udp_sum_calc (msglen,
100+
ntohl(saddr->sin_addr.s_addr),
101+
ntohs(saddr->sin_port),
102+
ntohl(daddr->sin_addr.s_addr),
103+
ntohs(daddr->sin_port),
104+
msg)
105+
: 0;
106+
length = msglen + sizeof uh + sizeof ih;
107+
}
84108
uh.uh_ulen = htons (msglen + sizeof uh);
85-
uh.uh_sum = flags & RAWSEND_COMPUTE_UDP_CHECKSUM
86-
? udp_sum_calc (msglen,
87-
ntohl(saddr->sin_addr.s_addr),
88-
ntohs(saddr->sin_port),
89-
ntohl(daddr->sin_addr.s_addr),
90-
ntohs(daddr->sin_port),
91-
msg)
92-
: 0;
93-
94-
length = msglen + sizeof uh + sizeof ih;
109+
95110
#ifndef HAVE_SYS_UIO_H
96111
if (length > msgbuflen)
97112
{
@@ -112,114 +127,142 @@ raw_send_from_to (s, msg, msglen, saddr_generic, daddr_generic, ttl, flags)
112127
next_alloc_size *= 2;
113128
}
114129
#endif /* not HAVE_SYS_UIO_H */
115-
ih.ip_hl = (sizeof ih+3)/4;
116-
ih.ip_v = 4;
117-
ih.ip_tos = 0;
118-
/* Depending on the target platform, te ip_off and ip_len fields
119-
should be in either host or network byte order. Usually
120-
BSD-derivatives require host byte order, but at least OpenBSD
121-
since version 2.1 uses network byte order. Linux uses network
122-
byte order for all IP header fields. */
130+
131+
if( ipv6 ) {
132+
((struct sockaddr_in6*) &dest_a)->sin6_family = AF_INET6;
133+
((struct sockaddr_in6*) &dest_a)->sin6_port = daddr_v6->sin6_port;
134+
((struct sockaddr_in6*) &dest_a)->sin6_addr = daddr_v6->sin6_addr;
135+
} else {
136+
ih.ip_hl = (sizeof ih+3)/4;
137+
ih.ip_v = 4;
138+
ih.ip_tos = 0;
139+
140+
/* Depending on the target platform, te ip_off and ip_len fields
141+
should be in either host or network byte order. Usually
142+
BSD-derivatives require host byte order, but at least OpenBSD
143+
since version 2.1 uses network byte order. Linux uses network
144+
byte order for all IP header fields. */
123145
#if defined (__linux__) || (defined (__OpenBSD__) && (OpenBSD > 199702))
124-
ih.ip_len = htons (length);
125-
ih.ip_off = htons (0);
146+
ih.ip_len = htons (length);
147+
ih.ip_off = htons (0);
126148
#else
127-
ih.ip_len = length;
128-
ih.ip_off = 0;
149+
ih.ip_len = length;
150+
ih.ip_off = 0;
129151
#endif
130-
ih.ip_id = htons (0);
131-
ih.ip_ttl = ttl;
132-
ih.ip_p = 17;
133-
ih.ip_sum = htons (0);
134-
ih.ip_src.s_addr = saddr->sin_addr.s_addr;
135-
ih.ip_dst.s_addr = daddr->sin_addr.s_addr;
136-
137-
/* At least on Solaris, it seems clear that even the raw IP datagram
138-
transmission code will actually compute the IP header checksum
139-
for us. Probably this is the case for all other systems on which
140-
this code works, so maybe we should just set the checksum to zero
141-
to avoid duplicate work. I'm not even sure whether my IP
142-
checksum computation in ip_header_checksum() below is correct. */
143-
ih.ip_sum = ip_header_checksum (&ih);
144-
145-
dest_a.sin_family = AF_INET;
146-
dest_a.sin_port = daddr->sin_port;
147-
dest_a.sin_addr.s_addr = daddr->sin_addr.s_addr;
148-
152+
ih.ip_id = htons (0);
153+
ih.ip_ttl = ttl;
154+
ih.ip_p = 17;
155+
ih.ip_sum = htons (0);
156+
ih.ip_src.s_addr = saddr->sin_addr.s_addr;
157+
ih.ip_dst.s_addr = daddr->sin_addr.s_addr;
158+
159+
/* At least on Solaris, it seems clear that even the raw IP datagram
160+
transmission code will actually compute the IP header checksum
161+
for us. Probably this is the case for all other systems on which
162+
this code works, so maybe we should just set the checksum to zero
163+
to avoid duplicate work. I'm not even sure whether my IP
164+
checksum computation in ip_header_checksum() below is correct. */
165+
ih.ip_sum = ip_header_checksum (&ih);
166+
167+
((struct sockaddr_in*) &dest_a)->sin_family = AF_INET;
168+
((struct sockaddr_in*) &dest_a)->sin_port = daddr->sin_port;
169+
((struct sockaddr_in*) &dest_a)->sin_addr.s_addr = daddr->sin_addr.s_addr;
170+
}
171+
int err = 0;
149172
#ifdef HAVE_SYS_UIO_H
150-
iov[0].iov_base = (char *) &ih;
151-
iov[0].iov_len = sizeof ih;
152-
iov[1].iov_base = (char *) &uh;
153-
iov[1].iov_len = sizeof uh;
154-
iov[2].iov_base = (char *) msg;
155-
iov[2].iov_len = msglen;
156-
157-
bzero ((char *) &mh, sizeof mh);
173+
174+
if( ipv6 ) {
175+
iov[0].iov_base = (char *) msg;
176+
iov[0].iov_len = msglen;
177+
mh.msg_iovlen = 1;
178+
179+
// Set the PKT information to spoof the source
180+
size_t cmsglen = CMSG_SPACE (sizeof (struct in6_pktinfo));
181+
mh.msg_control = calloc (1,cmsglen);
182+
mh.msg_controllen = cmsglen;
183+
184+
struct cmsghdr *hdr1 = CMSG_FIRSTHDR(&mh);
185+
hdr1->cmsg_level = IPPROTO_IPV6;
186+
hdr1->cmsg_type = IPV6_PKTINFO;
187+
hdr1->cmsg_len = CMSG_LEN (sizeof (struct in6_pktinfo));
188+
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *) CMSG_DATA (hdr1);
189+
pktinfo->ipi6_ifindex = 0;
190+
pktinfo->ipi6_addr = saddr_v6->sin6_addr;
191+
} else {
192+
iov[0].iov_base = (char *) &ih;
193+
iov[0].iov_len = sizeof ih;
194+
iov[1].iov_base = (char *) &uh;
195+
iov[1].iov_len = sizeof uh;
196+
iov[2].iov_base = (char *) msg;
197+
iov[2].iov_len = msglen;
198+
mh.msg_iovlen = 3;
199+
}
200+
201+
158202
mh.msg_name = (char *)&dest_a;
159203
mh.msg_namelen = sizeof dest_a;
160204
mh.msg_iov = iov;
161-
mh.msg_iovlen = 3;
162205

163-
if (sendmsg (s, &mh, 0) == -1)
206+
if( sendmsg (s, &mh, 0) == -1 ) {
164207
#else /* not HAVE_SYS_UIO_H */
165-
memcpy (msgbuf+sizeof ih+sizeof uh, msg, msglen);
166-
memcpy (msgbuf+sizeof ih, & uh, sizeof uh);
167-
memcpy (msgbuf, & ih, sizeof ih);
168-
169-
if (sendto (s, msgbuf, length, flags,
170-
(struct sockaddr *)&dest_a, sizeof dest_a) == -1)
208+
if( ipv6 ) {
209+
memcpy (msgbuf, msg, msglen);
210+
} else {
211+
memcpy (msgbuf+sizeof ih+sizeof uh, msg, msglen);
212+
memcpy (msgbuf+sizeof ih, & uh, sizeof uh);
213+
memcpy (msgbuf, & ih, sizeof ih);
214+
}
215+
216+
if( sendto (s, msgbuf, length, flags,
217+
(struct sockaddr *)&dest_a, sizeof dest_a) == -1 ) {
171218
#endif /* not HAVE_SYS_UIO_H */
172-
{
173-
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &sockerr, &sockerr_size) == 0)
174-
{
175-
fprintf (stderr, "socket error: %d\n", sockerr);
176-
fprintf (stderr, "socket: %s\n",
177-
strerror (errno));
178-
}
179-
return -1;
219+
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &sockerr, &sockerr_size) == 0)
220+
{
221+
fprintf (stderr, "socket error: %d\n", sockerr);
222+
fprintf (stderr, "socket: %s\n",
223+
strerror (errno));
224+
}
225+
return -1;
180226
}
181227
return 0;
182228
}
183229
#undef saddr
184230
#undef daddr
231+
#undef saddr_v6
232+
#undef daddr_v6
185233

186234
extern int
187235
make_raw_udp_socket (sockbuflen, af)
188236
size_t sockbuflen;
189237
int af;
190238
{
191239
int s;
192-
if (af == AF_INET6)
193-
{
194-
fprintf (stderr, "Spoofing not supported for IPv6\n");
195-
return -1;
196-
}
197-
if ((s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1)
198-
return s;
240+
int i=0;
241+
if ((s = socket ( af == AF_INET ? PF_INET : PF_INET6 , SOCK_DGRAM, af == AF_INET ? IPPROTO_RAW : IPPROTO_UDP)) == -1)
242+
return s;
199243
if (sockbuflen != -1)
200-
{
201-
if (setsockopt (s, SOL_SOCKET, SO_SNDBUF,
202-
(char *) &sockbuflen, sizeof sockbuflen) == -1)
203-
{
204-
fprintf (stderr, "setsockopt(SO_SNDBUF,%ld): %s\n",
205-
sockbuflen, strerror (errno));
206-
}
207-
}
208-
244+
{
245+
if (setsockopt (s, SOL_SOCKET, SO_SNDBUF,
246+
(char *) &sockbuflen, sizeof sockbuflen) == -1)
247+
{
248+
fprintf (stderr, "setsockopt(SO_SNDBUF,%ld): %s\n",
249+
sockbuflen, strerror (errno));
250+
}
251+
}
209252
#ifdef IP_HDRINCL
210-
/* Some BSD-derived systems require the IP_HDRINCL socket option for
211-
header spoofing. Contributed by Vladimir A. Jakovenko
212-
<vovik@lucky.net> */
213-
{
214-
int on = 1;
215-
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0)
216-
{
217-
fprintf (stderr, "setsockopt(IP_HDRINCL,%d): %s\n",
218-
on, strerror (errno));
219-
}
220-
}
253+
/* Some BSD-derived systems require the IP_HDRINCL socket option for
254+
header spoofing. Contributed by Vladimir A. Jakovenko
255+
<vovik@lucky.net> */
256+
if (af == AF_INET )
257+
{
258+
int on = 1;
259+
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0)
260+
{
261+
fprintf (stderr, "setsockopt(IP_HDRINCL,%d): %s\n",
262+
on, strerror (errno));
263+
}
264+
}
221265
#endif /* IP_HDRINCL */
222-
223266
return s;
224267
}
225268

@@ -253,6 +296,71 @@ ip_header_checksum (const void * header)
253296
return ~csum & 0xffff;
254297
}
255298

299+
/* IPv6 UDP header as per RFC 2460 */
300+
struct udp_v6_pseudo_header {
301+
struct in6_addr src_addr;
302+
struct in6_addr dest_addr;
303+
uint32_t len_udp;
304+
uint32_t zeros:24 ;
305+
uint8_t next_header;
306+
uint16_t src_port;
307+
uint16_t dest_port;
308+
uint16_t len;
309+
} __attribute__((packed));
310+
311+
/* This union will allow us to calculate the header with a simple for loop */
312+
union udp_v6_sum {
313+
struct udp_v6_pseudo_header p_hdr;
314+
uint16_t hdr[23];
315+
};
316+
317+
uint16_t udp_sum_calc_v6(
318+
struct in6_addr src_addr,
319+
uint16_t src_port,
320+
struct in6_addr dest_addr,
321+
uint16_t dest_port,
322+
uint16_t len_udp,
323+
const char *buff
324+
)
325+
{
326+
union udp_v6_sum sum;
327+
uint16_t pad = 0;
328+
uint32_t csum = 0;
329+
size_t i = 0;
330+
331+
bzero ( &sum , sizeof (union udp_v6_sum));
332+
sum.p_hdr.src_addr=src_addr;
333+
sum.p_hdr.dest_addr=dest_addr;
334+
sum.p_hdr.len_udp = htons(len_udp+8);
335+
sum.p_hdr.next_header = 17;
336+
sum.p_hdr.src_port = src_port;
337+
sum.p_hdr.dest_port = dest_port;
338+
sum.p_hdr.len = htons(len_udp+8);
339+
340+
for( i = 0; i < 24 ; i++ ) {
341+
csum += (uint32_t)ntohs(sum.hdr[i]);
342+
}
343+
344+
if( len_udp%2 != 0 ) {
345+
pad = 1;
346+
}
347+
348+
for( i=0; i< ( len_udp - pad ); i+=2 ) {
349+
csum += (uint32_t) ntohs(*(uint16_t*) buff);
350+
buff += 2;
351+
}
352+
353+
if( pad ) {
354+
csum += (uint32_t) ( *(uint8_t *) buff );
355+
}
356+
357+
while ( csum>>16 ) {
358+
csum = ( csum & 0xFFFF ) + ( csum >> 16 );
359+
}
360+
361+
return htons((uint16_t) ~csum) ;
362+
}
363+
256364
uint16_t udp_sum_calc( uint16_t len_udp,
257365
uint32_t src_addr,
258366
uint16_t src_port,

0 commit comments

Comments
 (0)