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