Subject: bin/30772: Enable mountd(8) to bind to a fixed, user-given port
To: None <gnats-admin@netbsd.org, netbsd-bugs@netbsd.org>
From: None <netbsd@wolfnode.de>
List: netbsd-bugs
Date: 07/17/2005 23:36:00
>Number: 30772
>Category: bin
>Synopsis: Enable mountd(8) to bind to a fixed, user-given port
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Jul 17 23:36:00 +0000 2005
>Originator: Florian Stoehr
>Release: HEAD
>Organization:
>Environment:
-
>Description:
By default, mountd(8) binds to any port in the range 600-1023 which is horrible if one wants to enable NFS through a firewall.
This patch introduces a "-p <port>" to mountd, forcing it to bind to the specified port.
The patch is for IPv4 and IPv6. I've tested this on IPv4 only, so someone MUST LOOK AT THE CODE for IPv6. In particular, I don't known whether letting sin6->flow be zero is OK or not.
Patches for mountd.c as well as mountd.8 appended.
>How-To-Repeat:
>Fix:
--- src/usr.sbin/mountd/mountd.8.orig 2005-07-18 01:16:03.000000000 +0200
+++ src/usr.sbin/mountd/mountd.8 2005-07-18 01:16:21.000000000 +0200
@@ -29,7 +29,7 @@
.\"
.\" @(#)mountd.8 8.4 (Berkeley) 4/28/95
.\"
-.Dd January 14, 2005
+.Dd July 17, 2005
.Dt MOUNTD 8
.Os
.Sh NAME
@@ -40,6 +40,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl dNn
+.Op Fl p Ar port
.Op Fl P Ar policy
.Op Ar exportsfile
.Sh DESCRIPTION
@@ -78,11 +79,15 @@
is only provided for backwards compatibility. Requests
are checked for reserved ports on a per-export basis, see
.Xr exports 5 .
-.It Ar exportsfile
-The
-.Ar exportsfile
-argument specifies an alternative location
-for the exports file.
+.It Fl p Ar port
+Force
+.Nm
+to bind to the given port. If this
+option is not given,
+.Nm
+may bind to every anonymous port
+(in the range 600-1023) which causes trouble when trying to use
+NFS through a firewall.
.It Fl P Ar policy
IPsec
.Ar policy
@@ -94,6 +99,11 @@
the last string will take effect. If an invalid IPsec policy string is used
.Nm
logs an error message and terminates itself.
+.It Ar exportsfile
+The
+.Ar exportsfile
+argument specifies an alternative location
+for the exports file.
.El
.Pp
When
--- src/usr.sbin/mountd/mountd.c.orig 2005-06-04 01:22:36.000000000 +0200
+++ src/usr.sbin/mountd/mountd.c 2005-07-17 04:40:57.000000000 +0200
@@ -265,6 +265,7 @@
#define OP_MASKLEN 0x200
static int debug = 0;
+static int forcedport = 0;
#if 0
static void SYSLOG __P((int, const char *,...));
#endif
@@ -291,10 +292,13 @@
{
SVCXPRT *udptransp, *tcptransp, *udp6transp, *tcp6transp;
struct netconfig *udpconf, *tcpconf, *udp6conf, *tcp6conf;
+ struct sockaddr_in *udpforcedsa = NULL, *tcpforcedsa = NULL;
+ struct sockaddr_in6 *udpforcedsa6 = NULL, *tcpforcedsa6 = NULL;
int udpsock, tcpsock, udp6sock, tcp6sock;
int xcreated = 0, s;
int c, one = 1;
int maxrec = RPC_MAXDATASIZE;
+ extern char* optarg;
#ifdef IPSEC
char *policy = NULL;
#define ADDOPTS "P:"
@@ -302,7 +306,7 @@
#define ADDOPTS
#endif
- while ((c = getopt(argc, argv, "dNnr" ADDOPTS)) != -1)
+ while ((c = getopt(argc, argv, "dNnrp:" ADDOPTS)) != -1)
switch (c) {
#ifdef IPSEC
case 'P':
@@ -320,8 +324,12 @@
case 'n':
case 'r':
break;
+ case 'p':
+ /* A forced port "0" will dynamically allocate a port */
+ forcedport = atoi(optarg);
+ break;
default:
- fprintf(stderr, "usage: %s [-dNn]"
+ fprintf(stderr, "usage: %s [-dNn] [-p port]"
#ifdef IPSEC
" [-P ipsec policy]"
#endif
@@ -394,7 +402,25 @@
rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
if (udpsock != -1 && udpconf != NULL) {
- bindresvport(udpsock, NULL);
+ if (forcedport == 0) {
+ /* Dynamically allocate the port */
+ bindresvport(udpsock, NULL);
+ } else {
+ /* Force the port */
+ udpforcedsa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
+ memset(udpforcedsa, 0, sizeof(struct sockaddr_in));
+ udpforcedsa->sin_len = sizeof(struct sockaddr_in);
+ udpforcedsa->sin_family = AF_INET;
+ udpforcedsa->sin_port = htons(forcedport);
+
+ if (bindresvport(udpsock, udpforcedsa) == 0) {
+ if (debug)
+ (void)fprintf(stderr, "Forced udp port %d opened successfully\n", forcedport);
+ } else {
+ if (debug)
+ (void)fprintf(stderr, "Could not open forced udp port %d\n", forcedport);
+ }
+ }
#ifdef IPSEC
if (policy)
ipsecsetup(AF_INET, udpsock, policy);
@@ -414,7 +440,25 @@
}
if (tcpsock != -1 && tcpconf != NULL) {
- bindresvport(tcpsock, NULL);
+ if (forcedport == 0) {
+ /* Dynamically allocate the port */
+ bindresvport(tcpsock, NULL);
+ } else {
+ /* Force the port */
+ tcpforcedsa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
+ memset(tcpforcedsa, 0, sizeof(struct sockaddr_in));
+ tcpforcedsa->sin_len = sizeof(struct sockaddr_in);
+ tcpforcedsa->sin_family = AF_INET;
+ tcpforcedsa->sin_port = htons(forcedport);
+
+ if (bindresvport(tcpsock, tcpforcedsa) == 0) {
+ if (debug)
+ (void)fprintf(stderr, "Forced tcp port %d opened successfully\n", forcedport);
+ } else {
+ if (debug)
+ (void)fprintf(stderr, "Could not open forced tcp port %d\n", forcedport);
+ }
+ }
#ifdef IPSEC
if (policy)
ipsecsetup(AF_INET, tcpsock, policy);
@@ -436,7 +480,25 @@
}
if (udp6sock != -1 && udp6conf != NULL) {
- bindresvport(udp6sock, NULL);
+ if (forcedport == 0) {
+ /* Dynamically allocate the port */
+ bindresvport(udp6sock, NULL);
+ } else {
+ /* Force the port */
+ udpforcedsa6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
+ memset(udpforcedsa6, 0, sizeof(struct sockaddr_in6));
+ udpforcedsa6->sin6_len = sizeof(struct sockaddr_in6);
+ udpforcedsa6->sin6_family = AF_INET6;
+ udpforcedsa6->sin6_port = htons(forcedport);
+
+ if (bindresvport_sa(udp6sock, (struct sockaddr *)udpforcedsa6) == 0) {
+ if (debug)
+ (void)fprintf(stderr, "Forced udp6 port %d opened successfully\n", forcedport);
+ } else {
+ if (debug)
+ (void)fprintf(stderr, "Could not open forced udp6 port %d\n", forcedport);
+ }
+ }
#ifdef IPSEC
if (policy)
ipsecsetup(AF_INET6, tcpsock, policy);
@@ -456,7 +518,25 @@
}
if (tcp6sock != -1 && tcp6conf != NULL) {
- bindresvport(tcp6sock, NULL);
+ if (forcedport == 0) {
+ /* Dynamically allocate the port */
+ bindresvport(tcp6sock, NULL);
+ } else {
+ /* Force the port */
+ tcpforcedsa6 = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
+ memset(tcpforcedsa6, 0, sizeof(struct sockaddr_in6));
+ tcpforcedsa6->sin6_len = sizeof(struct sockaddr_in6);
+ tcpforcedsa6->sin6_family = AF_INET6;
+ tcpforcedsa6->sin6_port = htons(forcedport);
+
+ if (bindresvport_sa(tcp6sock, (struct sockaddr *)tcpforcedsa6) == 0) {
+ if (debug)
+ (void)fprintf(stderr, "Forced tcp6 port %d opened successfully\n", forcedport);
+ } else {
+ if (debug)
+ (void)fprintf(stderr, "Could not open forced tcp6 port %d\n", forcedport);
+ }
+ }
#ifdef IPSEC
if (policy)
ipsecsetup(AF_INET6, tcpsock, policy);
@@ -486,6 +566,19 @@
kuidinit();
#endif
svc_run();
+
+ if (udpforcedsa != NULL)
+ free(udpforcedsa);
+
+ if (tcpforcedsa != NULL)
+ free(tcpforcedsa);
+
+ if (udpforcedsa6 != NULL)
+ free(udpforcedsa6);
+
+ if (tcpforcedsa6 != NULL)
+ free(tcpforcedsa6);
+
syslog(LOG_ERR, "Mountd died");
exit(1);
}