This is basically just a note for myself. There are times when you simply don’t need fancy “new” things like NFS v4, and v3 will do just fine. So why allow access via v4 then? Here’s how to set it up on Debian 7 (Wheezy), including some simple firewalling.
Initial setup
Once you’ve installed the nfs-kernel-server, nfs-common and rpcbind packages, and started fired up their services, you’ll be seeing a process list like this:
root [nfsd4] root [nfsd4_callbacks] root [lockd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root /sbin/rpcbind -w root /usr/sbin/rpc.idmapd root /usr/sbin/rpc.mountd --manage-gids statd /sbin/rpc.statd
And listening tcp/udp ports similar to this:
tcp 0.0.0.0:111 rpcbind tcp 0.0.0.0:2049 - tcp 0.0.0.0:49425 - tcp 0.0.0.0:49546 rpc.mountd tcp 0.0.0.0:53457 rpc.statd tcp 0.0.0.0:57298 rpc.mountd tcp 0.0.0.0:58384 rpc.mountd udp 0.0.0.0:2049 - udp 0.0.0.0:111 rpcbind udp 0.0.0.0:896 rpcbind udp 0.0.0.0:42342 rpc.mountd udp 0.0.0.0:43437 - udp 0.0.0.0:43640 rpc.mountd udp 0.0.0.0:51389 rpc.statd udp 0.0.0.0:53773 rpc.mountd udp 127.0.0.1:931 rpc.statd
Restart the services, and you’ll see most of those ports change — not very firewall friendly. Fortunately, it’s not too complicated to modify this behaviour.
/etc/default/nfs-common
Set a static listening port for the rpc.statd daemon.
-STATDOPTS=
+STATDOPTS='--port 2046
You can also set the outgoing port with the –outgoing-port argument, but I don’t find that useful since I don’t do egress firewalling in this case.
The rpc.idmapd and rpc.gssd daemons are not needed if you run NFS v3.
-NEED_IDMAPD=
-NEED_GSSD=
+NEED_IDMAPD=no
+NEED_GSSD=no
/etc/default/nfs-kernel-server
Disable NFS v4 in the kernel server. The nfs-kernel-server init script does not feature a RPCNFSDOPTS variable or similar, but this one works just as well, since this variable is appended to the rpc.nfsd command line:
-RPCNFSDCOUNT=8
+RPCNFSDCOUNT='--no-nfs-version 4 8'
Disable NFS v4 in the rpc.mountd daemon, and set a static listening port:
-RPCMOUNTDOPTS=--manage-gids
+RPCMOUNTDOPTS='--manage-gids --no-nfs-version 4 --port 2048'
sysctl
The ports used by the kernel server is configured either via the kernel module arguments, the kernel command line, or via the sysctl interface. I prefer the latter, especially in case of virtualized systems running kernels without modules support.
Simply add a new file in /etc/sysctl.d with a .conf file extension, containing these settings:
fs.nfs.nlm_tcpport = 2050
fs.nfs.nlm_udpport = 2050
Make sure to set the parameters using the sysctl tool, or apply the ones found in the newly created file via the tool’s -p
option.
/etc/services
Just to make output of netstat, tcpdump etc. a bit prettier if not run with numeric options, adding something like this to the services file is nice:
nfs.mountd 2048/tcp
nfs.mountd 2048/udp
nfs.lockd 2050/tcp
nfs.lockd 2050/udp
Post re-configuration
Restart the services, and you’ll end up with a bit smaller process list:
root [nfsd4] root [nfsd4_callbacks] root [lockd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root [nfsd] root /sbin/rpcbind -w root /usr/sbin/rpc.mountd --manage-gids --no-nfs-version 4 --port 2048 statd /sbin/rpc.statd --port 2046
And a bit cleaner list of listening tcp/udp ports:
tcp 0.0.0.0:111 rpcbind tcp 0.0.0.0:2046 rpc.statd tcp 0.0.0.0:2048 rpc.mountd tcp 0.0.0.0:2049 - tcp 0.0.0.0:2050 - udp 0.0.0.0:111 rpcbind udp 0.0.0.0:738 rpcbind udp 0.0.0.0:2046 rpc.statd udp 0.0.0.0:2048 rpc.mountd udp 0.0.0.0:2049 - udp 0.0.0.0:2050 - udp 127.0.0.1:773 rpc.statd
rpcbind and rpc.statd still opens some dynamic low-range ports (that are not listed in the output of rpcinfo -p
). If these ports are bothering you, you might want to have a look at the hack provided at http://wiki.metawerx.net/wiki/setrpcrandomport.
iptables
In your filter table, add two simple rules to your INPUT chain:
-i interface -p udp -m multiport --dports 111,2046,2048,2049,2050 -m state --state NEW -j ACCEPT
-i interface -p tcp -m multiport --dports 111,2046,2048,2049,2050 -m state --state NEW -j ACCEPT
You could also filter on hosts etc. A simple way to do that is to change the ACCEPT target to a custom chain, in which you could place some source address filtering. Ever better – simply use IP sets, which could be used for both the incoming ports and the source addresses in this case.
Obviously, you would want to add some default policy or some REJECT rules in the end of the INPUT chain.
No IPv6?
You should probably run IPv6, but if you don’t, and IPv6 is disabled in your kernel (or via the sysctl interface), you might see some nasty messages upon starting the nfs-kernel-server service:
[....] Starting NFS kernel daemon:
nfsdrpc.nfsd: address family inet6 not supported by protocol TCP
mountdrpc.mountd: svc_tli_create: could not open connection for udp6
rpc.mountd: svc_tli_create: could not open connection for tcp6
rpc.mountd: svc_tli_create: could not open connection for udp6
rpc.mountd: svc_tli_create: could not open connection for tcp6
rpc.mountd: svc_tli_create: could not open connection for udp6
rpc.mountd: svc_tli_create: could not open connection for tcp6
. ok
To fix this, have a look in /etc/netconfig and disable (comment out) the udp6 and tcp6 entries.