]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Allow rpc.nfsd to suppress tcp or udp, and listen on a specific address.
authorSteve Dickson <SteveD@redhat.com>
Sun, 2 Jul 2006 23:52:00 +0000 (09:52 +1000)
committerNeil Brown <neilb@suse.de>
Sun, 2 Jul 2006 23:52:00 +0000 (09:52 +1000)
 -T       - will suppressing listening for TCP connection.
 -U       - will suppress UDP
 -H host  - will only listen on that local address
 -p port  - will listen on that port.

This requires kernel patches which will hopefully be in 2.6.19 and possibly some
earlier test and vendor kernels.

support/include/nfs/nfs.h
support/include/nfslib.h
support/nfs/nfssvc.c
utils/nfsd/nfsd.c
utils/nfsd/nfsd.man

index 2cf6857ba5ef8729a9da5486ebd588e8051bb0c3..f0286b2ca07704a49c84502004333aefd8fceea5 100644 (file)
@@ -44,8 +44,12 @@ struct nfs_fh_old {
 #define LOCKDCTL_SVC           NFSCTL_LOCKD
 
 #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) 
 #define LOCKDCTL_SVC           NFSCTL_LOCKD
 
 #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) 
+#define NFSCTL_UDPUNSET(_cltbits)     ((_cltbits) &= ~(1 << (17 - 1))) 
+#define NFSCTL_TCPUNSET(_cltbits)     ((_cltbits) &= ~(1 << (18 - 1))) 
 
 #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) 
 
 #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) 
+#define NFSCTL_UDPISSET(_cltbits)     ((_cltbits) & (1 << (17 - 1))) 
+#define NFSCTL_TCPISSET(_cltbits)     ((_cltbits) & (1 << (18 - 1))) 
 
 #define NFSCTL_ALLBITS (~0)
 
 
 #define NFSCTL_ALLBITS (~0)
 
index 50892e22b0d3fe0874887df1b8606c284d34cedd..3e25761cef700c70e4f16700e38fb617ee013bea 100644 (file)
@@ -120,7 +120,7 @@ int                 wildmat(char *text, char *pattern);
  * nfsd library functions.
  */
 int                    nfsctl(int, struct nfsctl_arg *, union nfsctl_res *);
  * nfsd library functions.
  */
 int                    nfsctl(int, struct nfsctl_arg *, union nfsctl_res *);
-int                    nfssvc(int port, int nrservs, unsigned int versbits);
+int                    nfssvc(int port, int nrservs, unsigned int versbits, unsigned int portbits, char *haddr);
 int                    nfsaddclient(struct nfsctl_client *clp);
 int                    nfsdelclient(struct nfsctl_client *clp);
 int                    nfsexport(struct nfsctl_export *exp);
 int                    nfsaddclient(struct nfsctl_client *clp);
 int                    nfsdelclient(struct nfsctl_client *clp);
 int                    nfsexport(struct nfsctl_export *exp);
index c51ace18ea078c223aa597afb4637b9fbd1663a1..a6ea410226f193d5f22def299ff9d9a57914682a 100644 (file)
 #include <config.h>
 #endif
 
 #include <config.h>
 #endif
 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <syslog.h>
 
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <syslog.h>
 
+
 #include "nfslib.h"
 
 #include "nfslib.h"
 
+#define NFSD_PORTS_FILE     "/proc/fs/nfsd/portlist"
+#define NFSD_VERS_FILE    "/proc/fs/nfsd/versions"
+#define NFSD_THREAD_FILE  "/proc/fs/nfsd/threads"
+
+static void
+nfssvc_setfds(int port, unsigned int ctlbits, char *haddr)
+{
+       int fd, on=1;
+       char buf[BUFSIZ];
+       int udpfd = -1, tcpfd = -1;
+       struct sockaddr_in sin;
+
+       fd = open(NFSD_PORTS_FILE, O_WRONLY);
+       if (fd < 0)
+               return;
+       sin.sin_family = AF_INET;
+       sin.sin_port   = htons(port);
+       sin.sin_addr.s_addr =  inet_addr(haddr);
+
+       if (NFSCTL_UDPISSET(ctlbits)) {
+               udpfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+               if (udpfd < 0) {
+                       syslog(LOG_ERR, "nfssvc: unable to create UPD socket: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+               if (bind(udpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
+                       syslog(LOG_ERR, "nfssvc: unable to bind UPD socket: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+       }
+
+       if (NFSCTL_TCPISSET(ctlbits)) {
+               tcpfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+               if (tcpfd < 0) {
+                       syslog(LOG_ERR, "nfssvc: unable to createt tcp socket: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+               if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
+                       syslog(LOG_ERR, "nfssvc: unable to set SO_REUSEADDR: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+               if (bind(tcpfd, (struct  sockaddr  *)&sin, sizeof(sin)) < 0){
+                       syslog(LOG_ERR, "nfssvc: unable to bind TCP socket: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+               if (listen(tcpfd, 64) < 0){
+                       syslog(LOG_ERR, "nfssvc: unable to create listening socket: "
+                               "errno %d (%s)\n", errno, strerror(errno));
+                       exit(1);
+               }
+       }
+       if (udpfd >= 0) {
+               snprintf(buf, BUFSIZ,"%d\n", udpfd); 
+               if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+                       syslog(LOG_ERR, 
+                              "nfssvc: writting fds to kernel failed: errno %d (%s)", 
+                              errno, strerror(errno));
+               }
+               close(fd);
+               fd = -1;
+       }
+       if (tcpfd >= 0) {
+               if (fd < 0)
+                       fd = open(NFSD_PORTS_FILE, O_WRONLY);
+               snprintf(buf, BUFSIZ,"%d\n", tcpfd); 
+               if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+                       syslog(LOG_ERR, 
+                              "nfssvc: writting fds to kernel failed: errno %d (%s)", 
+                              errno, strerror(errno));
+               }
+       }
+       close(fd);
+
+       return;
+}
 static void
 nfssvc_versbits(unsigned int ctlbits)
 {
 static void
 nfssvc_versbits(unsigned int ctlbits)
 {
@@ -25,7 +109,7 @@ nfssvc_versbits(unsigned int ctlbits)
 
        ptr = buf;
        off = 0;
 
        ptr = buf;
        off = 0;
-       fd = open("/proc/fs/nfsd/versions", O_WRONLY);
+       fd = open(NFSD_VERS_FILE, O_WRONLY);
        if (fd < 0)
                return;
 
        if (fd < 0)
                return;
 
@@ -45,14 +129,17 @@ nfssvc_versbits(unsigned int ctlbits)
        return;
 }
 int
        return;
 }
 int
-nfssvc(int port, int nrservs, unsigned int versbits)
+nfssvc(int port, int nrservs, unsigned int versbits, unsigned protobits,
+       char *haddr)
 {
        struct nfsctl_arg       arg;
        int fd;
 
 {
        struct nfsctl_arg       arg;
        int fd;
 
+       nfssvc_setfds(port, protobits, haddr);
+
        nfssvc_versbits(versbits);
 
        nfssvc_versbits(versbits);
 
-       fd = open("/proc/fs/nfsd/threads", O_WRONLY);
+       fd = open(NFSD_THREAD_FILE, O_WRONLY);
        if (fd < 0)
                fd = open("/proc/fs/nfs/threads", O_WRONLY);
        if (fd >= 0) {
        if (fd < 0)
                fd = open("/proc/fs/nfs/threads", O_WRONLY);
        if (fd >= 0) {
index fa6ee71fdd6443245511a4b105df891017106905..d0bbfb30abd721cecea08c80f8deee6b82a9425d 100644 (file)
 #include <getopt.h>
 #include <syslog.h>
 #include <netdb.h>
 #include <getopt.h>
 #include <syslog.h>
 #include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
 #include "nfslib.h"
 
 static void    usage(const char *);
 
 static struct option longopts[] =
 {
 #include "nfslib.h"
 
 static void    usage(const char *);
 
 static struct option longopts[] =
 {
+       { "host", 1, 0, 'H' },
        { "help", 0, 0, 'h' },
        { "no-nfs-version", 1, 0, 'N' },
        { "help", 0, 0, 'h' },
        { "no-nfs-version", 1, 0, 'N' },
+       { "no-tcp", 0, 0, 'T' },
+       { "no-udp", 0, 0, 'U' },
+       { "port", 1, 0, 'P' },
+       { "port", 1, 0, 'p' },
        { NULL, 0, 0, 0 }
 };
        { NULL, 0, 0, 0 }
 };
+unsigned int protobits = NFSCTL_ALLBITS;
 unsigned int versbits = NFSCTL_ALLBITS;
 unsigned int versbits = NFSCTL_ALLBITS;
+char *haddr = NULL;
 
 int
 main(int argc, char **argv)
 {
        int     count = 1, c, error, port, fd, found_one;
        struct servent *ent;
 
 int
 main(int argc, char **argv)
 {
        int     count = 1, c, error, port, fd, found_one;
        struct servent *ent;
+       struct hostent *hp;
 
        ent = getservbyname ("nfs", "udp");
        if (ent != NULL)
 
        ent = getservbyname ("nfs", "udp");
        if (ent != NULL)
@@ -44,8 +56,19 @@ main(int argc, char **argv)
        else
                port = 2049;
 
        else
                port = 2049;
 
-       while ((c = getopt_long(argc, argv, "hN:p:P:", longopts, NULL)) != EOF) {
+       while ((c = getopt_long(argc, argv, "H:hN:p:P:TU", longopts, NULL)) != EOF) {
                switch(c) {
                switch(c) {
+               case 'H':
+                       if (inet_addr(optarg) != INADDR_NONE) {
+                               haddr = strdup(optarg);
+                       } else if ((hp = gethostbyname(optarg)) != NULL) {
+                               haddr = inet_ntoa((*(struct in_addr*)(hp->h_addr_list[0])));
+                       } else {
+                               fprintf(stderr, "%s: Unknown hostname: %s\n",
+                                       argv[0], optarg);
+                               usage(argv [0]);
+                       }
+                       break;
                case 'P':       /* XXX for nfs-server compatibility */
                case 'p':
                        port = atoi(optarg);
                case 'P':       /* XXX for nfs-server compatibility */
                case 'p':
                        port = atoi(optarg);
@@ -67,6 +90,12 @@ main(int argc, char **argv)
                                exit(1);
                        }
                        break;
                                exit(1);
                        }
                        break;
+               case 'T':
+                               NFSCTL_TCPUNSET(protobits);
+                               break;
+               case 'U':
+                               NFSCTL_UDPUNSET(protobits);
+                               break;
                default:
                        fprintf(stderr, "Invalid argument: '%c'\n", c);
                case 'h':
                default:
                        fprintf(stderr, "Invalid argument: '%c'\n", c);
                case 'h':
@@ -76,6 +105,10 @@ main(int argc, char **argv)
        /*
         * Do some sanity checking, if the ctlbits are set
         */
        /*
         * Do some sanity checking, if the ctlbits are set
         */
+       if (!NFSCTL_UDPISSET(protobits) && !NFSCTL_TCPISSET(protobits)) {
+               fprintf(stderr, "invalid protocol specified\n");
+               exit(1);
+       }
        found_one = 0;
        for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
                if (NFSCTL_VERISSET(versbits, c))
        found_one = 0;
        for (c = NFSD_MINVERS; c <= NFSD_MAXVERS; c++) {
                if (NFSCTL_VERISSET(versbits, c))
@@ -85,6 +118,14 @@ main(int argc, char **argv)
                fprintf(stderr, "no version specified\n");
                exit(1);
        }                       
                fprintf(stderr, "no version specified\n");
                exit(1);
        }                       
+       if (NFSCTL_VERISSET(versbits, 4) && !NFSCTL_TCPISSET(versbits)) {
+               fprintf(stderr, "version 4 requires the TCP protocol\n");
+               exit(1);
+       }
+       if (haddr == NULL) {
+               struct in_addr in = {INADDR_ANY}; 
+               haddr = strdup(inet_ntoa(in));
+       }
 
        if (chdir(NFS_STATEDIR)) {
                fprintf(stderr, "%s: chdir(%s) failed: %s\n",
 
        if (chdir(NFS_STATEDIR)) {
                fprintf(stderr, "%s: chdir(%s) failed: %s\n",
@@ -116,7 +157,7 @@ main(int argc, char **argv)
        closeall(3);
 
        openlog("nfsd", LOG_PID, LOG_DAEMON);
        closeall(3);
 
        openlog("nfsd", LOG_PID, LOG_DAEMON);
-       if ((error = nfssvc(port, count, versbits)) < 0) {
+       if ((error = nfssvc(port, count, versbits, protobits, haddr)) < 0) {
                int e = errno;
                syslog(LOG_ERR, "nfssvc: %s", strerror(e));
                closelog();
                int e = errno;
                syslog(LOG_ERR, "nfssvc: %s", strerror(e));
                closelog();
@@ -129,7 +170,7 @@ static void
 usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
 usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
-               "%s [-p|-P|--port port] [-N|--no-nfs-version version ] nrservs\n", 
+               "%s [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
                prog);
        exit(2);
 }
                prog);
        exit(2);
 }
index d175d11677b8a39795e168da1ee72db0fa31e008..4ac709c64d0670c687df7302d666328798be6a15 100644 (file)
@@ -22,6 +22,17 @@ server provides an ancillary service needed to satisfy mount requests
 by NFS clients.
 .SH OPTIONS
 .TP
 by NFS clients.
 .SH OPTIONS
 .TP
+.B \-H " or " \-\-host  hostname
+specify a particular hostname (or address) that NFS requests will
+be accepted on. By default,
+.B rpc.nfsd
+will accept NFS requests on all known network addresses.
+Note that
+.B lockd
+(which performs file locking services for NFS) may still accept
+request on all known network addresses.  This may change in future
+releases of the Linux Kernel.
+.TP
 .B \-p " or " \-\-port  port
 specify a diferent port to listen on for NFS requests. By default,
 .B rpc.nfsd
 .B \-p " or " \-\-port  port
 specify a diferent port to listen on for NFS requests. By default,
 .B rpc.nfsd
@@ -34,6 +45,16 @@ does not offer certain versions of NFS. The current version of
 .B rpc.nfsd
 can support both NFS version 2,3 and the newer version 4.
 .TP
 .B rpc.nfsd
 can support both NFS version 2,3 and the newer version 4.
 .TP
+.B \-T " or " \-\-no-tcp
+Disable 
+.B rpc.nfsd 
+from accepting TCP connections from clients.
+.TP
+.B \-U " or " \-\-no-udp
+Disable
+.B rpc.nfsd
+from accepting UDP connections from clients.
+.TP
 .I nproc
 specify the number of NFS server threads. By default, just one
 thread is started. However, for optimum performance several threads
 .I nproc
 specify the number of NFS server threads. By default, just one
 thread is started. However, for optimum performance several threads