2020-05-08 10:46:08 -07:00
// SPDX-License-Identifier: GPL-2.0-only
# include <errno.h>
# include <stdbool.h>
# include <stdio.h>
# include <string.h>
# include <unistd.h>
2020-05-14 13:03:48 -07:00
2020-05-19 00:45:48 +02:00
# include <arpa/inet.h>
2020-05-14 13:03:48 -07:00
# include <sys/epoll.h>
2020-05-08 10:46:08 -07:00
# include <linux/err.h>
# include <linux/in.h>
# include <linux/in6.h>
2020-05-14 13:03:48 -07:00
# include "bpf_util.h"
2020-05-08 10:46:08 -07:00
# include "network_helpers.h"
# define clean_errno() (errno == 0 ? "None" : strerror(errno))
# define log_err(MSG, ...) fprintf(stderr, "(%s:%d: errno: %s) " MSG "\n", \
__FILE__ , __LINE__ , clean_errno ( ) , # # __VA_ARGS__ )
2020-05-08 10:46:09 -07:00
struct ipv4_packet pkt_v4 = {
. eth . h_proto = __bpf_constant_htons ( ETH_P_IP ) ,
. iph . ihl = 5 ,
. iph . protocol = IPPROTO_TCP ,
. iph . tot_len = __bpf_constant_htons ( MAGIC_BYTES ) ,
. tcp . urg_ptr = 123 ,
. tcp . doff = 5 ,
} ;
struct ipv6_packet pkt_v6 = {
. eth . h_proto = __bpf_constant_htons ( ETH_P_IPV6 ) ,
. iph . nexthdr = IPPROTO_TCP ,
. iph . payload_len = __bpf_constant_htons ( MAGIC_BYTES ) ,
. tcp . urg_ptr = 123 ,
. tcp . doff = 5 ,
} ;
2020-05-19 00:45:48 +02:00
int start_server_with_port ( int family , int type , __u16 port )
2020-05-08 10:46:08 -07:00
{
struct sockaddr_storage addr = { } ;
socklen_t len ;
int fd ;
if ( family = = AF_INET ) {
struct sockaddr_in * sin = ( void * ) & addr ;
sin - > sin_family = AF_INET ;
2020-05-19 00:45:48 +02:00
sin - > sin_port = htons ( port ) ;
2020-05-08 10:46:08 -07:00
len = sizeof ( * sin ) ;
} else {
struct sockaddr_in6 * sin6 = ( void * ) & addr ;
sin6 - > sin6_family = AF_INET6 ;
2020-05-19 00:45:48 +02:00
sin6 - > sin6_port = htons ( port ) ;
2020-05-08 10:46:08 -07:00
len = sizeof ( * sin6 ) ;
}
fd = socket ( family , type | SOCK_NONBLOCK , 0 ) ;
if ( fd < 0 ) {
log_err ( " Failed to create server socket " ) ;
return - 1 ;
}
if ( bind ( fd , ( const struct sockaddr * ) & addr , len ) < 0 ) {
log_err ( " Failed to bind socket " ) ;
close ( fd ) ;
return - 1 ;
}
if ( type = = SOCK_STREAM ) {
if ( listen ( fd , 1 ) < 0 ) {
log_err ( " Failed to listed on socket " ) ;
close ( fd ) ;
return - 1 ;
}
}
return fd ;
}
2020-05-19 00:45:48 +02:00
int start_server ( int family , int type )
{
return start_server_with_port ( family , type , 0 ) ;
}
2020-05-08 10:46:08 -07:00
static const struct timeval timeo_sec = { . tv_sec = 3 } ;
static const size_t timeo_optlen = sizeof ( timeo_sec ) ;
int connect_to_fd ( int family , int type , int server_fd )
{
2020-05-14 13:03:48 -07:00
int fd , save_errno ;
2020-05-08 10:46:08 -07:00
fd = socket ( family , type , 0 ) ;
if ( fd < 0 ) {
log_err ( " Failed to create client socket " ) ;
return - 1 ;
}
2020-05-14 13:03:48 -07:00
if ( connect_fd_to_fd ( fd , server_fd ) < 0 & & errno ! = EINPROGRESS ) {
save_errno = errno ;
close ( fd ) ;
errno = save_errno ;
return - 1 ;
}
return fd ;
}
int connect_fd_to_fd ( int client_fd , int server_fd )
{
struct sockaddr_storage addr ;
socklen_t len = sizeof ( addr ) ;
int save_errno ;
if ( setsockopt ( client_fd , SOL_SOCKET , SO_RCVTIMEO , & timeo_sec ,
timeo_optlen ) ) {
2020-05-08 10:46:08 -07:00
log_err ( " Failed to set SO_RCVTIMEO " ) ;
2020-05-14 13:03:48 -07:00
return - 1 ;
2020-05-08 10:46:08 -07:00
}
if ( getsockname ( server_fd , ( struct sockaddr * ) & addr , & len ) ) {
log_err ( " Failed to get server addr " ) ;
2020-05-14 13:03:48 -07:00
return - 1 ;
2020-05-08 10:46:08 -07:00
}
2020-05-14 13:03:48 -07:00
if ( connect ( client_fd , ( const struct sockaddr * ) & addr , len ) < 0 ) {
if ( errno ! = EINPROGRESS ) {
save_errno = errno ;
log_err ( " Failed to connect to server " ) ;
errno = save_errno ;
}
return - 1 ;
2020-05-08 10:46:08 -07:00
}
2020-05-14 13:03:48 -07:00
return 0 ;
}
int connect_wait ( int fd )
{
struct epoll_event ev = { } , events [ 2 ] ;
int timeout_ms = 1000 ;
int efd , nfd ;
efd = epoll_create1 ( EPOLL_CLOEXEC ) ;
if ( efd < 0 ) {
log_err ( " Failed to open epoll fd " ) ;
return - 1 ;
}
ev . events = EPOLLRDHUP | EPOLLOUT ;
ev . data . fd = fd ;
if ( epoll_ctl ( efd , EPOLL_CTL_ADD , fd , & ev ) < 0 ) {
log_err ( " Failed to register fd=%d on epoll fd=%d " , fd , efd ) ;
close ( efd ) ;
return - 1 ;
}
nfd = epoll_wait ( efd , events , ARRAY_SIZE ( events ) , timeout_ms ) ;
if ( nfd < 0 )
log_err ( " Failed to wait for I/O event on epoll fd=%d " , efd ) ;
2020-05-08 10:46:08 -07:00
2020-05-14 13:03:48 -07:00
close ( efd ) ;
return nfd ;
2020-05-08 10:46:08 -07:00
}