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
4956
5057static unsigned ip_header_checksum (const void * header );
5158static 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
5361int
5462raw_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
186234extern int
187235make_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+
256364uint16_t udp_sum_calc ( uint16_t len_udp ,
257365 uint32_t src_addr ,
258366 uint16_t src_port ,
0 commit comments