flexnbd-proxy: Add UNIX socket support for the listen address

This commit is contained in:
nick
2013-04-15 16:52:54 +01:00
parent 4e70db8d7f
commit 33ee19dc5a
6 changed files with 78 additions and 32 deletions

View File

@@ -8,6 +8,7 @@ int atoi(const char *nptr);
((x) >= 'A' && (x) <= 'F' ) || \
(x) == ':' || (x) == '.' \
)
/* FIXME: should change this to return negative on error like everything else */
int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
{
@@ -47,6 +48,22 @@ int parse_ip_to_sockaddr(struct sockaddr* out, char* src)
return 0;
}
int parse_to_sockaddr(struct sockaddr* out, char* address)
{
struct sockaddr_un* un = (struct sockaddr_un*) out;
NULLCHECK( address );
if ( address[0] == '/' ) {
un->sun_family = AF_UNIX;
strncpy( un->sun_path, address, 108 ); /* FIXME: linux only */
return 1;
}
return parse_ip_to_sockaddr( out, address );
}
int parse_acl(struct ip_and_mask (**out)[], int max, char **entries)
{
struct ip_and_mask* list;

View File

@@ -2,6 +2,8 @@
#define PARSE_H
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <unistd.h>
@@ -10,6 +12,7 @@ union mysockaddr {
struct sockaddr generic;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
struct sockaddr_un un;
};
struct ip_and_mask {
@@ -18,6 +21,7 @@ struct ip_and_mask {
};
int parse_ip_to_sockaddr(struct sockaddr* out, char* src);
int parse_to_sockaddr(struct sockaddr* out, char* src);
int parse_acl(struct ip_and_mask (**out)[], int max, char **entries);
void parse_port( char *s_port, struct sockaddr_in *out );

View File

@@ -19,10 +19,11 @@ static struct option proxy_options[] = {
static char proxy_short_options[] = "hl:p:C:P:b:" SOPT_QUIET SOPT_VERBOSE;
static char proxy_help_text[] =
"Usage: flexnbd-proxy <options>\n\n"
"Resiliently proxy an NBD connection between client and server\n\n"
"Resiliently proxy an NBD connection between client and server\n"
"We can listen on TCP or UNIX socket, but only connect to TCP servers.\n\n"
HELP_LINE
"\t--" OPT_ADDR ",-l <ADDR>\tThe address we will bind to as a proxy.\n"
"\t--" OPT_PORT ",-p <PORT>\tThe port we will bind to as a proxy.\n"
"\t--" OPT_PORT ",-p <PORT>\tThe port we will bind to as a proxy, if required.\n"
"\t--" OPT_CONNECT_ADDR ",-C <ADDR>\tAddress of the proxied server.\n"
"\t--" OPT_CONNECT_PORT ",-P <PORT>\tPort of the proxied server.\n"
"\t--" OPT_BIND ",-b <ADDR>\tThe address we connect from, as a proxy.\n"
@@ -114,8 +115,8 @@ int main( int argc, char *argv[] )
);
}
if ( NULL == downstream_addr || NULL == downstream_port ){
fprintf( stderr, "both --addr and --port are required.\n" );
if ( NULL == downstream_addr ){
fprintf( stderr, "--addr is required.\n" );
exit_err( proxy_help_text );
} else if ( NULL == upstream_addr || NULL == upstream_port ){
fprintf( stderr, "both --conn-addr and --conn-port are required.\n" );
@@ -136,10 +137,17 @@ int main( int argc, char *argv[] )
sigaction(SIGINT, &exit_action, NULL);
signal(SIGPIPE, SIG_IGN); /* calls to splice() unhelpfully throw this */
info(
"Proxying between %s %s (downstream) and %s %s (upstream)",
downstream_addr, downstream_port, upstream_addr, upstream_port
);
if ( NULL != downstream_port ) {
info(
"Proxying between %s %s (downstream) and %s %s (upstream)",
downstream_addr, downstream_port, upstream_addr, upstream_port
);
} else {
info(
"Proxying between %s (downstream) and %s %s (upstream)",
downstream_addr, upstream_addr, upstream_port
);
}
success = do_proxy( proxy );
proxy_destroy( proxy );

View File

@@ -24,15 +24,15 @@ struct proxier* proxy_create(
NULLCHECK( s_downstream_address );
FATAL_UNLESS(
parse_ip_to_sockaddr( &out->listen_on.generic, s_downstream_address ),
"Couldn't parse downstream address '%s' (use 0 if "
"you want to bind all IPs)",
s_downstream_address
parse_to_sockaddr( &out->listen_on.generic, s_downstream_address ),
"Couldn't parse downstream address %s"
);
FATAL_IF_NULL( s_downstream_port, "Downstream port not specified" );
NULLCHECK( s_downstream_port );
parse_port( s_downstream_port, &out->listen_on.v4 );
if ( out->listen_on.family != AF_UNIX ) {
FATAL_IF_NULL( s_downstream_port, "Downstream port not specified" );
NULLCHECK( s_downstream_port );
parse_port( s_downstream_port, &out->listen_on.v4 );
}
FATAL_IF_NULL(s_upstream_address, "Upstream address not specified");
NULLCHECK( s_upstream_address );
@@ -143,10 +143,12 @@ void proxy_open_listen_socket(struct proxier* params)
SHOW_ERRNO( "Couldn't set SO_REUSEADDR" )
);
FATAL_IF_NEGATIVE(
sock_set_tcp_nodelay(params->listen_fd, 1),
SHOW_ERRNO( "Couldn't set TCP_NODELAY" )
);
if( AF_UNIX != params->listen_on.family ) {
FATAL_IF_NEGATIVE(
sock_set_tcp_nodelay(params->listen_fd, 1),
SHOW_ERRNO( "Couldn't set TCP_NODELAY" )
);
}
FATAL_UNLESS_ZERO(
sock_try_bind( params->listen_fd, &params->listen_on.generic ),
@@ -379,8 +381,10 @@ int proxy_accept( struct proxier* params )
if ( FD_ISSET( params->listen_fd, &fds ) ) {
client_fd = accept( params->listen_fd, &client_address.generic, &socklen );
if ( sock_set_tcp_nodelay(client_fd, 1) == -1 ) {
warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) );
if ( client_address.family != AF_UNIX ) {
if ( sock_set_tcp_nodelay(client_fd, 1) == -1 ) {
warn( SHOW_ERRNO( "Failed to set TCP_NODELAY" ) );
}
}
info( "Accepted nbd client socket fd %d", client_fd );
@@ -440,6 +444,12 @@ void proxy_cleanup( struct proxier* proxy )
proxy->upstream_fd = -1;
}
if ( AF_UNIX == proxy->listen_on.family ) {
if ( -1 == unlink( proxy->listen_on.un.sun_path ) ) {
warn( SHOW_ERRNO( "Failed to unlink %s", proxy->listen_on.un.sun_path ) );
}
}
debug( "Cleanup done" );
}

View File

@@ -4,12 +4,14 @@
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include "sockutil.h"
#include "util.h"
size_t sockaddr_size( const struct sockaddr* sa )
{
struct sockaddr_un* un = (struct sockaddr_un*) sa;
size_t ret = 0;
switch( sa->sa_family ) {
@@ -19,6 +21,9 @@ size_t sockaddr_size( const struct sockaddr* sa )
case AF_INET6:
ret = sizeof( struct sockaddr_in6 );
break;
case AF_UNIX:
ret = sizeof( un->sun_family ) + SUN_LEN( un );
break;
}
return ret;
@@ -31,6 +36,7 @@ const char* sockaddr_address_string( const struct sockaddr* sa, char* dest, size
struct sockaddr_in* in = ( struct sockaddr_in* ) sa;
struct sockaddr_in6* in6 = ( struct sockaddr_in6* ) sa;
struct sockaddr_un* un = ( struct sockaddr_un* ) sa;
unsigned short real_port = ntohs( in->sin_port ); // common to in and in6
size_t size;
@@ -42,13 +48,15 @@ const char* sockaddr_address_string( const struct sockaddr* sa, char* dest, size
ret = inet_ntop( AF_INET, &in->sin_addr, dest, len );
} else if ( sa->sa_family == AF_INET6 ) {
ret = inet_ntop( AF_INET6, &in6->sin6_addr, dest, len );
} else if ( sa->sa_family == AF_UNIX ) {
ret = strncpy( dest, un->sun_path, SUN_LEN( un ) );
}
if ( ret == NULL ) {
strncpy( dest, "???", len );
}
if ( NULL != ret && real_port > 0 ) {
if ( NULL != ret && real_port > 0 && sa->sa_family != AF_UNIX ) {
size = strlen( dest );
snprintf( dest + size, len - size, " port %d", real_port );
}