diff --git a/src/control.c b/src/control.c index 41ffcd5..8a6e6a8 100644 --- a/src/control.c +++ b/src/control.c @@ -217,7 +217,7 @@ int control_mirror(struct control_params* client, int linesc, char** lines) return -1; } - fd = socket_connect(&connect_to.generic); + fd = socket_connect(&connect_to.generic, NULL); remote_size = socket_nbd_read_hello(fd); remote_size = remote_size; // shush compiler diff --git a/src/flexnbd.c b/src/flexnbd.c index 8580fde..ea580fd 100644 --- a/src/flexnbd.c +++ b/src/flexnbd.c @@ -111,6 +111,7 @@ void params_readwrite( struct mode_readwrite_params* out, char* s_ip_address, char* s_port, + char* s_bind_address, char* s_from, char* s_length_or_filename ) @@ -128,6 +129,9 @@ void params_readwrite( SERVER_ERROR("Couldn't parse connection address '%s'", s_ip_address); + if (s_bind_address != NULL && parse_ip_to_sockaddr(&out->connect_from.generic, s_bind_address) == 0) + SERVER_ERROR("Couldn't parse bind address '%s'", s_bind_address); + /* FIXME: duplicated from above */ out->connect_to.v4.sin_port = atoi(s_port); if (out->connect_to.v4.sin_port < 0 || out->connect_to.v4.sin_port > 65535) @@ -198,7 +202,7 @@ void read_serve_param( int c, char **ip_addr, char **ip_port, char **file, char } -void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **from, char **size) +void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **bind_addr, char **from, char **size) { switch(c){ case 'h': @@ -217,6 +221,9 @@ void read_readwrite_param( int c, char **ip_addr, char **ip_port, char **from, c case 'S': *size = optarg; break; + case 'b': + *bind_addr = optarg; + break; case 'd': set_debug(1); break; @@ -320,8 +327,9 @@ int mode_serve( int argc, char *argv[] ) int mode_read( int argc, char *argv[] ) { int c; - char *ip_addr = NULL; - char *ip_port = NULL; + char *ip_addr = NULL; + char *ip_port = NULL; + char *bind_addr = NULL; char *from = NULL; char *size = NULL; int err = 0; @@ -330,8 +338,11 @@ int mode_read( int argc, char *argv[] ) while (1){ c = getopt_long(argc, argv, read_short_options, read_options, NULL); - if ( c == -1 ) break; - read_readwrite_param( c, &ip_addr, &ip_port, &from, &size ); + + if ( c == -1 ) + break; + + read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size ); } if ( NULL == ip_addr || NULL == ip_port ) { @@ -345,7 +356,7 @@ int mode_read( int argc, char *argv[] ) if ( err ) { exit_err( read_help_text ); } memset( &readwrite, 0, sizeof( readwrite ) ); - params_readwrite( 0, &readwrite, ip_addr, ip_port, from, size ); + params_readwrite( 0, &readwrite, ip_addr, ip_port, bind_addr, from, size ); do_read( &readwrite ); return 0; } @@ -353,8 +364,9 @@ int mode_read( int argc, char *argv[] ) int mode_write( int argc, char *argv[] ) { int c; - char *ip_addr = NULL; - char *ip_port = NULL; + char *ip_addr = NULL; + char *ip_port = NULL; + char *bind_addr = NULL; char *from = NULL; char *size = NULL; int err = 0; @@ -363,8 +375,10 @@ int mode_write( int argc, char *argv[] ) while (1){ c = getopt_long(argc, argv, write_short_options, write_options, NULL); - if ( c == -1 ) break; - read_readwrite_param( c, &ip_addr, &ip_port, &from, &size ); + if ( c == -1 ) + break; + + read_readwrite_param( c, &ip_addr, &ip_port, &bind_addr, &from, &size ); } if ( NULL == ip_addr || NULL == ip_port ) { @@ -378,7 +392,7 @@ int mode_write( int argc, char *argv[] ) if ( err ) { exit_err( write_help_text ); } memset( &readwrite, 0, sizeof( readwrite ) ); - params_readwrite( 1, &readwrite, ip_addr, ip_port, from, size ); + params_readwrite( 1, &readwrite, ip_addr, ip_port, bind_addr, from, size ); do_write( &readwrite ); return 0; } diff --git a/src/options.h b/src/options.h index f25752f..7dea799 100644 --- a/src/options.h +++ b/src/options.h @@ -3,6 +3,7 @@ #define OPT_HELP "help" #define OPT_ADDR "addr" +#define OPT_BIND "bind" #define OPT_PORT "port" #define OPT_FILE "file" #define OPT_SOCK "sock" @@ -34,6 +35,7 @@ #define GETOPT_SOCK GETOPT_ARG( OPT_SOCK, 's' ) #define GETOPT_FROM GETOPT_ARG( OPT_FROM, 'F' ) #define GETOPT_SIZE GETOPT_ARG( OPT_SIZE, 'S' ) +#define GETOPT_BIND GETOPT_ARG( OPT_BIND, 'b' ) #ifdef DEBUG # define OPT_DEBUG "debug" @@ -45,6 +47,12 @@ # define DEBUG_LINE "" #endif +#define HELP_LINE \ + "\t--" OPT_HELP ",-h \tThis text.\n" +#define SOCK_LINE \ + "\t--" OPT_SOCK ",-s \tPath to the control socket.\n" +#define BIND_LINE \ + "\t--" OPT_BIND ",-b \tBind the local socket to a particular IP address.\n" static struct option serve_options[] = { GETOPT_HELP, @@ -60,12 +68,12 @@ static char serve_short_options[] = "Dhl:p:f:s:"; static char serve_help_text[] = "Usage: flexnbd " CMD_SERVE " [*]\n\n" "Serve FILE from ADDR:PORT, with an optional control socket at SOCK.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" + HELP_LINE "\t--" OPT_ADDR ",-l \tThe address to serve on.\n" "\t--" OPT_PORT ",-p \tThe port to serve on.\n" "\t--" OPT_FILE ",-f \tThe file to serve.\n" - "\t--" OPT_DENY ",-D\tDeny connections by default unless in ACL\n" - "\t--" OPT_SOCK ",-s \tPath to the control socket to open.\n" + "\t--" OPT_DENY ",-D\tDeny connections by default unless in ACL.\n" + SOCK_LINE DEBUG_LINE; static struct option read_options[] = { @@ -74,18 +82,20 @@ static struct option read_options[] = { GETOPT_PORT, GETOPT_FROM, GETOPT_SIZE, + GETOPT_BIND, GETOPT_DEBUG, {0} }; -static char read_short_options[] = "hl:p:F:S:"; +static char read_short_options[] = "hl:p:F:S:b:"; static char read_help_text[] = "Usage: flexnbd " CMD_READ " \n\n" "Read SIZE bytes from a server at ADDR:PORT to stdout, starting at OFFSET.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" + HELP_LINE "\t--" OPT_ADDR ",-l \tThe address to read from.\n" "\t--" OPT_PORT ",-p \tThe port to read from.\n" "\t--" OPT_FROM ",-F \tByte offset to read from.\n" "\t--" OPT_SIZE ",-S \tBytes to read.\n" + BIND_LINE DEBUG_LINE; @@ -94,11 +104,12 @@ static char *write_short_options = read_short_options; static char write_help_text[] = "Usage: flexnbd " CMD_WRITE" \n\n" "Write SIZE bytes from stdin to a server at ADDR:PORT, starting at OFFSET.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" + HELP_LINE "\t--" OPT_ADDR ",-l \tThe address to write to.\n" "\t--" OPT_PORT ",-p \tThe port to write to.\n" "\t--" OPT_FROM ",-F \tByte offset to write from.\n" "\t--" OPT_SIZE ",-S \tBytes to write.\n" + BIND_LINE DEBUG_LINE; struct option acl_options[] = { @@ -111,8 +122,8 @@ static char acl_short_options[] = "hs:"; static char acl_help_text[] = "Usage: flexnbd " CMD_ACL " [+]\n\n" "Set the access control list for a server with control socket SOCK.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" - "\t--" OPT_SOCK ",-s \tPath to the control socket.\n" + HELP_LINE + SOCK_LINE DEBUG_LINE; struct option mirror_options[] = { @@ -127,8 +138,7 @@ static char mirror_short_options[] = "hs:l:p:"; static char mirror_help_text[] = "Usage: flexnbd " CMD_MIRROR " \n\n" "Start mirroring from the server with control socket SOCK to one at ADDR:PORT.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" - "\t--" OPT_SOCK ",-s \tPath to the control socket.\n" + HELP_LINE "\t--" OPT_ADDR ",-l \tThe address to mirror to.\n" "\t--" OPT_PORT ",-p \tThe port to mirror to.\n" DEBUG_LINE; @@ -144,8 +154,8 @@ static char status_short_options[] = "hs:"; static char status_help_text[] = "Usage: flexnbd " CMD_STATUS " \n\n" "Get the status for a server with control socket SOCK.\n\n" - "\t--" OPT_HELP ",-h\tThis text.\n" - "\t--" OPT_SOCK ",-s \tPath to the control socket.\n" + HELP_LINE + SOCK_LINE DEBUG_LINE; static char help_help_text[] = @@ -159,3 +169,4 @@ static char help_help_text[] = "\tflexnbd status\n" "\tflexnbd help\n\n" "See flexnbd help for further info\n"; + diff --git a/src/params.h b/src/params.h index a550817..a2f5552 100644 --- a/src/params.h +++ b/src/params.h @@ -82,6 +82,7 @@ struct mode_serve_params { struct mode_readwrite_params { union mysockaddr connect_to; + union mysockaddr connect_from; off64_t from; off64_t len; int data_fd; diff --git a/src/readwrite.c b/src/readwrite.c index 36418f6..5b2e391 100644 --- a/src/readwrite.c +++ b/src/readwrite.c @@ -7,12 +7,20 @@ #include #include -int socket_connect(struct sockaddr* to) +int socket_connect(struct sockaddr* to, struct sockaddr* from) { int fd = socket(to->sa_family == AF_INET ? PF_INET : PF_INET6, SOCK_STREAM, 0); SERVER_ERROR_ON_FAILURE(fd, "Couldn't create client socket"); - SERVER_ERROR_ON_FAILURE(connect(fd, to, sizeof(struct sockaddr_in6)), - "connect failed"); + + if (NULL != from) + SERVER_ERROR_ON_FAILURE( + bind(fd, from, sizeof(struct sockaddr_in6)), + "bind() failed" + ); + + SERVER_ERROR_ON_FAILURE( + connect(fd, to, sizeof(struct sockaddr_in6)),"connect failed" + ); return fd; } @@ -106,7 +114,7 @@ void socket_nbd_write(int fd, off64_t from, int len, int in_fd, void* in_buf) void do_read(struct mode_readwrite_params* params) { - params->client = socket_connect(¶ms->connect_to.generic); + params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic); CHECK_RANGE("read"); socket_nbd_read(params->client, params->from, params->len, params->data_fd, NULL); @@ -115,7 +123,7 @@ void do_read(struct mode_readwrite_params* params) void do_write(struct mode_readwrite_params* params) { - params->client = socket_connect(¶ms->connect_to.generic); + params->client = socket_connect(¶ms->connect_to.generic, ¶ms->connect_from.generic); CHECK_RANGE("write"); socket_nbd_write(params->client, params->from, params->len, params->data_fd, NULL); diff --git a/src/readwrite.h b/src/readwrite.h index 6b0d3c4..2dabbfc 100644 --- a/src/readwrite.h +++ b/src/readwrite.h @@ -2,7 +2,7 @@ #define __READWRITE_H -int socket_connect(struct sockaddr* to); +int socket_connect(struct sockaddr* to, struct sockaddr* from); off64_t socket_nbd_read_hello(int fd); void socket_nbd_read(int fd, off64_t from, int len, int out_fd, void* out_buf); void socket_nbd_write(int fd, off64_t from, int len, int out_fd, void* out_buf);