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); > }