[mosh-devel] Patch to support port-range with -p

Luke Mewburn lukem-mosh at mewburn.net
Fri Oct 26 20:06:04 EDT 2012


Hi folks,

I've implemented a change to mosh (and mosh-server) to support
port-ranges in -p.  The existing syntax of "-p PORT" still works,
but you can also use "-p LOWPORT:HIGHPORT".
This should resolve issue # 296.

I've tried to adhere to the existing code style.

regards,
Luke.
-------------- next part --------------
From 63876410adc3e3184a177bf8989c097bbe60e47b Mon Sep 17 00:00:00 2001
From: Luke Mewburn <luke at mewburn.net>
Date: Sat, 27 Oct 2012 10:09:39 +1100
Subject: [PATCH 2/2] Support port range as -p/--port PORT[:HIGHPORT].

Extend mosh-server and mosh 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.

Tweak the formatting in mosh-server(1) synopsis to be consistent.

This resolves mosh issue # 296.
---
 man/mosh-server.1           |   12 +++---
 man/mosh.1                  |    7 ++--
 scripts/mosh                |   28 ++++++++++-----
 src/frontend/mosh-server.cc |    8 ++--
 src/network/network.cc      |   78 +++++++++++++++++++++++++++++++++----------
 src/network/network.h       |    4 ++-
 6 files changed, 96 insertions(+), 41 deletions(-)

diff --git a/man/mosh-server.1 b/man/mosh-server.1
index 16d65d4..39fbb34 100644
--- a/man/mosh-server.1
+++ b/man/mosh-server.1
@@ -2,7 +2,7 @@
 .\" First parameter, NAME, should be all caps
 .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
 .\" 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.
 .\"
 .\" Some roff macros, for reference:
@@ -22,9 +22,9 @@ mosh-server \- server-side helper for mosh
 new
 [\-s]
 [\-v]
-[\-i IP]
-[\-p port]
-[\-c colors]
+[\-i \fIIP\fP]
+[\-p \fIPORT\fP[:\fIPORT2\fP]]
+[\-c \fICOLORS\fP]
 [\-\- command...]
 .br
 .SH DESCRIPTION
@@ -69,8 +69,8 @@ Print some debugging information even after detaching.
 IP address of the local interface to bind (for multihomed hosts)
 
 .TP
-.B \-p \fIPORT\fP
-UDP port number to bind
+.B \-p \fIPORT\fP[:\fIPORT2\fP]
+UDP port number or port-range to bind
 
 .TP
 .B \-c \fICOLORS\fP
diff --git a/man/mosh.1 b/man/mosh.1
index 0292ab0..ea63ef2 100644
--- a/man/mosh.1
+++ b/man/mosh.1
@@ -2,7 +2,7 @@
 .\" First parameter, NAME, should be all caps
 .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
 .\" 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.
 .\"
 .\" Some roff macros, for reference:
@@ -121,8 +121,9 @@ Synonym for \-\-predict=always
 Synonym for \-\-predict=never
 
 .TP
-.B \-p \fINUM\fP, \-\-port=\fINUM\fP
-Use a particular server-side UDP port, for example, if this is the
+.B \-p \fIPORT\fP[:\fIPORT2\fP], \-\-port=\fIPORT\fP[:\fIPORT2\fP]
+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
 server. Otherwise, \fBmosh\fP will choose a port between 60000 and
 61000.
diff --git a/scripts/mosh b/scripts/mosh
index a6d6584..c9eb7da 100755
--- a/scripts/mosh
+++ b/scripts/mosh
@@ -66,7 +66,8 @@ qq{Usage: $0 [options] [--] [user@]host [command...]
 -n      --predict=never         never use local echo
         --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
                                 (example: "ssh -p 2222")
@@ -99,10 +100,10 @@ sub predict_check {
 GetOptions( 'client=s' => \$client,
 	    'server=s' => \$server,
 	    'predict=s' => \$predict,
-	    'port=i' => \$port_request,
+	    'port=s' => \$port_request,
 	    'a' => sub { $predict = 'always' },
 	    'n' => sub { $predict = 'never' },
-	    'p=i' => \$port_request,
+	    'p=s' => \$port_request,
 	    'ssh=s' => \$ssh,
 	    'help' => \$help,
 	    'version' => \$version,
@@ -121,13 +122,22 @@ if ( defined $predict ) {
   predict_check( $predict, 0 );
 }
 
-if ( defined $port_request ) {
-  if ( $port_request =~ m{^[0-9]+$}
-       and $port_request >= 0
-       and $port_request <= 65535 ) {
-    # good port
+if ( 0 and defined $port_request ) {
+  if ( $port_request =~ m{^(?<low>\d+)(:(?<high>\d+))?$} ) {
+    # good port or port-range
+    if ( $+{low} <= 0 or $+{low} >= 65535 ) {
+      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 {
-    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";
   }
 }
 
diff --git a/src/frontend/mosh-server.cc b/src/frontend/mosh-server.cc
index de6d6bf..4f7a5eb 100644
--- a/src/frontend/mosh-server.cc
+++ b/src/frontend/mosh-server.cc
@@ -103,7 +103,7 @@ using namespace std;
 
 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 );
@@ -235,9 +235,9 @@ int main( int argc, char *argv[] )
     exit( 1 );
   }
 
-  if ( desired_port
-       && ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
-    fprintf( stderr, "%s: Bad UDP port (%s)\n", argv[ 0 ], desired_port );
+  int dpl, dph;
+  if ( desired_port && ! Connection::parse_portrange( desired_port, dpl, dph ) ) {
+    fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[ 0 ], desired_port );
     print_usage( argv[ 0 ] );
     exit( 1 );
   }
diff --git a/src/network/network.cc b/src/network/network.cc
index d257188..d9d42d7 100644
--- a/src/network/network.cc
+++ b/src/network/network.cc
@@ -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
      try INADDR_ANY. If a port request is given, we bind only to that port. */
 
-  /* convert port number */
-  long int desired_port_no = 0;
-
-  if ( desired_port ) {
-    char *end;
-    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 );
-    }
-  }
+  /* convert port numbers */
+  int desired_port_low = 0;
+  int desired_port_high = 0;
 
-  if ( (desired_port_no < 0) || (desired_port_no > 65535) ) {
-    throw NetworkException( "Port number outside valid range [0..65535]", 0 );
+  if ( desired_port && !parse_portrange( desired_port, desired_port_low, desired_port_high ) ) {
+    throw NetworkException("Invalid port range", 0);
   }
 
   /* 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 */
   if ( desired_ip_addr != INADDR_ANY ) {
     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 ) {
       struct in_addr sin_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 */
   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 ) {
     fprintf( stderr, "Error binding to any interface: %s: %s\n",
 	     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 );
 }
 
-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;
   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;
 
-  if ( port != 0 ) { /* port preference */
-    search_low = search_high = port;
+  if ( port_low != 0 ) { /* low port preference */
+    search_low = port_low;
+  }
+  if ( port_high != 0 ) { /* high port preference */
+    search_high = port_high;
   }
 
   for ( int i = search_low; i <= search_high; i++ ) {
@@ -597,3 +592,50 @@ const Connection::Socket & Connection::Socket::operator=( const Socket & other )
 
   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;
+}
diff --git a/src/network/network.h b/src/network/network.h
index f98da24..8db4bd8 100644
--- a/src/network/network.h
+++ b/src/network/network.h
@@ -101,7 +101,7 @@ namespace Network {
 
     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
     {
@@ -185,6 +185,8 @@ namespace Network {
     }
 
     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 );
   };
 }
 
-- 
1.7.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
Url : http://mailman.mit.edu/pipermail/mosh-devel/attachments/20121026/a72080d8/attachment.bin


More information about the mosh-devel mailing list