NFS! File locking! Firewalls! Pain!

I recently managed to get my server firewall to allow NFS requests from clients on my local network. It was a bit of a pain, so in case you’re suffering similar pain, I’ve written up my solution.

Firstly, the problem was to

  1. firewall up my server,
  2. but still allow local-net NFS requests,
  3. including file-locking.

My setup is a Linux server, running Debian Stable (Woody), and the kernel-level NFS server (‘nfs-kernel-server’ package.)

I assume you’ve already

  1. set up your firewall, and know how to open up ports on your firewall. I also assume that
  2. you have an NFS server running, and that, when the firewall is switched off, your clients can happily mount shares from it. Also:
  3. you’re not trying to make your NFS server publically visible. That would be silly.

Clients need to communicate with several server daemons:

nfsd
Your NFS server daemons. Found at port 2049. Opening up that port on your server machine’s firewall (for UDP and TCP) is a good first step.
portmapper
Tells clients what ports the other services are on. Found at port 111. Open up that one too (UDP and TCP).
mountd
Involved in clients actually mounting one of the server directories. Needs to be visible through firewall, but its port number is dynamic.
statd
Something to do with file locking. Needs to be visible for clients to be able to hold locks on files. Similarly, its port number is dynamic.
lockd
The file locking daemon itself. Needs to be visible to clients for locking to work, but not only has a dynamic port number, but it’s embedded in the kernel too (at least the version I’m using).

We need to lock down the last 3 daemons to be at static, known port numbers, then we can open the necessary ports in the firewall. (Note that none of this requires any alterations to the client machines; the portmapper on the server will tell them what ports to use.)

First, pick a number… You need to decide upon 3 port numbers, one for ‘mountd’, one for ‘statd’, and one for ‘lockd’. I chose 4002, 4003, 4004. The important thing is that you pick numbers not used by any other services. Unless you’re running some exotic software, the numbers I chose should be alright for you too.

Add these numbers to your /etc/services file on the server.

Here’s the extract from my /etc/services:

# Local services

nfs 2049/tcp
nfs 2049/udp
# Tie down portmapper services for firewall:
mount 4002/tcp
mount 4002/udp
statd 4003/tcp
statd 4003/udp
lockd 4004/tcp
lockd 4004/udp

mountd

Find the place where your machine starts mountd—on Debian Woody, that’s /etc/init.d/nfs-kernel-server and change it to start the mountd program with the additional arguments “-p 4002”. On Debian Woody, modify the line RPCMOUNTDOPTS=”” to read RPCMOUNTDOPTS=”-p 4002″.

statd

Find the place where statd starts—on Debian Woody, /etc/nfs-common, and change to add arguments “-p 4003”. On Debian Woody, you’re looking for the line “–exec $PREFIX/sbin/rpc.statd — ” and changing it to read: “–exec $PREFIX/sbin/rpc.statd — -p 4003”

To check that the above two changes have worked, restart your NFS daemons, and run the command “rpcinfo -p”. This shows you what ports the various NFS daemons are bound to. It should show the “status” program (statd) at port 4003, and the “mountd” program at port 4002.

The next bit is trickier (at least for the kernel-level NFS server).

lockd

Lockd runs as a kernel loadable module, and takes its parameters (like what port to use) from the /etc/modules.conf file. Add the following line to that file:

options lockd nlm_udpport=4004 nlm_tcpport=4004

To effect the change you need to reload the lockd kernel module. If you prefer the easy life, rebooting the server will do it. (If you know your way round “rmmod” and “insmod” you can force it to reload by killing the NFS daemon, unloading the kernel modules ‘nfsd’, ‘lockd’, ‘sunrpc’ in that order, and reloading them, before restarting the NFS daemon.)

Again, run “rpcinfo -p” to check that lockd is now bound to the correct port.

Finally…

The last stage should be the most straightforward: open up ports 111, 2049 and whichever ports you chose for the other daemons, in my case 4002, 4003 and 4004, on your firewall, both UDP and TCP.

Remove from the oven, and serve.

Finally finally

Bloody hell, it’s not exactly straightforward, is it? Obviously designed by either a committee or a particularly inelegant person. Even FTP is easier to firewall than this. Damn you, NFS, damn you!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.