svc: make sure mountd can get ports from /etc/services
Subsystems (2)
PATCH 1/1 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.
--- support/include/rpcmisc.h | 1 + support/nfs/svc_create.c | 9 ++++- support/nfs/svc_socket.c | 83 +++++++++++++++++++++----------------------- 3 files changed, 48 insertions(+), 45 deletions(-)
support/include/rpcmisc.h +1 -0
@@ -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;
support/nfs/svc_create.c +7 -2
@@ -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 )
support/nfs/svc_socket.c +40 -43
102 lines not on this page · raw message
Signature · 1 line
1.7.4.1
Hi MJ-
Quoted 6 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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.
Quoted 160 lines
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(-)support/include/rpcmisc.h +1
-0@@ -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;support/nfs/svc_create.c +7
-2@@ -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 )support/nfs/svc_socket.c +35
-0@@ -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_longnumber, int type, int protocol, int reuse) {
structsockaddr_inaddr;
socklen_tlen = sizeof (structsockaddr_in);support/nfs/svc_socket.c +5
-43-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 )Signature · 1 line
1.7.4.1
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
Chuck Lever:
Quoted 8 lines
Hi MJ-
Quoted 4 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"mount 12345/tcp", mountd should be bind to 12345, but the
latest nfs-utils, mountd get a rand port, not 12345.
Quoted 6 lines
Quoted 2 lines
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.
Signature · 3 lines
---- thanks Mi Jinlong
Quoted 162 lines
Quoted 161 lines
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(-)support/include/rpcmisc.h +1
-0@@ -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;support/nfs/svc_create.c +7
-2@@ -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 )support/nfs/svc_socket.c +35
-0@@ -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_longnumber, int type, int protocol, int reuse) {
structsockaddr_inaddr;
socklen_tlen = sizeof (structsockaddr_in);support/nfs/svc_socket.c +5
-43-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 )Signature · 1 line
1.7.4.1
Quoted 14 lines · Mi Jinlong
Chuck Lever:
Quoted 11 lines
Hi MJ-
Quoted 6 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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.
Quoted 7 lines
Quoted 3 lines
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/servicesbetween 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?
Quoted 1 line
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?
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
Chuck Lever:
Quoted 14 lines · Mi Jinlong
Quoted 13 lines
Chuck Lever:
Quoted 10 lines
Hi MJ-
Quoted 6 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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.
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
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/servicesbetween 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.
Quoted 5 lines
Quoted 2 lines
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.
Signature · 3 lines
---- thanks Mi Jinlong
Quoted 26 lines · Mi Jinlong
Chuck Lever:
Quoted 14 lines · Mi Jinlong
Quoted 13 lines
Chuck Lever:
Quoted 10 lines
Hi MJ-
Quoted 6 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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.Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
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/servicesbetween 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?
Quoted 8 lines
Hi Chuck,
It's after your patch "mountd: Support TI-RPC mountd listener" (commit id:b551b1fd0052de9b8c674b30c39d9f2a1e9d79cc).
Before this patch, mountd call
rpc_initto create rpc socket, after it, ifHAVE_LIBTIRPCis defined, mountd will callnfs_svc_createto 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.
Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
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?
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
Chuck Lever :
Quoted 26 lines · Mi Jinlong
Quoted 25 lines
Chuck Lever:
Quoted 13 lines · Mi Jinlong
Quoted 12 lines
Chuck Lever:
Quoted 10 lines
Hi MJ-
Quoted 6 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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.Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
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/servicesbetween 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,
Quoted 9 lines
Quoted 6 lines
It's after your patch "mountd: Support TI-RPC mountd listener" (commit id:b551b1fd0052de9b8c674b30c39d9f2a1e9d79cc).
Before this patch, mountd call
rpc_initto create rpc socket, after it, ifHAVE_LIBTIRPCis defined, mountd will callnfs_svc_createto 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() ***Quoted 4 lines
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 ofnfs_svc_create(). Ifnfs_svc_create()is indeed the proximal cause of this behavior, mountd won't consult/etc/servicesif 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.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
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!
Quoted 2 lines
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/servicesto 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.
Signature · 3 lines
---- thanks Mi Jinlong
Quoted 6 lines · Mi Jinlong
Chuck Lever :
Quoted 1 line
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/servicesto 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.
Signature · 2 lines
Chuck Lever chuck[dot]lever[at]oracle[dot]com
PATCH v2 1/1 rpc.mountd: let mountd consult /etc/services for port
In reply to Mi JinlongAt 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.
--- 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(-)
support/include/rpcmisc.h +1 -0
@@ -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;
support/nfs/svc_create.c +7 -2
@@ -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 )
support/nfs/svc_socket.c +37 -43
99 lines not on this page · raw message
utils/mountd/mountd.man +4 -1
@@ -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
utils/statd/statd.man +4 -1
@@ -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.
Signature · 1 line
1.7.5.1
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.
Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port
Hi Jim-
Quoted 10 lines · Jim Rees
Mi Jinlong wrote:
At RHEL, if user set port for mountd at
/etc/servicesas
"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.
Quoted 6 lines
I expect listeners to either use a well-known port, in which case they look in
/etc/servicesand 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/servicesrather 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.
Quoted 2 lines
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.
Quoted 4 lines
You could argue that the admin would have to add a line to
/etc/servicesfor 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.
Quoted 8 lines
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
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.
Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port
Quoted 11 lines · Jim Rees
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.
Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port
Steve Dickson:
Quoted 15 lines · Jim Rees
Quoted 11 lines
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.
Quoted 7 lines
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/serviceare 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
Re: [PATCH v2] rpc.mountd: let mountd consult /etc/services for port
In reply to Mi JinlongHello 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.
Quoted 193 lines · Mi Jinlong
At RHEL, if user set port for mountd at
/etc/servicesas
"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(-)support/include/rpcmisc.h +1
-0@@ -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;support/nfs/svc_create.c +7
-2@@ -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 )support/nfs/svc_socket.c +37
-43@@ -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 )utils/mountd/mountd.man +4
-1@@ -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 'sutils/statd/statd.man +4
-1@@ -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.