Hi all, I have a requirement to run NFS read-only in an Internet-facing colocation environment. I am not happy with packet filters alone around rpcbind, call me paranoid, so I just spent the last few minutes cutting this patch. As you are aware, RPC applications can be forced to listen on a known port through the sin/sa argument to bindresvport[_sa](). Why several Linux distributions have this feature yet none of the BSDs do is beyond me... Please let me know your thoughts. If there are no valid objections I plan to commit it. Regards, BMS -------------- next part -------------- Index: mountd.8 ==================================================================RCS file: /home/ncvs/src/usr.sbin/mountd/mountd.8,v retrieving revision 1.24 diff -u -r1.24 mountd.8 --- mountd.8 12 Dec 2002 17:26:02 -0000 1.24 +++ mountd.8 2 Mar 2004 20:55:37 -0000 @@ -43,6 +43,7 @@ .Sh SYNOPSIS .Nm .Op Fl 2dlnr +.Op Fl p Ar port .Op Ar exportsfile .Sh DESCRIPTION The @@ -77,6 +78,18 @@ that require it. It will automatically clear the vfs.nfsrv.nfs_privport sysctl flag, which controls if the kernel will accept NFS requests from reserved ports only. +.It Fl p Ar port +Force +.Nm +to bind to the specified port, for both +.Vt AF_INET +and +.Vt AF_INET6 +address families. +If +.Nm +cannot bind to this port, an appropriate error will be recorded in +the system log, and the daemon will then exit. .It Fl r Allow mount RPCs requests for regular files to be served. Although this seems to violate the mount protocol specification, Index: mountd.c ==================================================================RCS file: /home/ncvs/src/usr.sbin/mountd/mountd.c,v retrieving revision 1.74 diff -u -r1.74 mountd.c --- mountd.c 30 Oct 2003 22:57:43 -0000 1.74 +++ mountd.c 2 Mar 2004 21:08:17 -0000 @@ -272,11 +272,15 @@ fd_set readfds; SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp; struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; int udpsock, tcpsock, udp6sock, tcp6sock; + char *endptr; + in_port_t svcport = 0; int xcreated = 0, s; int maxrec = RPC_MAXDATASIZE; int one = 1; - int c; + int c, r; udp6conf = tcp6conf = NULL; udp6sock = tcp6sock = NULL; @@ -298,7 +302,7 @@ errx(1, "NFS server is not available or loadable"); } - while ((c = getopt(argc, argv, "2dlnr")) != -1) + while ((c = getopt(argc, argv, "2dlnp:r")) != -1) switch (c) { case '2': force_v2 = 1; @@ -315,6 +319,14 @@ case 'l': dolog = 1; break; + case 'p': + endptr = NULL; + svcport = (in_port_t)strtoul(optarg, &endptr, 10); + if (endptr == NULL || *endptr != '\0' || + svcport < IPPORT_RESERVEDSTART || + svcport >= IPPORT_MAX) + usage(); + break; default: usage(); }; @@ -390,8 +402,26 @@ exit(1); } } + if (svcport != 0) { + bzero(&sin, sizeof(struct sockaddr_in)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_port = htons(svcport); + + bzero(&sin6, sizeof(struct sockaddr_in6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(svcport); + } if (udpsock != -1 && udpconf != NULL) { - bindresvport(udpsock, NULL); + if (svcport != 0) { + r = bindresvport(udpsock, &sin); + if (r != 0) { + syslog(LOG_ERR, "bindresvport: %m"); + exit(1); + } + } else + (void)bindresvport(udpsock, NULL); udptransp = svc_dg_create(udpsock, 0, 0); if (udptransp != NULL) { if (!svc_reg(udptransp, RPCPROG_MNT, RPCMNT_VER1, @@ -411,7 +441,14 @@ } if (tcpsock != -1 && tcpconf != NULL) { - bindresvport(tcpsock, NULL); + if (svcport != 0) { + r = bindresvport(tcpsock, &sin); + if (r != 0) { + syslog(LOG_ERR, "bindresvport: %m"); + exit(1); + } + } else + (void)bindresvport(tcpsock, NULL); listen(tcpsock, SOMAXCONN); tcptransp = svc_vc_create(tcpsock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (tcptransp != NULL) { @@ -432,7 +469,15 @@ } if (have_v6 && udp6sock != -1 && udp6conf != NULL) { - bindresvport(udp6sock, NULL); + if (svcport != 0) { + r = bindresvport_sa(udp6sock, + (struct sockaddr *)&sin6); + if (r != 0) { + syslog(LOG_ERR, "bindresvport_sa: %m"); + exit(1); + } + } else + (void)bindresvport_sa(udp6sock, NULL); udp6transp = svc_dg_create(udp6sock, 0, 0); if (udp6transp != NULL) { if (!svc_reg(udp6transp, RPCPROG_MNT, RPCMNT_VER1, @@ -452,7 +497,15 @@ } if (have_v6 && tcp6sock != -1 && tcp6conf != NULL) { - bindresvport(tcp6sock, NULL); + if (svcport != 0) { + r = bindresvport_sa(tcp6sock, + (struct sockaddr *)&sin6); + if (r != 0) { + syslog(LOG_ERR, "bindresvport_sa: %m"); + exit(1); + } + } else + (void)bindresvport_sa(tcp6sock, NULL); listen(tcp6sock, SOMAXCONN); tcp6transp = svc_vc_create(tcp6sock, RPC_MAXDATASIZE, RPC_MAXDATASIZE); if (tcp6transp != NULL) { @@ -502,7 +555,8 @@ usage() { fprintf(stderr, - "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n"); + "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " + "[export_file]\n"); exit(1); }
Bruce M Simpson
2004-Mar-02 13:58 UTC
[RELENG_4] Re: [PATCH] Force mountd(8) to a specified port.
On Tue, Mar 02, 2004 at 09:10:30PM +0000, Bruce M Simpson wrote:> As you are aware, RPC applications can be forced to listen on a known port > through the sin/sa argument to bindresvport[_sa](). Why several Linux > distributions have this feature yet none of the BSDs do is beyond me...Here's a similar patch for RELENG_4. Please give me feedback. Regards, BMS -------------- next part -------------- ? .mountd.c.rej.swp Index: mountd.8 ==================================================================RCS file: /home/ncvs/src/sbin/mountd/Attic/mountd.8,v retrieving revision 1.16.2.2 diff -u -r1.16.2.2 mountd.8 --- mountd.8 8 Dec 2000 14:04:02 -0000 1.16.2.2 +++ mountd.8 2 Mar 2004 21:56:11 -0000 @@ -43,6 +43,7 @@ .Sh SYNOPSIS .Nm .Op Fl 2dlnr +.Op Fl p Ar port .Op Ar exportsfile .Sh DESCRIPTION .Nm Mountd @@ -76,6 +77,18 @@ that require it. It will automatically clear the vfs.nfs.nfs_privport sysctl flag, which controls if the kernel will accept NFS requests from reserved ports only. +.It Fl p Ar port +Force +.Nm +to bind to the specified port, for both +.Vt AF_INET +and +.Vt AF_INET6 +address families. +If +.Nm +cannot bind to this port, an appropriate error will be recorded in +the system log, and the daemon will then exit. .It Fl r Allow mount RPCs requests for regular files to be served. Although this seems to violate the mount protocol specification, Index: mountd.c ==================================================================RCS file: /home/ncvs/src/sbin/mountd/Attic/mountd.c,v retrieving revision 1.39.2.5 diff -u -r1.39.2.5 mountd.c --- mountd.c 13 Sep 2002 15:57:43 -0000 1.39.2.5 +++ mountd.c 2 Mar 2004 21:56:11 -0000 @@ -238,8 +238,12 @@ int argc; char **argv; { + struct sockaddr_in sin; SVCXPRT *udptransp, *tcptransp; + char *endptr; int c, error, mib[3]; + int tcpsock, udpsock; + in_port_t svcport; struct vfsconf vfc; error = getvfsbyname("nfs", &vfc); @@ -252,7 +256,7 @@ if (error) errx(1, "NFS support is not available in the running kernel"); - while ((c = getopt(argc, argv, "2dlnr")) != -1) + while ((c = getopt(argc, argv, "2dlnp:r")) != -1) switch (c) { case '2': force_v2 = 1; @@ -269,6 +273,14 @@ case 'l': log = 1; break; + case 'p': + endptr = NULL; + svcport = (in_port_t)strtoul(optarg, &endptr, 10); + if (endptr == NULL || *endptr != '\0' || + svcport < IPPORT_RESERVEDSTART || + svcport >= 65535) + usage(); + break; default: usage(); }; @@ -313,8 +325,24 @@ exit(1); } } - if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL || - (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) { + if ((udpsock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1 || + (tcpsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + syslog(LOG_ERR, "can't create socket"); + exit(1); + } + if (svcport != 0) { + bzero(&sin, sizeof(struct sockaddr_in)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_port = htons(svcport); + if (bind(udpsock, (struct sockaddr *)&sin, sizeof(sin)) == -1 || + bind(tcpsock, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + syslog(LOG_ERR, "can't bind socket"); + exit(1); + } + } + if ((udptransp = svcudp_create(udpsock)) == NULL || + (tcptransp = svctcp_create(tcpsock, 0, 0)) == NULL) { syslog(LOG_ERR, "can't create socket"); exit(1); } @@ -340,7 +368,8 @@ usage() { fprintf(stderr, - "usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n"); + "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " + "[export_file]\n"); exit(1); }
In some mail from Bruce M Simpson, sie said:> Hi all, > > I have a requirement to run NFS read-only in an Internet-facing colocation > environment. I am not happy with packet filters alone around rpcbind, call > me paranoid, so I just spent the last few minutes cutting this patch. > > As you are aware, RPC applications can be forced to listen on a known port > through the sin/sa argument to bindresvport[_sa](). Why several Linux > distributions have this feature yet none of the BSDs do is beyond me... > > Please let me know your thoughts. If there are no valid objections I plan > to commit it.I'm confused by your first paragraph...the primary purpose of a patch like this would be, I imagine, to support being able to write filter rules for your firewall with a specific port defined rather than have to determine it after rpcbind & mountd have started. Darren