Support port range as -p/--port PORT[:HIGHPORT].

Extend mosh and mosh-server to support parsing a high port from
the desired_port argument.  The first (low) port must not be
greater than the second (high) port.
If only one value is provided, behaviour is as before; bind
to one port.  Also tweak the formatting in mosh-server(1) synopsis
to be consistent.

This resolves mosh issue # 296.

Signed-off-by: Luke Mewburn <luke@mewburn.net>
This commit is contained in:
Luke Mewburn
2012-10-27 18:38:05 +11:00
committed by Keith Winstein
parent b99da057bb
commit 141ec239da
6 changed files with 95 additions and 40 deletions
+6 -6
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.TH MOSH 1 "February 2012" .TH MOSH 1 "October 2012"
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@@ -22,9 +22,9 @@ mosh-server \- server-side helper for mosh
new new
[\-s] [\-s]
[\-v] [\-v]
[\-i IP] [\-i \fIIP\fP]
[\-p port] [\-p \fIPORT\fP[:\fIPORT2\fP]]
[\-c colors] [\-c \fICOLORS\fP]
[\-\- command...] [\-\- command...]
.br .br
.SH DESCRIPTION .SH DESCRIPTION
@@ -69,8 +69,8 @@ Print some debugging information even after detaching.
IP address of the local interface to bind (for multihomed hosts) IP address of the local interface to bind (for multihomed hosts)
.TP .TP
.B \-p \fIPORT\fP .B \-p \fIPORT\fP[:\fIPORT2\fP]
UDP port number to bind UDP port number or port-range to bind
.TP .TP
.B \-c \fICOLORS\fP .B \-c \fICOLORS\fP
+4 -3
View File
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" other parameters are allowed: see man(7), man(1)
.TH MOSH 1 "February 2012" .TH MOSH 1 "October 2012"
.\" Please adjust this date whenever revising the manpage. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@@ -121,8 +121,9 @@ Synonym for \-\-predict=always
Synonym for \-\-predict=never Synonym for \-\-predict=never
.TP .TP
.B \-p \fINUM\fP, \-\-port=\fINUM\fP .B \-p \fIPORT\fP[:\fIPORT2\fP], \-\-port=\fIPORT\fP[:\fIPORT2\fP]
Use a particular server-side UDP port, for example, if this is the Use a particular server-side UDP port or port range,
for example, if this is the
only port that is forwarded through a firewall to the only port that is forwarded through a firewall to the
server. Otherwise, \fBmosh\fP will choose a port between 60000 and server. Otherwise, \fBmosh\fP will choose a port between 60000 and
61000. 61000.
+18 -8
View File
@@ -66,7 +66,8 @@ qq{Usage: $0 [options] [--] [user@]host [command...]
-n --predict=never never use local echo -n --predict=never never use local echo
--predict=experimental aggressively echo even when incorrect --predict=experimental aggressively echo even when incorrect
-p NUM --port=NUM server-side UDP port -p PORT[:PORT2]
--port=PORT[:PORT2] server-side UDP port or range
--ssh=COMMAND ssh command to run when setting up session --ssh=COMMAND ssh command to run when setting up session
(example: "ssh -p 2222") (example: "ssh -p 2222")
@@ -99,10 +100,10 @@ sub predict_check {
GetOptions( 'client=s' => \$client, GetOptions( 'client=s' => \$client,
'server=s' => \$server, 'server=s' => \$server,
'predict=s' => \$predict, 'predict=s' => \$predict,
'port=i' => \$port_request, 'port=s' => \$port_request,
'a' => sub { $predict = 'always' }, 'a' => sub { $predict = 'always' },
'n' => sub { $predict = 'never' }, 'n' => sub { $predict = 'never' },
'p=i' => \$port_request, 'p=s' => \$port_request,
'ssh=s' => \$ssh, 'ssh=s' => \$ssh,
'help' => \$help, 'help' => \$help,
'version' => \$version, 'version' => \$version,
@@ -122,12 +123,21 @@ if ( defined $predict ) {
} }
if ( defined $port_request ) { if ( defined $port_request ) {
if ( $port_request =~ m{^[0-9]+$} if ( $port_request =~ m{^(?<low>\d+)(:(?<high>\d+))?$} ) {
and $port_request >= 0 # good port or port-range
and $port_request <= 65535 ) { if ( $+{low} <= 0 or $+{low} >= 65535 ) {
# good port die "$0: Server-side (low) port ($+{low}) must be within valid range [0..65535].\n";
}
if ( defined $+{high} ) {
if ( $+{high} <= 0 or $+{high} >= 65535 ) {
die "$0: Server-side high port ($+{high}) must be within valid range [0..65535].\n";
}
if ( $+{low} > $+{high} ) {
die "$0: Server-side port range ($port_request): low port greater than high port.\n";
}
}
} else { } else {
die "$0: Server-side port ($port_request) must be within valid range [0..65535].\n"; die "$0: Server-side port ($port_request) not valid.\n";
} }
} }
+4 -4
View File
@@ -103,7 +103,7 @@ using namespace std;
void print_usage( const char *argv0 ) void print_usage( const char *argv0 )
{ {
fprintf( stderr, "Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n", argv0 ); fprintf( stderr, "Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2]] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n", argv0 );
} }
void print_motd( void ); void print_motd( void );
@@ -235,9 +235,9 @@ int main( int argc, char *argv[] )
exit( 1 ); exit( 1 );
} }
if ( desired_port int dpl, dph;
&& ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) { if ( desired_port && ! Connection::parse_portrange( desired_port, dpl, dph ) ) {
fprintf( stderr, "%s: Bad UDP port (%s)\n", argv[ 0 ], desired_port ); fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[ 0 ], desired_port );
print_usage( argv[ 0 ] ); print_usage( argv[ 0 ] );
exit( 1 ); exit( 1 );
} }
+60 -18
View File
@@ -223,20 +223,12 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
/* If an IP request is given, we try to bind to that IP, but we also /* If an IP request is given, we try to bind to that IP, but we also
try INADDR_ANY. If a port request is given, we bind only to that port. */ try INADDR_ANY. If a port request is given, we bind only to that port. */
/* convert port number */ /* convert port numbers */
long int desired_port_no = 0; int desired_port_low = 0;
int desired_port_high = 0;
if ( desired_port ) { if ( desired_port && !parse_portrange( desired_port, desired_port_low, desired_port_high ) ) {
char *end; throw NetworkException("Invalid port range", 0);
errno = 0;
desired_port_no = strtol( desired_port, &end, 10 );
if ( (errno != 0) || (end != desired_port + strlen( desired_port )) ) {
throw NetworkException( "Invalid port number", errno );
}
}
if ( (desired_port_no < 0) || (desired_port_no > 65535) ) {
throw NetworkException( "Port number outside valid range [0..65535]", 0 );
} }
/* convert desired IP */ /* convert desired IP */
@@ -253,7 +245,7 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
/* try to bind to desired IP first */ /* try to bind to desired IP first */
if ( desired_ip_addr != INADDR_ANY ) { if ( desired_ip_addr != INADDR_ANY ) {
try { try {
if ( try_bind( sock(), desired_ip_addr, desired_port_no ) ) { return; } if ( try_bind( sock(), desired_ip_addr, desired_port_low, desired_port_high ) ) { return; }
} catch ( const NetworkException& e ) { } catch ( const NetworkException& e ) {
struct in_addr sin_addr; struct in_addr sin_addr;
sin_addr.s_addr = desired_ip_addr; sin_addr.s_addr = desired_ip_addr;
@@ -265,7 +257,7 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
/* now try any local interface */ /* now try any local interface */
try { try {
if ( try_bind( sock(), INADDR_ANY, desired_port_no ) ) { return; } if ( try_bind( sock(), INADDR_ANY, desired_port_low, desired_port_high ) ) { return; }
} catch ( const NetworkException& e ) { } catch ( const NetworkException& e ) {
fprintf( stderr, "Error binding to any interface: %s: %s\n", fprintf( stderr, "Error binding to any interface: %s: %s\n",
e.function.c_str(), strerror( e.the_errno ) ); e.function.c_str(), strerror( e.the_errno ) );
@@ -276,7 +268,7 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
throw NetworkException( "Could not bind", errno ); throw NetworkException( "Could not bind", errno );
} }
bool Connection::try_bind( int socket, uint32_t addr, int port ) bool Connection::try_bind( int socket, uint32_t addr, int port_low, int port_high )
{ {
struct sockaddr_in local_addr; struct sockaddr_in local_addr;
local_addr.sin_family = AF_INET; local_addr.sin_family = AF_INET;
@@ -284,8 +276,11 @@ bool Connection::try_bind( int socket, uint32_t addr, int port )
int search_low = PORT_RANGE_LOW, search_high = PORT_RANGE_HIGH; int search_low = PORT_RANGE_LOW, search_high = PORT_RANGE_HIGH;
if ( port != 0 ) { /* port preference */ if ( port_low != 0 ) { /* low port preference */
search_low = search_high = port; search_low = port_low;
}
if ( port_high != 0 ) { /* high port preference */
search_high = port_high;
} }
for ( int i = search_low; i <= search_high; i++ ) { for ( int i = search_low; i <= search_high; i++ ) {
@@ -597,3 +592,50 @@ const Connection::Socket & Connection::Socket::operator=( const Socket & other )
return *this; return *this;
} }
bool Connection::parse_portrange( const char * desired_port, int & desired_port_low, int & desired_port_high )
{
/* parse "port" or "portlow:porthigh" */
desired_port_low = desired_port_high = 0;
char *end;
long value;
/* parse first (only?) port */
errno = 0;
value = strtol( desired_port, &end, 10 );
if ( (errno != 0) || (*end != '\0' && *end != ':') ) {
fprintf( stderr, "Invalid (low) port number (%s)\n", desired_port );
return false;
}
if ( (value < 0) || (value > 65535) ) {
fprintf( stderr, "(Low) port number %ld outside valid range [0..65535]\n", value );
return false;
}
desired_port_low = (int)value;
if (*end == '\0') { /* not a port range */
desired_port_high = desired_port_low;
return true;
}
/* port range; parse high port */
const char * cp = end + 1;
errno = 0;
value = strtol( cp, &end, 10 );
if ( (errno != 0) || (*end != '\0') ) {
fprintf( stderr, "Invalid high port number (%s)\n", cp );
return false;
}
if ( (value < 0) || (value > 65535) ) {
fprintf( stderr, "High port number %ld outside valid range [0..65535]\n", value );
return false;
}
desired_port_high = (int)value;
if ( desired_port_low > desired_port_high ) {
fprintf( stderr, "Low port %d greater than high port %d\n", desired_port_low, desired_port_high );
return false;
}
return true;
}
+3 -1
View File
@@ -101,7 +101,7 @@ namespace Network {
static const int CONGESTION_TIMESTAMP_PENALTY = 500; /* ms */ static const int CONGESTION_TIMESTAMP_PENALTY = 500; /* ms */
static bool try_bind( int socket, uint32_t addr, int port ); static bool try_bind( int socket, uint32_t addr, int port_low, int port_high );
class Socket class Socket
{ {
@@ -185,6 +185,8 @@ namespace Network {
} }
void set_last_roundtrip_success( uint64_t s_success ) { last_roundtrip_success = s_success; } void set_last_roundtrip_success( uint64_t s_success ) { last_roundtrip_success = s_success; }
static bool parse_portrange( const char * desired_port_range, int & desired_port_low, int & desired_port_high );
}; };
} }