As you note, this has come up before, and the same reasons exist then
as now.

The security model makes no sense: firewall, but allow NFS.

> getting NFS through a firewall is not that trivial with mountd binding to a 
> random port each time it starts.
> The patch below allows to specify a port which mountd will use.
> 
> The idea and the patch is not from me. 99% is based on an old patch submitted 
> to tech@ in 2007:
> http://old.nabble.com/-PATCH--mountd-to-listen-to-specified-port-td11075352.html
> The patch did not got much attention at that time, hope for a bit more now ;)
> 
> Only one or two minor tweaks were necessary to bring it to compile without 
> warnings.
> Tested and works well for me on i386/amd64.
> 
> comments, rants or even test reports are welcome.
> 
> cheers,
> Sebastian
> 
> 
> Index: include/rpc/svc.h
> ===================================================================
> RCS file: /cvs/src/include/rpc/svc.h,v
> retrieving revision 1.12
> diff -u -r1.12 svc.h
> --- include/rpc/svc.h 1 Sep 2010 14:43:34 -0000       1.12
> +++ include/rpc/svc.h 17 Oct 2012 10:33:06 -0000
> @@ -305,6 +305,9 @@
>  __BEGIN_DECLS
>  extern SVCXPRT *svcudp_create(int);
>  extern SVCXPRT *svcudp_bufcreate(int, unsigned int, unsigned int);
> +extern SVCXPRT *svcudp_create2(int, int, u_short);
> +extern SVCXPRT *svcudp_bufcreate2(int, int, u_short, unsigned int,
> +                 unsigned int);
>  __END_DECLS
>  
>  
> @@ -313,6 +316,7 @@
>   */
>  __BEGIN_DECLS
>  extern SVCXPRT *svctcp_create(int, unsigned int, unsigned int);
> +extern SVCXPRT *svctcp_create2(int, int, u_short, unsigned int, unsigned 
> int);
>  __END_DECLS
>  
>  /*
> Index: lib/libc/rpc/rpc.3
> ===================================================================
> RCS file: /cvs/src/lib/libc/rpc/rpc.3,v
> retrieving revision 1.45
> diff -u -r1.45 rpc.3
> --- lib/libc/rpc/rpc.3        27 Sep 2012 11:31:58 -0000      1.45
> +++ lib/libc/rpc/rpc.3        17 Oct 2012 10:33:11 -0000
> @@ -52,7 +52,7 @@
>  .\"   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
>  .\"   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  .\"
> -.Dd $Mdocdate: September 27 2012 $
> +.Dd $Mdocdate: October 15 2012 $
>  .Dt RPC 3
>  .Os
>  .Sh NAME
> @@ -109,8 +109,12 @@
>  .Nm svcfd_create ,
>  .Nm svcraw_create ,
>  .Nm svctcp_create ,
> +.Nm svctcp_create2 ,
>  .Nm svcudp_create ,
>  .Nm svcudp_bufcreate ,
> +.Nm svcudp_bufcreate2 ,
> +.Nm svcudp_create ,
> +.Nm svcudp_create2 ,
>  .Nm xdr_accepted_reply ,
>  .Nm xdr_authunix_parms ,
>  .Nm xdr_callhdr ,
> @@ -234,11 +238,19 @@
>  .Ft SVCXPRT *
>  .Fn svctcp_create "int sock" "u_int send_buf_size" "u_int recv_buf_size"
>  .Ft SVCXPRT *
> +.Fn svctcp_create2 "int sock" "int family" "u_short port" "u_int 
> send_buf_size" "u_int recv_buf_size"
> +.Ft SVCXPRT *
>  .Fn svcfd_create "int fd" "u_int sendsize" "u_int recvsize"
>  .Ft SVCXPRT *
>  .Fn svcudp_create "int sock"
>  .Ft SVCXPRT *
>  .Fn svcudp_bufcreate "int sock" "u_int sendsz" "u_int recvsz"
> +.Ft SVCXPRT *
> +.Fn svcudp_bufcreate2 "int sock" "int family" "u_short port" "u_int sendsz" 
> "u_int recvsz"
> +.Ft SVCXPRT *
> +.Fn svcudp_create "int sock"
> +.Ft SVCXPRT *
> +.Fn svcudp_create2 "int sock" "int family" "u_short port"
>  .Ft bool_t
>  .Fn xdr_accepted_reply "XDR *xdrs" "struct accepted_reply *ar"
>  .Ft bool_t
> @@ -1096,6 +1108,13 @@
>  users may specify the size of buffers; values of zero
>  choose suitable defaults.
>  .Pp
> +.Fn svctcp_create2
> +supersedes
> +.Fn svctcp_create
> +function. It allows to specify address family and port number also. This
> +function accepts AF_INET and AF_INET6 address families. If port is equal to 
> 0,
> +the function tries to bind socket to one of reserved ports.
> +.Pp
>  .Fn svcfd_create
>  will create a service on top of any open descriptor.
>  Typically, this descriptor is a connected socket for a stream protocol such
> @@ -1131,6 +1150,13 @@
>  except that it allows the user to specify the maximum packet size for sending
>  and receiving UDP-based RPC
>  messages instead of using the default size limit of 8800 bytes.
> +.Pp
> +.Fn svcudp_bufcreate2
> +supersedes
> +.Fn svcudp_bufcreate
> +function. It allows to specify address family and port number also. This
> +function accepts AF_INET and AF_INET6 address families. If port is equal to 
> 0,
> +the function tries to bind socket to one of reserved ports.
>  .Pp
>  .Fn xdr_accepted_reply
>  is used for encoding RPC reply messages.
> Index: lib/libc/rpc/svc_tcp.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/rpc/svc_tcp.c,v
> retrieving revision 1.30
> diff -u -r1.30 svc_tcp.c
> --- lib/libc/rpc/svc_tcp.c    1 Sep 2010 14:43:34 -0000       1.30
> +++ lib/libc/rpc/svc_tcp.c    17 Oct 2012 10:33:12 -0000
> @@ -136,7 +136,7 @@
>  
>       if (sock == RPC_ANYSOCK) {
>               if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
> -                     perror("svctcp_.c - udp socket creation problem");
> +                     perror("svctcp_.c - tcp socket creation problem");
>                       return (NULL);
>               }
>               madesock = TRUE;
> @@ -186,6 +186,119 @@
>               return (NULL);
>       }
>       return (xprt);
> +}
> +
> +/*
> + * This function creates sock (with specified adress family) if sock is -1.
> + * Then binds it to the specified port. It's possible to create v4 and v6
> + * sockets.
> + */
> +SVCXPRT *
> +svctcp_create2(int sock, int af, u_short port, u_int sendsize, u_int 
> recvsize)
> +{
> +     struct tcp_rendezvous *r;
> +     SVCXPRT *xprt;
> +     struct sockaddr *sa;
> +     struct sockaddr_in sin;
> +#ifdef INET6
> +     struct sockaddr_in6 sin6;
> +#endif
> +     socklen_t salen;
> +     bool_t madesock;
> +     int error;
> +
> +#ifdef INET6
> +     if (af != AF_INET && af != AF_INET6)
> +             return (NULL);
> +#else
> +     if (af != AF_INET)
> +             return (NULL);
> +#endif
> +
> +     madesock = FALSE;
> +
> +     if (sock == RPC_ANYSOCK) {
> +             sock = socket(af, SOCK_STREAM, 0);
> +             if (sock == -1)
> +                     return (NULL);
> +             madesock = TRUE;
> +     }
> +
> +     if (af == AF_INET) {
> +             memset(&sin, 0, sizeof(sin));
> +             sin.sin_family = AF_INET;
> +             sin.sin_port = htons(port);
> +             sin.sin_addr.s_addr = INADDR_ANY;
> +             salen = sizeof(sin);
> +             sa = (struct sockaddr *)&sin;
> +     }
> +#ifdef INET6
> +     else {
> +             memset(&sin6, 0, sizeof(sin6));
> +             sin6.sin_family = AF_INET6;
> +             sin6.sin_port = htons(port);
> +             sin6.sin_addr.s_addr = in6addr_any;
> +             salen = sizeof(sin6);
> +             sa = (struct sockaddr *)&sin6;
> +     }
> +#endif       /* INET6 */
> +
> +     switch (port) {
> +     case 0:
> +             error = bindresvport_sa(sock, sa);
> +             if (error == 0)
> +                     break;
> +             /* FALLTHOUGH */
> +     default:
> +             error = bind(sock, sa, salen);
> +             break;
> +     }
> +
> +     if (error != 0 || listen(sock, 2) != 0) {
> +             if (madesock)
> +                     close(sock);
> +             return (NULL);
> +     }
> +
> +     if (port == 0) {
> +             if (getsockname(sock, sa, &salen) != 0) {
> +                     if (madesock)
> +                             close(sock);
> +                     return (NULL);
> +             }
> +             if (af == AF_INET)
> +                     port = ntohs(((struct sockaddr_in *)sa)->sin_port);
> +#ifdef INET6
> +             else
> +                     port = ntohs(((struct sockaddr_in6 *)sa)->sin_port);
> +#endif
> +     }
> +
> +     r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r));
> +     if (r != NULL) {
> +             r->sendsize = sendsize;
> +             r->recvsize = recvsize;
> +
> +             xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
> +             if (xprt != NULL) {
> +                     xprt->xp_p2 = NULL;
> +                     xprt->xp_p1 = (caddr_t)r;
> +                     xprt->xp_verf = _null_auth;
> +                     xprt->xp_ops = &svctcp_rendezvous_op;
> +                     xprt->xp_port = port;
> +                     xprt->xp_sock = sock;
> +                     if (__xprt_register(xprt) != 0)
> +                             return (xprt);
> +
> +                     free(xprt);
> +             }
> +             free(r);
> +     }
> +
> +     if (madesock)
> +             close(sock);
> +
> +     return (NULL);
>  }
>  
>  /*
> Index: lib/libc/rpc/svc_udp.c
> ===================================================================
> RCS file: /cvs/src/lib/libc/rpc/svc_udp.c,v
> retrieving revision 1.19
> diff -u -r1.19 svc_udp.c
> --- lib/libc/rpc/svc_udp.c    1 Sep 2010 14:43:34 -0000       1.19
> +++ lib/libc/rpc/svc_udp.c    17 Oct 2012 10:33:12 -0000
> @@ -173,6 +173,125 @@
>       return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE));
>  }
>  
> +SVCXPRT *
> +svcudp_bufcreate2(int sock, int af, u_short port, u_int sendsz, u_int recvsz)
> +{
> +     SVCXPRT *xprt;
> +     struct svcudp_data *su;
> +     struct sockaddr *sa;
> +     struct sockaddr_in sin;
> +#ifdef INET6
> +     struct sockaddr_in6 sin6;
> +#endif
> +     socklen_t salen;
> +     bool_t madesock;
> +     int error;
> +
> +#ifdef INET6
> +     if (af != AF_INET && af != AF_INET6)
> +             return (NULL);
> +#else
> +     if (af != AF_INET)
> +             return (NULL);
> +#endif
> +
> +     madesock = FALSE;
> +
> +     if (sock == RPC_ANYSOCK) {
> +             sock = socket(af, SOCK_DGRAM, 0);
> +             if (sock == -1)
> +                     return (NULL);
> +             madesock = TRUE;
> +     }
> +
> +     if (af == AF_INET) {
> +             memset(&sin, 0, sizeof(sin));
> +             sin.sin_family = AF_INET;
> +             sin.sin_port = htons(port);
> +             sin.sin_addr.s_addr = INADDR_ANY;
> +             salen = sizeof(sin);
> +             sa = (struct sockaddr *)&sin;
> +     }
> +#ifdef INET6
> +     else {
> +             memset(&sin6, 0, sizeof(sin6));
> +             sin6.sin_family = AF_INET6;
> +             sin6.sin_port = htons(port);
> +             sin6.sin_addr.s_addr = in6addr_any;
> +             salen = sizeof(sin6);
> +             sa = (struct sockaddr *)&sin6;
> +     }
> +#endif       /* INET6 */
> +
> +     switch (port) {
> +     case 0:
> +             error = bindresvport_sa(sock, sa);
> +             if (error == 0)
> +                     break;
> +             /* FALLTHOUGH */
> +     default:
> +             error = bind(sock, sa, salen);
> +             break;
> +     }
> +
> +     if (error != 0) {
> +             if (madesock)
> +                     close(sock);
> +             return (NULL);
> +     }
> +
> +     if (port == 0) {
> +             if (getsockname(sock, sa, &salen) != 0) {
> +                     if (madesock)
> +                             close(sock);
> +                     return (NULL);
> +             }
> +             if (af == AF_INET)
> +                     port = ntohs(((struct sockaddr_in *)sa)->sin_port);
> +#ifdef INET6
> +             else
> +                     port = ntohs(((struct sockaddr_in6 *)sa)->sin_port);
> +#endif
> +     }
> +
> +     xprt = (SVCXPRT *)mem_alloc(sizeof(*xprt));
> +     if (xprt != NULL) {
> +             su = (struct svcudp_data *)mem_alloc(sizeof(*su));
> +             if (su != NULL) {
> +                     su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
> +                     rpc_buffer(xprt) = mem_alloc(su->su_iosz);
> +                     if (rpc_buffer(xprt) != NULL) {
> +                             xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt),
> +                                 su->su_iosz, XDR_DECODE);
> +                             su->su_cache = NULL;
> +                             xprt->xp_p2 = (caddr_t)su;
> +                             xprt->xp_verf.oa_base = su->su_verfbody;
> +                             xprt->xp_ops = &svcudp_op;
> +                             xprt->xp_port = port;
> +                             xprt->xp_sock = sock;
> +
> +                             if (__xprt_register(xprt) != 0)
> +                                     return (xprt);
> +
> +                             free(rpc_buffer(xprt));
> +                     }
> +                     free(su);
> +             }
> +             free(xprt);
> +     }
> +
> +     if (madesock)
> +             close(sock);
> +     return (NULL);
> +}
> +
> +SVCXPRT *
> +svcudp_create2(int sock, int af, u_short port)
> +{
> +
> +     return(svcudp_bufcreate2(sock, af, port, UDPMSGSIZE, UDPMSGSIZE));
> +}
> +
>  /* ARGSUSED */
>  static enum xprt_stat
>  svcudp_stat(SVCXPRT *xprt)
> Index: sbin/mountd/mountd.8
> ===================================================================
> RCS file: /cvs/src/sbin/mountd/mountd.8,v
> retrieving revision 1.16
> diff -u -r1.16 mountd.8
> --- sbin/mountd/mountd.8      31 May 2007 19:19:46 -0000      1.16
> +++ sbin/mountd/mountd.8      17 Oct 2012 10:33:30 -0000
> @@ -30,7 +30,7 @@
>  .\"
>  .\"     @(#)mountd.8 8.4 (Berkeley) 4/28/95
>  .\"
> -.Dd $Mdocdate: May 31 2007 $
> +.Dd $Mdocdate: October 15 2012 $
>  .Dt MOUNTD 8
>  .Os
>  .Sh NAME
> @@ -41,6 +41,7 @@
>  .Sh SYNOPSIS
>  .Nm mountd
>  .Op Fl dn
> +.Op Fl p Ar portnum
>  .Op Ar exportsfile
>  .Sh DESCRIPTION
>  .Nm
> @@ -71,6 +72,10 @@
>  The use of
>  .Fl n
>  is STRONGLY discouraged, as it opens up a wide range of security problems.
> +.It Fl p Ar portnum
> +Specify port number
> +.Nm
> +will listen on. It allows to configure firewall to filter on this port.
>  .It Ar exportsfile
>  The
>  .Ar exportsfile
> Index: sbin/mountd/mountd.c
> ===================================================================
> RCS file: /cvs/src/sbin/mountd/mountd.c,v
> retrieving revision 1.71
> diff -u -r1.71 mountd.c
> --- sbin/mountd/mountd.c      22 Mar 2010 16:35:27 -0000      1.71
> +++ sbin/mountd/mountd.c      17 Oct 2012 10:33:31 -0000
> @@ -51,6 +51,7 @@
>  #include <arpa/inet.h>
>  
>  #include <ctype.h>
> +#include <err.h>
>  #include <errno.h>
>  #include <grp.h>
>  #include <netdb.h>
> @@ -175,6 +176,8 @@
>  int  xdr_mlist(XDR *, caddr_t);
>  void mountd_svc_run(void);
>  
> +SVCXPRT *    create_svctcp(u_short port, int af);
> +
>  struct exportlist *exphead;
>  struct mountlist *mlhead;
>  struct grouplist *grphead;
> @@ -196,6 +199,7 @@
>  #define      OP_ALLDIRS      0x40
>  
>  int debug = 0;
> +u_short use_port = 0;        /* default: any */
>  
>  volatile sig_atomic_t gothup;
>  volatile sig_atomic_t gotterm;
> @@ -214,8 +218,11 @@
>       SVCXPRT *udptransp, *tcptransp;
>       FILE *pidfile;
>       int c;
> +     const char *errstr;
> +     long long portnum;
>  
> -     while ((c = getopt(argc, argv, "dnr")) != -1)
> +     portnum = 0;    /* any port */
> +     while ((c = getopt(argc, argv, "dnrp:")) != -1)
>               switch (c) {
>               case 'd':
>                       debug = 1;
> @@ -226,8 +233,15 @@
>               case 'r':
>                       /* Compatibility */
>                       break;
> +             case 'p':
> +                     portnum = strtonum(optarg, 0, USHRT_MAX, &errstr);
> +                     if (errstr != NULL)
> +                             errx(1, "Port number is invalid");
> +                     use_port = portnum;
> +                     break;
>               default:
> -                     fprintf(stderr, "usage: mountd [-dn] [exportsfile]\n");
> +                     fprintf(stderr,
> +                             "usage: mountd [-dn] [-p port] 
> [exportsfile]\n");
>                       exit(1);
>               }
>       argc -= optind;
> @@ -273,8 +287,8 @@
>       signal(SIGHUP, (void (*)(int)) new_exportlist);
>       signal(SIGTERM, (void (*)(int)) send_umntall);
>       signal(SIGSYS, SIG_IGN);
> -     if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||
> -         (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {
> +     if ((udptransp = svcudp_create2(RPC_ANYSOCK, AF_INET, portnum)) == NULL 
> ||
> +         (tcptransp = svctcp_create2(RPC_ANYSOCK, AF_INET, portnum, 0, 0)) 
> == NULL) {
>               syslog(LOG_ERR, "Can't create socket");
>               exit(1);
>       }

Reply via email to