2626#include <unistd.h>
2727#include <arpa/inet.h>
2828#include <net/ethernet.h>
29+ #include <net/if.h>
2930#include <netinet/tcp.h>
3031#include <sys/socket.h>
3132#include <linux/if_packet.h>
33+ #include <linux/netfilter.h>
3234#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
3335
3436#include "globvar.h"
@@ -146,9 +148,69 @@ static int remove_tfo_cookie(uint16_t ethertype, uint8_t *pkt,
146148}
147149
148150
151+ /*
152+ This is a workaround for iptables since it does not allow us to intercept
153+ packets after POSTROUTING SNAT, which means the SNATed source address is
154+ unknown.
155+ Instead of using an AF_PACKET socket, we create a temporary AF_INET or
156+ AF_INET6 raw socket, so that the packet gets SNATed correctly.
157+ */
158+ static int sendto_snat (struct sockaddr_ll * sll , struct sockaddr * daddr ,
159+ uint8_t * pkt_buff , int pkt_len )
160+ {
161+ int res , ret , sock_fd ;
162+ ssize_t nbytes ;
163+ char * iface , iface_buf [IF_NAMESIZE ];
164+
165+ ret = -1 ;
166+
167+ iface = if_indextoname (sll -> sll_ifindex , iface_buf );
168+ if (!iface ) {
169+ E ("ERROR: if_indextoname(): %s" , strerror (errno ));
170+ return -1 ;
171+ }
172+
173+ sock_fd = socket (daddr -> sa_family , SOCK_RAW , IPPROTO_RAW );
174+ if (sock_fd < 0 ) {
175+ E ("ERROR: socket(): %s" , strerror (errno ));
176+ return -1 ;
177+ }
178+
179+ res = setsockopt (sock_fd , SOL_SOCKET , SO_BINDTODEVICE , iface ,
180+ strlen (iface ));
181+ if (res < 0 ) {
182+ E ("ERROR: setsockopt(): SO_BINDTODEVICE: %s" , strerror (errno ));
183+ goto close_socket ;
184+ }
185+
186+ res = setsockopt (sock_fd , SOL_SOCKET , SO_MARK , & g_ctx .fwmark ,
187+ sizeof (g_ctx .fwmark ));
188+ if (res < 0 ) {
189+ E ("ERROR: setsockopt(): SO_MARK: %s" , strerror (errno ));
190+ goto close_socket ;
191+ }
192+
193+ nbytes = sendto (sock_fd , pkt_buff , pkt_len , 0 , daddr ,
194+ daddr -> sa_family == AF_INET6 ? sizeof (struct sockaddr_in6 )
195+ : sizeof (struct sockaddr_in ));
196+ if (nbytes < 0 ) {
197+ E ("ERROR: sendto(): %s" , strerror (errno ));
198+ goto close_socket ;
199+ }
200+
201+ ret = nbytes ;
202+
203+ close_socket :
204+ close (sock_fd );
205+
206+ return ret ;
207+ }
208+
209+
149210static int send_payload (struct sockaddr_ll * sll , struct sockaddr * saddr ,
150211 struct sockaddr * daddr , uint8_t ttl , uint16_t sport_be ,
151- uint16_t dport_be , uint32_t seq_be , uint32_t ackseq_be )
212+ uint16_t dport_be , uint32_t seq_be , uint32_t ackseq_be ,
213+ int need_snat )
152214{
153215 int pkt_len ;
154216 ssize_t nbytes ;
@@ -175,11 +237,19 @@ static int send_payload(struct sockaddr_ll *sll, struct sockaddr *saddr,
175237 return -1 ;
176238 }
177239
178- nbytes = sendto (sockfd , pkt_buff , pkt_len , 0 , (struct sockaddr * ) sll ,
179- sizeof (* sll ));
180- if (nbytes < 0 ) {
181- E ("ERROR: sendto(): %s" , strerror (errno ));
182- return -1 ;
240+ if (need_snat ) {
241+ nbytes = sendto_snat (sll , daddr , pkt_buff , pkt_len );
242+ if (nbytes < 0 ) {
243+ E (T (sendto_snat ));
244+ return -1 ;
245+ }
246+ } else {
247+ nbytes = sendto (sockfd , pkt_buff , pkt_len , 0 , (struct sockaddr * ) sll ,
248+ sizeof (* sll ));
249+ if (nbytes < 0 ) {
250+ E ("ERROR: sendto(): %s" , strerror (errno ));
251+ return -1 ;
252+ }
183253 }
184254
185255 return 0 ;
@@ -258,6 +328,7 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
258328 char src_ip [INET6_ADDRSTRLEN ], dst_ip [INET6_ADDRSTRLEN ];
259329 struct sockaddr_storage saddr_store , daddr_store ;
260330 struct sockaddr * saddr , * daddr ;
331+ ssize_t nbytes ;
261332
262333 * modified = 0 ;
263334
@@ -292,14 +363,14 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
292363 if (tcp_payload_len > 0 ) {
293364 E_INFO ("%s:%u ===PAYLOAD(?)===> %s:%u" , src_ip , ntohs (tcph -> source ),
294365 dst_ip , ntohs (tcph -> dest ));
295- return 0 ;
366+ return NF_ACCEPT ;
296367 } else if (sll -> sll_pkttype == PACKET_HOST && tcph -> syn && tcph -> ack ) {
297368 sll -> sll_pkttype = 0 ;
298369
299370 if (!g_ctx .outbound ) {
300371 E_INFO ("%s:%u ===SYN-ACK(?)===> %s:%u" , src_ip ,
301372 ntohs (tcph -> source ), dst_ip , ntohs (tcph -> dest ));
302- return 0 ;
373+ return NF_ACCEPT ;
303374 }
304375
305376 E_INFO ("%s:%u ===SYN-ACK===> %s:%u" , src_ip , ntohs (tcph -> source ),
@@ -316,7 +387,7 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
316387 if (hop <= g_ctx .ttl ) {
317388 E_INFO ("%s:%u ===LOCAL(?)===> %s:%u" , src_ip ,
318389 ntohs (tcph -> source ), dst_ip , ntohs (tcph -> dest ));
319- return 0 ;
390+ return NF_ACCEPT ;
320391 }
321392 snd_ttl = calc_snd_ttl (hop );
322393 }
@@ -325,7 +396,7 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
325396
326397 for (i = 0 ; i < g_ctx .repeat ; i ++ ) {
327398 res = send_payload (sll , daddr , saddr , snd_ttl , tcph -> dest ,
328- tcph -> source , tcph -> ack_seq , ack_new );
399+ tcph -> source , tcph -> ack_seq , ack_new , 0 );
329400 if (res < 0 ) {
330401 E (T (send_payload ));
331402 return -1 ;
@@ -334,7 +405,7 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
334405 E_INFO ("%s:%u <===FAKE(*)=== %s:%u" , src_ip , ntohs (tcph -> source ),
335406 dst_ip , ntohs (tcph -> dest ));
336407
337- return 0 ;
408+ return NF_ACCEPT ;
338409 } else if (sll -> sll_pkttype == PACKET_OUTGOING && tcph -> syn && tcph -> ack ) {
339410 sll -> sll_pkttype = 0 ;
340411
@@ -343,12 +414,9 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
343414 if (!g_ctx .inbound || srcinfo_unavail ) {
344415 E_INFO ("%s:%u <===SYN-ACK(?)=== %s:%u" , dst_ip , ntohs (tcph -> dest ),
345416 src_ip , ntohs (tcph -> source ));
346- return 0 ;
417+ return NF_ACCEPT ;
347418 }
348419
349- E_INFO ("%s:%u <===SYN-ACK=== %s:%u" , dst_ip , ntohs (tcph -> dest ), src_ip ,
350- ntohs (tcph -> source ));
351-
352420 seq_new = ntohl (tcph -> seq );
353421 seq_new ++ ;
354422 seq_new = htonl (seq_new );
@@ -360,7 +428,7 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
360428 if (hop <= g_ctx .ttl ) {
361429 E_INFO ("%s:%u <===LOCAL(?)=== %s:%u" , src_ip ,
362430 ntohs (tcph -> source ), dst_ip , ntohs (tcph -> dest ));
363- return 0 ;
431+ return NF_ACCEPT ;
364432 }
365433 snd_ttl = calc_snd_ttl (hop );
366434 }
@@ -369,7 +437,8 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
369437
370438 for (i = 0 ; i < g_ctx .repeat ; i ++ ) {
371439 res = send_payload (sll , saddr , daddr , snd_ttl , tcph -> source ,
372- tcph -> dest , seq_new , tcph -> ack_seq );
440+ tcph -> dest , seq_new , tcph -> ack_seq ,
441+ g_ctx .use_iptables /* needs SNAT */ );
373442 if (res < 0 ) {
374443 E (T (send_payload ));
375444 return -1 ;
@@ -378,12 +447,37 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
378447 E_INFO ("%s:%u <===FAKE(*)=== %s:%u" , dst_ip , ntohs (tcph -> dest ), src_ip ,
379448 ntohs (tcph -> source ));
380449
381- return 0 ;
450+ /*
451+ We send the original packet using a raw socket and discard the
452+ current processing flow.
453+ This ensures that the SYN-ACK is transmitted after the payload.
454+ Although this deliberately causes a TCP out-of-order situation,
455+ it guarantees that our payload is always sent before the client's
456+ packet.
457+ */
458+ if (g_ctx .use_iptables ) {
459+ nbytes = sendto_snat (sll , daddr , pkt_data , pkt_len );
460+ if (nbytes < 0 ) {
461+ E (T (sendto_snat ));
462+ return -1 ;
463+ }
464+ } else {
465+ nbytes = sendto (sockfd , pkt_data , pkt_len , 0 ,
466+ (struct sockaddr * ) sll , sizeof (* sll ));
467+ if (nbytes < 0 ) {
468+ E ("ERROR: sendto(): %s" , strerror (errno ));
469+ return -1 ;
470+ }
471+ }
472+
473+ E_INFO ("%s:%u <===SYN-ACK=== %s:%u" , dst_ip , ntohs (tcph -> dest ), src_ip ,
474+ ntohs (tcph -> source ));
475+ return NF_DROP ;
382476 } else if (sll -> sll_pkttype == PACKET_HOST && tcph -> syn ) {
383477 if (!g_ctx .inbound ) {
384478 E_INFO ("%s:%u ===SYN(?)===> %s:%u" , src_ip , ntohs (tcph -> source ),
385479 dst_ip , ntohs (tcph -> dest ));
386- return 0 ;
480+ return NF_ACCEPT ;
387481 }
388482
389483 * modified = !remove_tfo_cookie (ethertype , pkt_data , tcph );
@@ -401,12 +495,12 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
401495 return -1 ;
402496 }
403497
404- return 0 ;
498+ return NF_ACCEPT ;
405499 } else if (sll -> sll_pkttype == PACKET_OUTGOING && tcph -> syn ) {
406500 if (!g_ctx .outbound ) {
407501 E_INFO ("%s:%u <===SYN(?)=== %s:%u" , dst_ip , ntohs (tcph -> dest ),
408502 src_ip , ntohs (tcph -> source ));
409- return 0 ;
503+ return NF_ACCEPT ;
410504 }
411505
412506 * modified = !remove_tfo_cookie (ethertype , pkt_data , tcph );
@@ -418,10 +512,10 @@ int fh_rawsend_handle(struct sockaddr_ll *sll, uint8_t *pkt_data, int pkt_len,
418512 ntohs (tcph -> source ));
419513 }
420514
421- return 0 ;
515+ return NF_ACCEPT ;
422516 } else {
423517 E_INFO ("%s:%u ===(?)=== %s:%u" , src_ip , ntohs (tcph -> source ), dst_ip ,
424518 ntohs (tcph -> dest ));
425- return 0 ;
519+ return NF_ACCEPT ;
426520 }
427521}
0 commit comments