2011-04-19 08:44:33

by Mi Jinlong

[permalink] [raw]
Subject: [PATCH] svc: make sure mountd can get ports from /etc/services

At RHEL, if user set port for mountd at /etc/services as
"mount 12345/tcp", mountd should be bind to 12345, but the
latest nfs-utils, mountd get a rand port, not 12345.

This patch make sure mountd be bind to the port which was set
at /etc/service.

Signed-off-by: Mi Jinlong <[email protected]>
---
support/include/rpcmisc.h | 1 +
support/nfs/svc_create.c | 9 ++++-
support/nfs/svc_socket.c | 83 +++++++++++++++++++++-----------------------
3 files changed, 48 insertions(+), 45 deletions(-)

diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
index 0b06457..b806227 100644
--- a/support/include/rpcmisc.h
+++ b/support/include/rpcmisc.h
@@ -53,6 +53,7 @@ void rpc_init(char *name, int prog, int vers,
void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
struct rpc_dtable *dtable, int nvers,
void *argp, void *resp);
+int getservport(u_long number, const char *proto);

extern int _rpcpmstart;
extern int _rpcfdtype;
diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
index b3f75ed..fd09902 100644
--- a/support/nfs/svc_create.c
+++ b/support/nfs/svc_create.c
@@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
const struct sigaction create_sigaction = {
.sa_handler = SIG_IGN,
};
- unsigned int visible, up;
+ unsigned int visible, up, servport;
struct netconfig *nconf;
void *handlep;

@@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
visible++;
+ if (port == 0)
+ servport = getservport(program, nconf->nc_proto);
+ else
+ servport = port;
+
up += svc_create_nconf(name, program, version, dispatch,
- port, nconf);
+ servport, nconf);
}

if (visible == 0)
diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
index 03a5325..ec406a9 100644
--- a/support/nfs/svc_socket.c
+++ b/support/nfs/svc_socket.c
@@ -35,14 +35,46 @@
# define __close(f) close ((f))
#endif

+int getservport(u_long number, const char *proto)
+{
+ char rpcdata [1024], servdata [1024];
+ struct rpcent rpcbuf, *rpcp;
+ struct servent servbuf, *servp = NULL;
+ int ret;
+
+ ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
+ &rpcp);
+ if (ret == 0 && rpcp != NULL)
+ {
+ /* First try name. */
+ ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
+ sizeof servdata, &servp);
+ if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
+ {
+ const char **a;
+
+ /* Then we try aliases. */
+ for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
+ {
+ ret = getservbyname_r (*a, proto, &servbuf, servdata,
+ sizeof servdata, &servp);
+ if (ret == 0 && servp != NULL)
+ break;
+ }
+ }
+ }
+
+ if (ret == 0 && servp != NULL)
+ return ntohs(servp->s_port);
+
+ return 0;
+}
+
static int
svc_socket (u_long number, int type, int protocol, int reuse)
{
struct sockaddr_in addr;
socklen_t len = sizeof (struct sockaddr_in);
- char rpcdata [1024], servdata [1024];
- struct rpcent rpcbuf, *rpcp;
- struct servent servbuf, *servp = NULL;
int sock, ret;
const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";

@@ -66,48 +98,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)

memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
+ addr.sin_port = htons(getservport(number, proto));

- ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
- &rpcp);
- if (ret == 0 && rpcp != NULL)
+ if (bind (sock, (struct sockaddr *) &addr, len) < 0)
{
- /* First try name. */
- ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
- sizeof servdata, &servp);
- if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
- {
- const char **a;
-
- /* Then we try aliases. */
- for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
- {
- ret = getservbyname_r (*a, proto, &servbuf, servdata,
- sizeof servdata, &servp);
- if (ret == 0 && servp != NULL)
- break;
- }
- }
- }
-
- if (ret == 0 && servp != NULL)
- {
- addr.sin_port = servp->s_port;
- if (bind (sock, (struct sockaddr *) &addr, len) < 0)
- {
- perror (_("svc_socket: bind problem"));
- (void) __close (sock);
- sock = -1;
- }
- }
- else
- {
- addr.sin_port = 0;
- if (bind (sock, (struct sockaddr *) &addr, len) < 0)
- {
- perror (_("svc_socket: bind problem"));
- (void) __close (sock);
- sock = -1;
- }
+ perror (_("svc_socket: bind problem"));
+ (void) __close (sock);
+ sock = -1;
}

if (sock >= 0)
--
1.7.4.1





2011-04-19 13:28:33

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services

Hi MJ-

On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:

> At RHEL, if user set port for mountd at /etc/services as
> "mount 12345/tcp", mountd should be bind to 12345, but the
> latest nfs-utils, mountd get a rand port, not 12345.
>
> This patch make sure mountd be bind to the port which was set
> at /etc/service.

I don't think this is documented anywhere. Is there a reason it should work this way?

The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.

> Signed-off-by: Mi Jinlong <[email protected]>
> ---
> support/include/rpcmisc.h | 1 +
> support/nfs/svc_create.c | 9 ++++-
> support/nfs/svc_socket.c | 83 +++++++++++++++++++++-----------------------
> 3 files changed, 48 insertions(+), 45 deletions(-)
>
> diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
> index 0b06457..b806227 100644
> --- a/support/include/rpcmisc.h
> +++ b/support/include/rpcmisc.h
> @@ -53,6 +53,7 @@ void rpc_init(char *name, int prog, int vers,
> void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
> struct rpc_dtable *dtable, int nvers,
> void *argp, void *resp);
> +int getservport(u_long number, const char *proto);
>
> extern int _rpcpmstart;
> extern int _rpcfdtype;
> diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
> index b3f75ed..fd09902 100644
> --- a/support/nfs/svc_create.c
> +++ b/support/nfs/svc_create.c
> @@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
> const struct sigaction create_sigaction = {
> .sa_handler = SIG_IGN,
> };
> - unsigned int visible, up;
> + unsigned int visible, up, servport;
> struct netconfig *nconf;
> void *handlep;
>
> @@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
> if (!(nconf->nc_flag & NC_VISIBLE))
> continue;
> visible++;
> + if (port == 0)
> + servport = getservport(program, nconf->nc_proto);
> + else
> + servport = port;
> +
> up += svc_create_nconf(name, program, version, dispatch,
> - port, nconf);
> + servport, nconf);
> }
>
> if (visible == 0)
> diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
> index 03a5325..ec406a9 100644
> --- a/support/nfs/svc_socket.c
> +++ b/support/nfs/svc_socket.c
> @@ -35,14 +35,46 @@
> # define __close(f) close ((f))
> #endif
>
> +int getservport(u_long number, const char *proto)
> +{
> + char rpcdata [1024], servdata [1024];
> + struct rpcent rpcbuf, *rpcp;
> + struct servent servbuf, *servp = NULL;
> + int ret;
> +
> + ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
> + &rpcp);
> + if (ret == 0 && rpcp != NULL)
> + {
> + /* First try name. */
> + ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
> + sizeof servdata, &servp);
> + if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
> + {
> + const char **a;
> +
> + /* Then we try aliases. */
> + for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
> + {
> + ret = getservbyname_r (*a, proto, &servbuf, servdata,
> + sizeof servdata, &servp);
> + if (ret == 0 && servp != NULL)
> + break;
> + }
> + }
> + }
> +
> + if (ret == 0 && servp != NULL)
> + return ntohs(servp->s_port);
> +
> + return 0;
> +}
> +
> static int
> svc_socket (u_long number, int type, int protocol, int reuse)
> {
> struct sockaddr_in addr;
> socklen_t len = sizeof (struct sockaddr_in);
> - char rpcdata [1024], servdata [1024];
> - struct rpcent rpcbuf, *rpcp;
> - struct servent servbuf, *servp = NULL;
> int sock, ret;
> const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
>
> @@ -66,48 +98,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)
>
> memset (&addr, 0, sizeof (addr));
> addr.sin_family = AF_INET;
> + addr.sin_port = htons(getservport(number, proto));
>
> - ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
> - &rpcp);
> - if (ret == 0 && rpcp != NULL)
> + if (bind (sock, (struct sockaddr *) &addr, len) < 0)
> {
> - /* First try name. */
> - ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
> - sizeof servdata, &servp);
> - if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
> - {
> - const char **a;
> -
> - /* Then we try aliases. */
> - for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
> - {
> - ret = getservbyname_r (*a, proto, &servbuf, servdata,
> - sizeof servdata, &servp);
> - if (ret == 0 && servp != NULL)
> - break;
> - }
> - }
> - }
> -
> - if (ret == 0 && servp != NULL)
> - {
> - addr.sin_port = servp->s_port;
> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
> - {
> - perror (_("svc_socket: bind problem"));
> - (void) __close (sock);
> - sock = -1;
> - }
> - }
> - else
> - {
> - addr.sin_port = 0;
> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
> - {
> - perror (_("svc_socket: bind problem"));
> - (void) __close (sock);
> - sock = -1;
> - }
> + perror (_("svc_socket: bind problem"));
> + (void) __close (sock);
> + sock = -1;
> }
>
> if (sock >= 0)
> --
> 1.7.4.1
>
>
>

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





2011-04-25 07:07:26

by Mi Jinlong

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services



Chuck Lever :
> On Apr 20, 2011, at 11:42 PM, Mi Jinlong wrote:
>
>>
>> Chuck Lever:
>>> On Apr 20, 2011, at 5:29 AM, Mi Jinlong wrote:
>>>
>>>> Chuck Lever:
>>>>> Hi MJ-
>>>>>
>>>>> On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:
>>>>>
>>>>>> At RHEL, if user set port for mountd at /etc/services as
>>>>>> "mount 12345/tcp", mountd should be bind to 12345, but the
>>>>>> latest nfs-utils, mountd get a rand port, not 12345.
>>>>>>
>>>>>> This patch make sure mountd be bind to the port which was set
>>>>>> at /etc/service.
>>>>> I don't think this is documented anywhere. Is there a reason it should work this way?
>>>>>
>>>>> The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.
>>>> I don't have a depth research, agree with you.
>>>> But I got different result when I set port for mountd at /etc/services
>>>> between nfs-utils-1.2.3 and nfs-utils-1.2.2.
>>> IMO that's unintentional behavior. Could I ask a favor: would you bisect nfs-utils to find out exactly where this started and ended?
>> Hi Chuck,
>>
>> It's after your patch "mountd: Support TI-RPC mountd listener"
>> (commit id:b551b1fd0052de9b8c674b30c39d9f2a1e9d79cc).
>>
>> Before this patch, mountd call rpc_init to create rpc socket,
>> after it, if HAVE_LIBTIRPC is defined, mountd will call
>> nfs_svc_create to create rpc socket, that appears.
>
> Thanks. I don't immediately see how that code path consults /etc/services. There are no calls to getservby{name,port}(3) in either mountd or in libtirpc. Did I miss something? Any idea?
>
mountd main()
--> rpc_init()
--> svcudp_socket()
--> svc_socket()
--> getservbyname_r() ***

> You said it stopped working after a while. Can you bisect that as well?
>
> Note that if nfs-utils is built without TI-RPC support, rpc_init() is still used instead of nfs_svc_create(). If nfs_svc_create() is indeed the proximal cause of this behavior, mountd won't consult /etc/services if it is built without TI-RPC support. So it might be a bug if this works for some build configurations and doesn't work for others. The question is should it always work, or should it never work; see below.
>

If building without TI-RPC support, mountd will get ports from /etc/service.
With TI-RPC support, mountd will not get ports from /etc/service. That's the problem.

>>>> I just think we should get the same result at new nfs-utils as older.
>>> Is there a real-world use case for this feature? Why isn't the command line option adequate?
>>>
>> I have a test site which depend on this feature.
>> If this feature indeed unnecessary, I will try to modify my test site.
>
> Without knowing more about your test site, I claim it can and should use the "-p" option on rpc.mountd. If your distribution of choice is Red Hat-based, you can set this in /etc/sysconfig/nfs (see MOUNTD_PORT=).
>

Got it, thanks!

> In other words, we have a documented and supported mechanism now, that should always work, for setting mountd's listener port. Can you explain in detail why allowing /etc/services to have this effect is also necessary?
>

I just think the new nfs-utils should do the same thing as older one.
Maybe called backward compatibility.

--
----
thanks
Mi Jinlong


2011-04-25 15:58:35

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services


On Apr 25, 2011, at 3:09 AM, Mi Jinlong wrote:

> Chuck Lever :
>
>> In other words, we have a documented and supported mechanism now, that should always work, for setting mountd's listener port. Can you explain in detail why allowing /etc/services to have this effect is also necessary?
>
> I just think the new nfs-utils should do the same thing as older one.
> Maybe called backward compatibility.

I was confused by your original report.

Before, I read that with the commit mentioned above, /etc/services started working, then it stopped at some later point. Now you seem to be saying that /etc/services always worked this way, but with the commit above, it stops working. I've filed a bugzilla to track the issue:

https://bugzilla.linux-nfs.org/show_bug.cgi?id=200

If you can find documentation that describes this feature (ie makes it a formal API, or describes any other details about its operation we should know of), or know of a widely deployed application of mountd or statd that requires it, please do let us know, or modify the bugzilla report.

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





2011-04-20 09:28:09

by Mi Jinlong

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services



Chuck Lever:
> Hi MJ-
>
> On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:
>
>> At RHEL, if user set port for mountd at /etc/services as
>> "mount 12345/tcp", mountd should be bind to 12345, but the
>> latest nfs-utils, mountd get a rand port, not 12345.
>>
>> This patch make sure mountd be bind to the port which was set
>> at /etc/service.
>
> I don't think this is documented anywhere. Is there a reason it should work this way?
>
> The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.

I don't have a depth research, agree with you.
But I got different result when I set port for mountd at /etc/services
between nfs-utils-1.2.3 and nfs-utils-1.2.2.

I just think we should get the same result at new nfs-utils as older.

--
----
thanks
Mi Jinlong

>
>> Signed-off-by: Mi Jinlong <[email protected]>
>> ---
>> support/include/rpcmisc.h | 1 +
>> support/nfs/svc_create.c | 9 ++++-
>> support/nfs/svc_socket.c | 83 +++++++++++++++++++++-----------------------
>> 3 files changed, 48 insertions(+), 45 deletions(-)
>>
>> diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
>> index 0b06457..b806227 100644
>> --- a/support/include/rpcmisc.h
>> +++ b/support/include/rpcmisc.h
>> @@ -53,6 +53,7 @@ void rpc_init(char *name, int prog, int vers,
>> void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
>> struct rpc_dtable *dtable, int nvers,
>> void *argp, void *resp);
>> +int getservport(u_long number, const char *proto);
>>
>> extern int _rpcpmstart;
>> extern int _rpcfdtype;
>> diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
>> index b3f75ed..fd09902 100644
>> --- a/support/nfs/svc_create.c
>> +++ b/support/nfs/svc_create.c
>> @@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
>> const struct sigaction create_sigaction = {
>> .sa_handler = SIG_IGN,
>> };
>> - unsigned int visible, up;
>> + unsigned int visible, up, servport;
>> struct netconfig *nconf;
>> void *handlep;
>>
>> @@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
>> if (!(nconf->nc_flag & NC_VISIBLE))
>> continue;
>> visible++;
>> + if (port == 0)
>> + servport = getservport(program, nconf->nc_proto);
>> + else
>> + servport = port;
>> +
>> up += svc_create_nconf(name, program, version, dispatch,
>> - port, nconf);
>> + servport, nconf);
>> }
>>
>> if (visible == 0)
>> diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
>> index 03a5325..ec406a9 100644
>> --- a/support/nfs/svc_socket.c
>> +++ b/support/nfs/svc_socket.c
>> @@ -35,14 +35,46 @@
>> # define __close(f) close ((f))
>> #endif
>>
>> +int getservport(u_long number, const char *proto)
>> +{
>> + char rpcdata [1024], servdata [1024];
>> + struct rpcent rpcbuf, *rpcp;
>> + struct servent servbuf, *servp = NULL;
>> + int ret;
>> +
>> + ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
>> + &rpcp);
>> + if (ret == 0 && rpcp != NULL)
>> + {
>> + /* First try name. */
>> + ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
>> + sizeof servdata, &servp);
>> + if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
>> + {
>> + const char **a;
>> +
>> + /* Then we try aliases. */
>> + for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
>> + {
>> + ret = getservbyname_r (*a, proto, &servbuf, servdata,
>> + sizeof servdata, &servp);
>> + if (ret == 0 && servp != NULL)
>> + break;
>> + }
>> + }
>> + }
>> +
>> + if (ret == 0 && servp != NULL)
>> + return ntohs(servp->s_port);
>> +
>> + return 0;
>> +}
>> +
>> static int
>> svc_socket (u_long number, int type, int protocol, int reuse)
>> {
>> struct sockaddr_in addr;
>> socklen_t len = sizeof (struct sockaddr_in);
>> - char rpcdata [1024], servdata [1024];
>> - struct rpcent rpcbuf, *rpcp;
>> - struct servent servbuf, *servp = NULL;
>> int sock, ret;
>> const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
>>
>> @@ -66,48 +98,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)
>>
>> memset (&addr, 0, sizeof (addr));
>> addr.sin_family = AF_INET;
>> + addr.sin_port = htons(getservport(number, proto));
>>
>> - ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
>> - &rpcp);
>> - if (ret == 0 && rpcp != NULL)
>> + if (bind (sock, (struct sockaddr *) &addr, len) < 0)
>> {
>> - /* First try name. */
>> - ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
>> - sizeof servdata, &servp);
>> - if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
>> - {
>> - const char **a;
>> -
>> - /* Then we try aliases. */
>> - for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
>> - {
>> - ret = getservbyname_r (*a, proto, &servbuf, servdata,
>> - sizeof servdata, &servp);
>> - if (ret == 0 && servp != NULL)
>> - break;
>> - }
>> - }
>> - }
>> -
>> - if (ret == 0 && servp != NULL)
>> - {
>> - addr.sin_port = servp->s_port;
>> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
>> - {
>> - perror (_("svc_socket: bind problem"));
>> - (void) __close (sock);
>> - sock = -1;
>> - }
>> - }
>> - else
>> - {
>> - addr.sin_port = 0;
>> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
>> - {
>> - perror (_("svc_socket: bind problem"));
>> - (void) __close (sock);
>> - sock = -1;
>> - }
>> + perror (_("svc_socket: bind problem"));
>> + (void) __close (sock);
>> + sock = -1;
>> }
>>
>> if (sock >= 0)
>> --
>> 1.7.4.1
>>
>>
>>
>


2011-04-21 14:11:26

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services


On Apr 20, 2011, at 11:42 PM, Mi Jinlong wrote:

>
>
> Chuck Lever:
>> On Apr 20, 2011, at 5:29 AM, Mi Jinlong wrote:
>>
>>>
>>> Chuck Lever:
>>>> Hi MJ-
>>>>
>>>> On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:
>>>>
>>>>> At RHEL, if user set port for mountd at /etc/services as
>>>>> "mount 12345/tcp", mountd should be bind to 12345, but the
>>>>> latest nfs-utils, mountd get a rand port, not 12345.
>>>>>
>>>>> This patch make sure mountd be bind to the port which was set
>>>>> at /etc/service.
>>>> I don't think this is documented anywhere. Is there a reason it should work this way?
>>>>
>>>> The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.
>>> I don't have a depth research, agree with you.
>>> But I got different result when I set port for mountd at /etc/services
>>> between nfs-utils-1.2.3 and nfs-utils-1.2.2.
>>
>> IMO that's unintentional behavior. Could I ask a favor: would you bisect nfs-utils to find out exactly where this started and ended?
>
> Hi Chuck,
>
> It's after your patch "mountd: Support TI-RPC mountd listener"
> (commit id:b551b1fd0052de9b8c674b30c39d9f2a1e9d79cc).
>
> Before this patch, mountd call rpc_init to create rpc socket,
> after it, if HAVE_LIBTIRPC is defined, mountd will call
> nfs_svc_create to create rpc socket, that appears.

Thanks. I don't immediately see how that code path consults /etc/services. There are no calls to getservby{name,port}(3) in either mountd or in libtirpc. Did I miss something? Any idea?

You said it stopped working after a while. Can you bisect that as well?

Note that if nfs-utils is built without TI-RPC support, rpc_init() is still used instead of nfs_svc_create(). If nfs_svc_create() is indeed the proximal cause of this behavior, mountd won't consult /etc/services if it is built without TI-RPC support. So it might be a bug if this works for some build configurations and doesn't work for others. The question is should it always work, or should it never work; see below.

>
>>
>>> I just think we should get the same result at new nfs-utils as older.
>>
>> Is there a real-world use case for this feature? Why isn't the command line option adequate?
>>
>
> I have a test site which depend on this feature.
> If this feature indeed unnecessary, I will try to modify my test site.

Without knowing more about your test site, I claim it can and should use the "-p" option on rpc.mountd. If your distribution of choice is Red Hat-based, you can set this in /etc/sysconfig/nfs (see MOUNTD_PORT=).

In other words, we have a documented and supported mechanism now, that should always work, for setting mountd's listener port. Can you explain in detail why allowing /etc/services to have this effect is also necessary?

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





2011-04-20 15:09:39

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services


On Apr 20, 2011, at 5:29 AM, Mi Jinlong wrote:

>
>
> Chuck Lever:
>> Hi MJ-
>>
>> On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:
>>
>>> At RHEL, if user set port for mountd at /etc/services as
>>> "mount 12345/tcp", mountd should be bind to 12345, but the
>>> latest nfs-utils, mountd get a rand port, not 12345.
>>>
>>> This patch make sure mountd be bind to the port which was set
>>> at /etc/service.
>>
>> I don't think this is documented anywhere. Is there a reason it should work this way?
>>
>> The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.
>
> I don't have a depth research, agree with you.
> But I got different result when I set port for mountd at /etc/services
> between nfs-utils-1.2.3 and nfs-utils-1.2.2.

IMO that's unintentional behavior. Could I ask a favor: would you bisect nfs-utils to find out exactly where this started and ended?

> I just think we should get the same result at new nfs-utils as older.

Is there a real-world use case for this feature? Why isn't the command line option adequate?

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com





2011-04-21 03:40:52

by Mi Jinlong

[permalink] [raw]
Subject: Re: [PATCH] svc: make sure mountd can get ports from /etc/services



Chuck Lever:
> On Apr 20, 2011, at 5:29 AM, Mi Jinlong wrote:
>
>>
>> Chuck Lever:
>>> Hi MJ-
>>>
>>> On Apr 19, 2011, at 4:33 AM, Mi Jinlong wrote:
>>>
>>>> At RHEL, if user set port for mountd at /etc/services as
>>>> "mount 12345/tcp", mountd should be bind to 12345, but the
>>>> latest nfs-utils, mountd get a rand port, not 12345.
>>>>
>>>> This patch make sure mountd be bind to the port which was set
>>>> at /etc/service.
>>> I don't think this is documented anywhere. Is there a reason it should work this way?
>>>
>>> The typical way to set mountd's port is to use a command line option. That's the way it works for all the other RPC daemons. By default the ports are set up at random and registered with rpcbind. That's why clients use rpcbind, and not /etc/services, to find these services.
>> I don't have a depth research, agree with you.
>> But I got different result when I set port for mountd at /etc/services
>> between nfs-utils-1.2.3 and nfs-utils-1.2.2.
>
> IMO that's unintentional behavior. Could I ask a favor: would you bisect nfs-utils to find out exactly where this started and ended?

Hi Chuck,

It's after your patch "mountd: Support TI-RPC mountd listener"
(commit id:b551b1fd0052de9b8c674b30c39d9f2a1e9d79cc).

Before this patch, mountd call rpc_init to create rpc socket,
after it, if HAVE_LIBTIRPC is defined, mountd will call
nfs_svc_create to create rpc socket, that appears.

>
>> I just think we should get the same result at new nfs-utils as older.
>
> Is there a real-world use case for this feature? Why isn't the command line option adequate?
>

I have a test site which depend on this feature.
If this feature indeed unnecessary, I will try to modify my test site.

--
----
thanks
Mi Jinlong


2011-05-28 09:39:52

by Mi Jinlong

[permalink] [raw]
Subject: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

At RHEL, if user set port for mountd at /etc/services as
"mount 12345/tcp", mountd should be bind to 12345, but the
latest nfs-utils, mountd get a rand port, not 12345.

This patch make sure mountd be bind to the port which was set
at /etc/service.

Signed-off-by: Mi Jinlong <[email protected]>
---
support/include/rpcmisc.h | 1 +
support/nfs/svc_create.c | 9 ++++-
support/nfs/svc_socket.c | 80 +++++++++++++++++++++------------------------
utils/mountd/mountd.man | 5 ++-
utils/statd/statd.man | 5 ++-
5 files changed, 53 insertions(+), 47 deletions(-)

diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
index 0b06457..b806227 100644
--- a/support/include/rpcmisc.h
+++ b/support/include/rpcmisc.h
@@ -53,6 +53,7 @@ void rpc_init(char *name, int prog, int vers,
void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
struct rpc_dtable *dtable, int nvers,
void *argp, void *resp);
+int getservport(u_long number, const char *proto);

extern int _rpcpmstart;
extern int _rpcfdtype;
diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
index b3f75ed..c159fc8 100644
--- a/support/nfs/svc_create.c
+++ b/support/nfs/svc_create.c
@@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
const struct sigaction create_sigaction = {
.sa_handler = SIG_IGN,
};
- unsigned int visible, up;
+ unsigned int visible, up, servport;
struct netconfig *nconf;
void *handlep;

@@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
visible++;
+ if (port == 0)
+ servport = getservport(program, nconf->nc_proto);
+ else
+ servport = port;
+
up += svc_create_nconf(name, program, version, dispatch,
- port, nconf);
+ servport, nconf);
}

if (visible == 0)
diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
index 03a5325..c252f53 100644
--- a/support/nfs/svc_socket.c
+++ b/support/nfs/svc_socket.c
@@ -35,14 +35,43 @@
# define __close(f) close ((f))
#endif

+int getservport(u_long number, const char *proto)
+{
+ char rpcdata[1024], servdata[1024];
+ struct rpcent rpcbuf, *rpcp;
+ struct servent servbuf, *servp = NULL;
+ int ret;
+
+ ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata,
+ &rpcp);
+ if (ret == 0 && rpcp != NULL) {
+ /* First try name. */
+ ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata,
+ sizeof servdata, &servp);
+ if ((ret != 0 || servp == NULL) && rpcp->r_aliases) {
+ const char **a;
+
+ /* Then we try aliases. */
+ for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) {
+ ret = getservbyname_r(*a, proto, &servbuf, servdata,
+ sizeof servdata, &servp);
+ if (ret == 0 && servp != NULL)
+ break;
+ }
+ }
+ }
+
+ if (ret == 0 && servp != NULL)
+ return ntohs(servp->s_port);
+
+ return 0;
+}
+
static int
svc_socket (u_long number, int type, int protocol, int reuse)
{
struct sockaddr_in addr;
socklen_t len = sizeof (struct sockaddr_in);
- char rpcdata [1024], servdata [1024];
- struct rpcent rpcbuf, *rpcp;
- struct servent servbuf, *servp = NULL;
int sock, ret;
const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";

@@ -66,48 +95,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)

memset (&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
+ addr.sin_port = htons(getservport(number, proto));

- ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
- &rpcp);
- if (ret == 0 && rpcp != NULL)
- {
- /* First try name. */
- ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
- sizeof servdata, &servp);
- if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
- {
- const char **a;
-
- /* Then we try aliases. */
- for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
- {
- ret = getservbyname_r (*a, proto, &servbuf, servdata,
- sizeof servdata, &servp);
- if (ret == 0 && servp != NULL)
- break;
- }
- }
- }
-
- if (ret == 0 && servp != NULL)
+ if (bind(sock, (struct sockaddr *) &addr, len) < 0)
{
- addr.sin_port = servp->s_port;
- if (bind (sock, (struct sockaddr *) &addr, len) < 0)
- {
- perror (_("svc_socket: bind problem"));
- (void) __close (sock);
- sock = -1;
- }
- }
- else
- {
- addr.sin_port = 0;
- if (bind (sock, (struct sockaddr *) &addr, len) < 0)
- {
- perror (_("svc_socket: bind problem"));
- (void) __close (sock);
- sock = -1;
- }
+ perror (_("svc_socket: bind problem"));
+ (void) __close(sock);
+ sock = -1;
}

if (sock >= 0)
diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
index 016a357..b322437 100644
--- a/utils/mountd/mountd.man
+++ b/utils/mountd/mountd.man
@@ -122,7 +122,10 @@ Ignored (compatibility with unfsd??).
Specifies the port number used for RPC listener sockets.
If this option is not specified,
.B rpc.mountd
-chooses a random ephemeral port for each listener socket.
+will try to consult
+.IR /etc/services ,
+if gets port succeed, set the same port for all listener socket,
+otherwise chooses a random ephemeral port for each listener socket.
.IP
This option can be used to fix the port value of
.BR rpc.mountd 's
diff --git a/utils/statd/statd.man b/utils/statd/statd.man
index b72236c..203f8c9 100644
--- a/utils/statd/statd.man
+++ b/utils/statd/statd.man
@@ -219,7 +219,10 @@ for details.
Specifies the port number used for RPC listener sockets.
If this option is not specified,
.B rpc.statd
-chooses a random ephemeral port for each listener socket.
+will try to consult
+.IR /etc/services ,
+if gets port succeed, set the same port for all listener socket,
+otherwise chooses a random ephemeral port for each listener socket.
.IP
This option can be used to fix the port value of its listeners when
SM_NOTIFY requests must traverse a firewall between clients and servers.
--
1.7.5.1




2011-05-28 13:29:56

by Jim Rees

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

Mi Jinlong wrote:

At RHEL, if user set port for mountd at /etc/services as
"mount 12345/tcp", mountd should be bind to 12345, but the
latest nfs-utils, mountd get a rand port, not 12345.

This patch make sure mountd be bind to the port which was set
at /etc/service.

Is this really such a good idea? I would find this behavior surprising. I
expect listeners to either use a well-known port, in which case they look in
/etc/services and fall back to a compiled-in constant (like telnet or ftp),
or use an ephemeral port, in which case they don't even look at
/etc/services. This patch would change mountd so that its behavior
(well-known versus ephemeral) depends on /etc/services rather than a
run-time option.

The change in behavior would not be immediately obvious, either, because who
is going to notice that mountd is now on a well-known port?

You could argue that the admin would have to add a line to /etc/services for
anything to change, and I guess I could be convinced. But are you sure some
distro packaging person isn't going to put that line in without
understanding the implications?

Yes, I know putting mountd on a random port isn't going to thwart a
determined hacker. I'm thinking of the nuisance factor. Consider ssh.
It's a secure protocol, so there isn't really a security risk with leaving
it on port 22, but sometimes you have to move it off to keep the log files
from filling up with crap.

Here's an alternate proposal. Have the "-p" option take either a number or
a name. If it's a name, look it up in /etc/services.

2011-05-28 16:01:24

by Chuck Lever

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

Hi Jim-

On May 28, 2011, at 9:29 AM, Jim Rees wrote:

> Mi Jinlong wrote:
>
> At RHEL, if user set port for mountd at /etc/services as
> "mount 12345/tcp", mountd should be bind to 12345, but the
> latest nfs-utils, mountd get a rand port, not 12345.
>
> This patch make sure mountd be bind to the port which was set
> at /etc/service.
>
> Is this really such a good idea? I would find this behavior surprising.

I also find this behavior surprising. However, this patch fixes a regression. If you build mountd today with the legacy RPC library, it already consults /etc/services, and has done for a long while. Mi is simply restoring this traditional behavior for newer TI-RPC builds.

> I expect listeners to either use a well-known port, in which case they look in
> /etc/services and fall back to a compiled-in constant (like telnet or ftp),
> or use an ephemeral port, in which case they don't even look at
> /etc/services. This patch would change mountd so that its behavior
> (well-known versus ephemeral) depends on /etc/services rather than a
> run-time option.

As I read it: If -p is specified, mountd uses that value for the listener port. Otherwise, if -p is not specified, mountd looks in /etc/services, and uses the port listed there. If there is no "mountd" service listed in /etc/services, it uses an ephemeral port.

For any ONCRPC service other than NFS and rpcbind, there is typically no built-in fixed port. In that sense, the rpc. daemons are not like telnet or ftp. Ephemeral ports are used and registered with rpcbind, so well-known ports are not needed.

> The change in behavior would not be immediately obvious, either, because who
> is going to notice that mountd is now on a well-known port?

A problem certainly arises going the other way: if the port value was fixed in order to transit a firewall, and the port becomes ephemeral, then the problem becomes obvious. This is exactly how mountd is broken today since, when built with TI-RPC, it no longer consults /etc/services and instead it uses an ephemeral port. Admittedly, this is rare.

> You could argue that the admin would have to add a line to /etc/services for
> anything to change, and I guess I could be convinced. But are you sure some
> distro packaging person isn't going to put that line in without
> understanding the implications?

/etc/services does not by default contain an entry for mountd (or statd, which is also affected by this change). Without those entries, the daemons behave exactly as you expect. This is probably why we never noticed mountd looked in /etc/services. That, and this behavior isn't documented anywhere.

Since there is no IANA-listed port number assignment for the legacy mountd or statd services, I doubt /etc/services will be changed by a distro as you suggest. However, distros will change the file to add new well-known ports for other services. Installing a new copy will erase any local changes. This is a good reason to prefer -p instead.

> Yes, I know putting mountd on a random port isn't going to thwart a
> determined hacker. I'm thinking of the nuisance factor. Consider ssh.
> It's a secure protocol, so there isn't really a security risk with leaving
> it on port 22, but sometimes you have to move it off to keep the log files
> from filling up with crap.
>
> Here's an alternate proposal. Have the "-p" option take either a number or
> a name. If it's a name, look it up in /etc/services.

-p should be able to take a name anyway. It would be a simple change.

I personally think -p is sufficient for setting the listener port as needed, and no-one has identified any hard requirement (like ancient HA clustering scripts that everyone uses and no-one wants to change) for having mountd read /etc/services.

I believe /etc/services is a well-known port registry, a local copy of IANA's registry. Because mountd is an RPC service, fixing mountd's port is a local setting, and is not based on any standard. Thus /etc/services is not an appropriate mechanism for setting mountd's listener port value.

So, we could also address this by getting rid of the legacy RPC behavior instead. However, in cases like this, I typically choose to stick with legacy behavior, since that improves backwards compatibility. It already works like this for legacy RPC builds, so in some sense we are stuck with it.

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com




2011-05-28 16:45:05

by Jim Rees

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

Chuck Lever wrote:

So, we could also address this by getting rid of the legacy RPC behavior
instead. However, in cases like this, I typically choose to stick with
legacy behavior, since that improves backwards compatibility. It already
works like this for legacy RPC builds, so in some sense we are stuck with
it.

Ok. I remember the earlier discussion but forgot that the patch simply
restores older behavior that was changed by tirpc. In that case I'll go
along with Mi's patch.

2011-06-07 20:17:11

by Steve Dickson

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

On 05/28/2011 12:45 PM, Jim Rees wrote:
> Chuck Lever wrote:
>
> So, we could also address this by getting rid of the legacy RPC behavior
> instead. However, in cases like this, I typically choose to stick with
> legacy behavior, since that improves backwards compatibility. It already
> works like this for legacy RPC builds, so in some sense we are stuck with
> it.
>
> Ok. I remember the earlier discussion but forgot that the patch simply
> restores older behavior that was changed by tirpc. In that case I'll go
> along with Mi's patch.
I am all for restoring the older behavior, but unfortunately this patch
does not do it.

I when back and took a look at how the nfs-utils-1.2.2 code worked.
While its true both mountd and statd read ports from /etc/service,
they did not fail when those ports were already taken. They just
bound to random ephemeral ports, which is probably the reason none of
us noticed they were reading ports out of /etc/services. With
Mi's patch, both daemons fail when the ports in /etc/service are
already taken.

Mi, unfortunately I am not going to have any cycles to look
at this, due to the upcoming Bakeathon. So, could you please,
look into why the 1.2.2 recovered when ports in /etc/services
were taken and your patch does not.

tia,

steved.


2011-06-10 08:20:53

by Mi Jinlong

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port



Steve Dickson:
> On 05/28/2011 12:45 PM, Jim Rees wrote:
>> Chuck Lever wrote:
>>
>> So, we could also address this by getting rid of the legacy RPC behavior
>> instead. However, in cases like this, I typically choose to stick with
>> legacy behavior, since that improves backwards compatibility. It already
>> works like this for legacy RPC builds, so in some sense we are stuck with
>> it.
>>
>> Ok. I remember the earlier discussion but forgot that the patch simply
>> restores older behavior that was changed by tirpc. In that case I'll go
>> along with Mi's patch.
> I am all for restoring the older behavior, but unfortunately this patch
> does not do it.
>
> I when back and took a look at how the nfs-utils-1.2.2 code worked.
> While its true both mountd and statd read ports from /etc/service,
> they did not fail when those ports were already taken. They just
> bound to random ephemeral ports, which is probably the reason none of
> us noticed they were reading ports out of /etc/services. With
> Mi's patch, both daemons fail when the ports in /etc/service are
> already taken.

Hi steve,

Do you mean the daemons can't run?

I test nfs-utils-1.2.2 at fedora15, mountd can bind to the port
reading form /etc/service.

So, can you post some error or other message here?

thanks,
Mi Jinlong


2011-08-03 17:52:49

by Steve Dickson

[permalink] [raw]
Subject: Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port

Hello Mi,

My apologizes for taking so long on this... It did fall off my radar...
but after some unit testing, it appears things
work as expected....

Committed!

steved.

On 05/28/2011 05:42 AM, Mi Jinlong wrote:
> At RHEL, if user set port for mountd at /etc/services as
> "mount 12345/tcp", mountd should be bind to 12345, but the
> latest nfs-utils, mountd get a rand port, not 12345.
>
> This patch make sure mountd be bind to the port which was set
> at /etc/service.
>
> Signed-off-by: Mi Jinlong <[email protected]>
> ---
> support/include/rpcmisc.h | 1 +
> support/nfs/svc_create.c | 9 ++++-
> support/nfs/svc_socket.c | 80 +++++++++++++++++++++------------------------
> utils/mountd/mountd.man | 5 ++-
> utils/statd/statd.man | 5 ++-
> 5 files changed, 53 insertions(+), 47 deletions(-)
>
> diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h
> index 0b06457..b806227 100644
> --- a/support/include/rpcmisc.h
> +++ b/support/include/rpcmisc.h
> @@ -53,6 +53,7 @@ void rpc_init(char *name, int prog, int vers,
> void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt,
> struct rpc_dtable *dtable, int nvers,
> void *argp, void *resp);
> +int getservport(u_long number, const char *proto);
>
> extern int _rpcpmstart;
> extern int _rpcfdtype;
> diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c
> index b3f75ed..c159fc8 100644
> --- a/support/nfs/svc_create.c
> +++ b/support/nfs/svc_create.c
> @@ -393,7 +393,7 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
> const struct sigaction create_sigaction = {
> .sa_handler = SIG_IGN,
> };
> - unsigned int visible, up;
> + unsigned int visible, up, servport;
> struct netconfig *nconf;
> void *handlep;
>
> @@ -417,8 +417,13 @@ nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version,
> if (!(nconf->nc_flag & NC_VISIBLE))
> continue;
> visible++;
> + if (port == 0)
> + servport = getservport(program, nconf->nc_proto);
> + else
> + servport = port;
> +
> up += svc_create_nconf(name, program, version, dispatch,
> - port, nconf);
> + servport, nconf);
> }
>
> if (visible == 0)
> diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c
> index 03a5325..c252f53 100644
> --- a/support/nfs/svc_socket.c
> +++ b/support/nfs/svc_socket.c
> @@ -35,14 +35,43 @@
> # define __close(f) close ((f))
> #endif
>
> +int getservport(u_long number, const char *proto)
> +{
> + char rpcdata[1024], servdata[1024];
> + struct rpcent rpcbuf, *rpcp;
> + struct servent servbuf, *servp = NULL;
> + int ret;
> +
> + ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata,
> + &rpcp);
> + if (ret == 0 && rpcp != NULL) {
> + /* First try name. */
> + ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata,
> + sizeof servdata, &servp);
> + if ((ret != 0 || servp == NULL) && rpcp->r_aliases) {
> + const char **a;
> +
> + /* Then we try aliases. */
> + for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) {
> + ret = getservbyname_r(*a, proto, &servbuf, servdata,
> + sizeof servdata, &servp);
> + if (ret == 0 && servp != NULL)
> + break;
> + }
> + }
> + }
> +
> + if (ret == 0 && servp != NULL)
> + return ntohs(servp->s_port);
> +
> + return 0;
> +}
> +
> static int
> svc_socket (u_long number, int type, int protocol, int reuse)
> {
> struct sockaddr_in addr;
> socklen_t len = sizeof (struct sockaddr_in);
> - char rpcdata [1024], servdata [1024];
> - struct rpcent rpcbuf, *rpcp;
> - struct servent servbuf, *servp = NULL;
> int sock, ret;
> const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp";
>
> @@ -66,48 +95,13 @@ svc_socket (u_long number, int type, int protocol, int reuse)
>
> memset (&addr, 0, sizeof (addr));
> addr.sin_family = AF_INET;
> + addr.sin_port = htons(getservport(number, proto));
>
> - ret = getrpcbynumber_r (number, &rpcbuf, rpcdata, sizeof rpcdata,
> - &rpcp);
> - if (ret == 0 && rpcp != NULL)
> - {
> - /* First try name. */
> - ret = getservbyname_r (rpcp->r_name, proto, &servbuf, servdata,
> - sizeof servdata, &servp);
> - if ((ret != 0 || servp == NULL) && rpcp->r_aliases)
> - {
> - const char **a;
> -
> - /* Then we try aliases. */
> - for (a = (const char **) rpcp->r_aliases; *a != NULL; a++)
> - {
> - ret = getservbyname_r (*a, proto, &servbuf, servdata,
> - sizeof servdata, &servp);
> - if (ret == 0 && servp != NULL)
> - break;
> - }
> - }
> - }
> -
> - if (ret == 0 && servp != NULL)
> + if (bind(sock, (struct sockaddr *) &addr, len) < 0)
> {
> - addr.sin_port = servp->s_port;
> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
> - {
> - perror (_("svc_socket: bind problem"));
> - (void) __close (sock);
> - sock = -1;
> - }
> - }
> - else
> - {
> - addr.sin_port = 0;
> - if (bind (sock, (struct sockaddr *) &addr, len) < 0)
> - {
> - perror (_("svc_socket: bind problem"));
> - (void) __close (sock);
> - sock = -1;
> - }
> + perror (_("svc_socket: bind problem"));
> + (void) __close(sock);
> + sock = -1;
> }
>
> if (sock >= 0)
> diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man
> index 016a357..b322437 100644
> --- a/utils/mountd/mountd.man
> +++ b/utils/mountd/mountd.man
> @@ -122,7 +122,10 @@ Ignored (compatibility with unfsd??).
> Specifies the port number used for RPC listener sockets.
> If this option is not specified,
> .B rpc.mountd
> -chooses a random ephemeral port for each listener socket.
> +will try to consult
> +.IR /etc/services ,
> +if gets port succeed, set the same port for all listener socket,
> +otherwise chooses a random ephemeral port for each listener socket.
> .IP
> This option can be used to fix the port value of
> .BR rpc.mountd 's
> diff --git a/utils/statd/statd.man b/utils/statd/statd.man
> index b72236c..203f8c9 100644
> --- a/utils/statd/statd.man
> +++ b/utils/statd/statd.man
> @@ -219,7 +219,10 @@ for details.
> Specifies the port number used for RPC listener sockets.
> If this option is not specified,
> .B rpc.statd
> -chooses a random ephemeral port for each listener socket.
> +will try to consult
> +.IR /etc/services ,
> +if gets port succeed, set the same port for all listener socket,
> +otherwise chooses a random ephemeral port for each listener socket.
> .IP
> This option can be used to fix the port value of its listeners when
> SM_NOTIFY requests must traverse a firewall between clients and servers.