Hi,

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