diff options
author | Gordon Ross <gwr@nexenta.com> | 2016-12-18 18:24:35 -0500 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2017-07-20 21:54:31 -0400 |
commit | dec98d2aa2912b1fbd0abd2574307a695b566692 (patch) | |
tree | a171c296b3e5cd7563a0f82f4d7bad7c42ff4cc5 /usr/src/lib | |
parent | 6e270ca825f06ec0e2d77db462b83074ec585f2f (diff) | |
download | illumos-joyent-dec98d2aa2912b1fbd0abd2574307a695b566692.tar.gz |
8330 Add svc_tp_create_addr to libnsl
Reviewed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Approved by: Prakash Surya <prakash.surya@delphix.com>
Diffstat (limited to 'usr/src/lib')
-rw-r--r-- | usr/src/lib/libnsl/common/mapfile-vers | 7 | ||||
-rw-r--r-- | usr/src/lib/libnsl/rpc/svc_generic.c | 127 |
2 files changed, 103 insertions, 31 deletions
diff --git a/usr/src/lib/libnsl/common/mapfile-vers b/usr/src/lib/libnsl/common/mapfile-vers index 3f31af2f5e..9a0b25a16b 100644 --- a/usr/src/lib/libnsl/common/mapfile-vers +++ b/usr/src/lib/libnsl/common/mapfile-vers @@ -20,7 +20,7 @@ # # # Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2014 Nexenta Systems, Inc. All rights reserved. +# Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # @@ -39,6 +39,11 @@ $mapfile_version 2 +SYMBOL_VERSION ILLUMOS_0.1 { # Illumos additions + global: + svc_tp_create_addr; +} SUNW_1.10; + SYMBOL_VERSION SUNW_1.10 { # SunOS 5.11 (Solaris 11) global: SUNW_1.10; diff --git a/usr/src/lib/libnsl/rpc/svc_generic.c b/usr/src/lib/libnsl/rpc/svc_generic.c index ca9322b45d..3b5bb2b4bf 100644 --- a/usr/src/lib/libnsl/rpc/svc_generic.c +++ b/usr/src/lib/libnsl/rpc/svc_generic.c @@ -20,8 +20,8 @@ */ /* + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ /* Copyright (c) 1988 AT&T */ @@ -87,6 +87,10 @@ extern mutex_t xprtlist_lock; static SVCXPRT * svc_tli_create_common(int, const struct netconfig *, const struct t_bind *, uint_t, uint_t, boolean_t); +static SVCXPRT *svc_tp_create_bind(void (*dispatch)(), + const rpcprog_t, const rpcvers_t, + const struct netconfig *, const struct t_bind *); + boolean_t is_multilevel(rpcprog_t prognum) { @@ -176,11 +180,50 @@ svc_create(void (*dispatch)(), const rpcprog_t prognum, const rpcvers_t versnum, /* * The high level interface to svc_tli_create(). * It tries to create a server for "nconf" and registers the service - * with the rpcbind. It calls svc_tli_create(); + * with the rpcbind. */ SVCXPRT * svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, - const rpcvers_t versnum, const struct netconfig *nconf) + const rpcvers_t versnum, const struct netconfig *nconf) +{ + return (svc_tp_create_bind(dispatch, prognum, versnum, nconf, NULL)); +} + +/* + * svc_tp_create_addr() + * Variant of svc_tp_create() that allows specifying just the + * the binding address, for convenience. + */ +SVCXPRT * +svc_tp_create_addr(void (*dispatch)(), const rpcprog_t prognum, + const rpcvers_t versnum, const struct netconfig *nconf, + const struct netbuf *addr) +{ + struct t_bind bind; + struct t_bind *bindp = NULL; + + if (addr != NULL) { + + bind.addr = *addr; + if (!rpc_control(__RPC_SVC_LSTNBKLOG_GET, &bind.qlen)) { + syslog(LOG_ERR, + "svc_tp_create: can't get listen backlog"); + return (NULL); + } + bindp = &bind; + } + + /* + * When bindp == NULL, this is the same as svc_tp_create(). + */ + return (svc_tp_create_bind(dispatch, prognum, versnum, + nconf, bindp)); +} + +static SVCXPRT * +svc_tp_create_bind(void (*dispatch)(), const rpcprog_t prognum, + const rpcvers_t versnum, const struct netconfig *nconf, + const struct t_bind *bindaddr) { SVCXPRT *xprt; boolean_t anon_mlp = B_FALSE; @@ -194,7 +237,8 @@ svc_tp_create(void (*dispatch)(), const rpcprog_t prognum, /* Some programs need to allocate MLP for multilevel services */ if (is_system_labeled() && is_multilevel(prognum)) anon_mlp = B_TRUE; - xprt = svc_tli_create_common(RPC_ANYFD, nconf, NULL, 0, 0, anon_mlp); + xprt = svc_tli_create_common(RPC_ANYFD, nconf, bindaddr, 0, 0, + anon_mlp); if (xprt == NULL) return (NULL); @@ -324,7 +368,6 @@ svc_tli_create_common(const int ofd, const struct netconfig *nconf, } switch (state) { - bool_t tcp, exclbind; case T_UNBND: /* If this is a labeled system, then ask for an MLP */ if (is_system_labeled() && @@ -337,32 +380,15 @@ svc_tli_create_common(const int ofd, const struct netconfig *nconf, SO_ANON_MLP, 1); } - /* - * SO_EXCLBIND has the following properties - * - an fd bound to port P via IPv4 will prevent an IPv6 - * bind to port P (and vice versa) - * - an fd bound to a wildcard IP address for port P will - * prevent a more specific IP address bind to port P - * (see {tcp,udp}.c for details) - * - * We use the latter property to prevent hijacking of RPC - * services that reside at non-privileged ports. - */ - tcp = nconf ? (strcmp(nconf->nc_proto, NC_TCP) == 0) : 0; - if (nconf && - (tcp || (strcmp(nconf->nc_proto, NC_UDP) == 0)) && - rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind)) { - if (exclbind) { - if (__rpc_tli_set_options(fd, SOL_SOCKET, - SO_EXCLBIND, 1) < 0) { - syslog(LOG_ERR, - "svc_tli_create: can't set EXCLBIND [netid='%s']", - nconf->nc_netid); - goto freedata; - } - } - } if (bindaddr) { + /* + * Services that specify a bind address typically + * use a fixed service (IP port) so we need to set + * SO_REUSEADDR to prevent bind errors on restart. + */ + if (bindaddr->addr.len != 0) + (void) __rpc_tli_set_options(fd, SOL_SOCKET, + SO_REUSEADDR, 1); if (t_bind(fd, (struct t_bind *)bindaddr, tres) == -1) { char errorstr[100]; @@ -405,6 +431,47 @@ svc_tli_create_common(const int ofd, const struct netconfig *nconf, } } + /* + * If requested, set SO_EXCLBIND on each binding. + * + * SO_EXCLBIND has the following properties + * - an fd bound to port P via IPv4 will prevent an IPv6 + * bind to port P (and vice versa) + * - an fd bound to a wildcard IP address for port P will + * prevent a more specific IP address bind to port P + * (see {tcp,udp}.c for details) + * + * We use the latter property to prevent hijacking of RPC + * services that reside at non-privileged ports. + * + * When the bind address is not specified, each bind gets a + * new port number, and (for IP transports) we should set + * the exclusive flag after every IP bind. That's the + * strcmp nc_proto part of the expression below. + * + * When the bind address IS specified, we need to set the + * exclusive flag only after we've bound both IPv6+IPv4, + * or the IPv4 bind will fail. Setting the exclusive flag + * after the "tcp" or "udp" transport bind does that. + * That's the strcmp nc_netid part below. + */ + if (nconf != NULL && ((bindaddr == NULL && + (strcmp(nconf->nc_proto, NC_TCP) == 0 || + strcmp(nconf->nc_proto, NC_UDP) == 0)) || + (strcmp(nconf->nc_netid, "tcp") == 0 || + strcmp(nconf->nc_netid, "udp") == 0))) { + bool_t exclbind = FALSE; + (void) rpc_control(__RPC_SVC_EXCLBIND_GET, &exclbind); + if (exclbind && + __rpc_tli_set_options(fd, SOL_SOCKET, + SO_EXCLBIND, 1) < 0) { + syslog(LOG_ERR, + "svc_tli_create: can't set EXCLBIND [netid='%s']", + nconf->nc_netid); + goto freedata; + } + } + /* Enable options of returning the ip's for udp */ if (nconf) { int ret = 0; |