enum {
RPCBPROC_NULL,
RPCBPROC_SET,
RPCBPROC_UNSET,
RPCBPROC_GETPORT,
RPCBPROC_GETADDR = 3, /* alias for GETPORT */
RPCBPROC_DUMP,
RPCBPROC_CALLIT,
RPCBPROC_BCAST = 5, /* alias for CALLIT */
RPCBPROC_GETTIME,
RPCBPROC_UADDR2TADDR,
RPCBPROC_TADDR2UADDR,
RPCBPROC_GETVERSADDR,
RPCBPROC_INDIRECT,
RPCBPROC_GETADDRLIST,
RPCBPROC_GETSTAT,
};
/* * r_owner * * The "owner" is allowed to unset a service in the rpcbind database. * * For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a * UID which it maps to a local user name via a password lookup. * In all other cases it is ignored. * * For SET/UNSET requests, user space provides a value, even for * network requests, and GETADDR uses an empty string. We follow * those precedents here.
*/ #define RPCB_OWNER_STRING "0" #define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
/* * Note that RFC 1833 does not put any size restrictions on the * address string returned by the remote rpcbind database.
*/ #define RPCB_getaddrres_sz RPCB_addr_sz
/* Evaluate to actual length of the `sockaddr_un' structure. */ # define SUN_LEN(ptr) (offsetof(struct sockaddr_un, sun_path) \
+ 1 + strlen((ptr)->sun_path + 1))
/* * Returns zero on success, otherwise a negative errno value * is returned.
*/ staticint rpcb_create_af_local(struct net *net, conststruct sockaddr_un *addr)
{ struct rpc_create_args args = {
.net = net,
.protocol = XPRT_TRANSPORT_LOCAL,
.address = (struct sockaddr *)addr,
.addrsize = SUN_LEN(addr),
.servername = "localhost",
.program = &rpcb_program,
.version = RPCBVERS_2,
.authflavor = RPC_AUTH_NULL,
.cred = current_cred(), /* * We turn off the idle timeout to prevent the kernel * from automatically disconnecting the socket. * Otherwise, we'd have to cache the mount namespace * of the caller and somehow pass that to the socket * reconnect code.
*/
.flags = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT,
}; struct rpc_clnt *clnt, *clnt4; int result = 0;
/* * Because we requested an RPC PING at transport creation time, * this works only if the user space portmapper is rpcbind, and * it's listening on AF_LOCAL on the named socket.
*/
clnt = rpc_create(&args); if (IS_ERR(clnt)) {
result = PTR_ERR(clnt); goto out;
}
clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); if (IS_ERR(clnt4))
clnt4 = NULL;
clnt = rpc_create(&args); if (IS_ERR(clnt)) {
result = PTR_ERR(clnt); goto out;
}
/* * This results in an RPC ping. On systems running portmapper, * the v4 ping will fail. Proceed anyway, but disallow rpcb * v4 upcalls.
*/
clnt4 = rpc_bind_new_program(clnt, &rpcb_program, RPCBVERS_4); if (IS_ERR(clnt4))
clnt4 = NULL;
rpcb_set_local(net, clnt, clnt4, false);
out: return result;
}
/* * Returns zero on success, otherwise a negative errno value * is returned.
*/ int rpcb_create_local(struct net *net)
{ static DEFINE_MUTEX(rpcb_create_local_mutex); int result = 0;
if (rpcb_get_local(net)) return result;
mutex_lock(&rpcb_create_local_mutex); if (rpcb_get_local(net)) goto out;
if (rpcb_create_local_abstract(net) != 0 &&
rpcb_create_local_unix(net) != 0)
result = rpcb_create_local_net(net);
/** * rpcb_register - set or unset a port registration with the local rpcbind svc * @net: target network namespace * @prog: RPC program number to bind * @vers: RPC version number to bind * @prot: transport protocol to register * @port: port value to register * * Returns zero if the registration request was dispatched successfully * and the rpcbind daemon returned success. Otherwise, returns an errno * value that reflects the nature of the error (request could not be * dispatched, timed out, or rpcbind returned an error). * * RPC services invoke this function to advertise their contact * information via the system's rpcbind daemon. RPC services * invoke this function once for each [program, version, transport] * tuple they wish to advertise. * * Callers may also unregister RPC services that are no longer * available by setting the passed-in port to zero. This removes * all registered transports for [program, version] from the local * rpcbind database. * * This function uses rpcbind protocol version 2 to contact the * local rpcbind daemon. * * Registration works over both AF_INET and AF_INET6, and services * registered via this function are advertised as available for any * address. If the local rpcbind daemon is listening on AF_INET6, * services registered via this function will be advertised on * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 * addresses).
*/ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsignedshort port)
{ struct rpcbind_args map = {
.r_prog = prog,
.r_vers = vers,
.r_prot = prot,
.r_port = port,
}; struct rpc_message msg = {
.rpc_argp = &map,
}; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); bool is_set = false;
/** * rpcb_v4_register - set or unset a port registration with the local rpcbind * @net: target network namespace * @program: RPC program number of service to (un)register * @version: RPC version number of service to (un)register * @address: address family, IP address, and port to (un)register * @netid: netid of transport protocol to (un)register * * Returns zero if the registration request was dispatched successfully * and the rpcbind daemon returned success. Otherwise, returns an errno * value that reflects the nature of the error (request could not be * dispatched, timed out, or rpcbind returned an error). * * RPC services invoke this function to advertise their contact * information via the system's rpcbind daemon. RPC services * invoke this function once for each [program, version, address, * netid] tuple they wish to advertise. * * Callers may also unregister RPC services that are registered at a * specific address by setting the port number in @address to zero. * They may unregister all registered protocol families at once for * a service by passing a NULL @address argument. If @netid is "" * then all netids for [program, version, address] are unregistered. * * This function uses rpcbind protocol version 4 to contact the * local rpcbind daemon. The local rpcbind daemon must support * version 4 of the rpcbind protocol in order for these functions * to register a service successfully. * * Supported netids include "udp" and "tcp" for UDP and TCP over * IPv4, and "udp6" and "tcp6" for UDP and TCP over IPv6, * respectively. * * The contents of @address determine the address family and the * port to be registered. The usual practice is to pass INADDR_ANY * as the raw address, but specifying a non-zero address is also * supported by this API if the caller wishes to advertise an RPC * service on a specific network interface. * * Note that passing in INADDR_ANY does not create the same service * registration as IN6ADDR_ANY. The former advertises an RPC * service on any IPv4 address, but not on IPv6. The latter * advertises the service on all IPv4 and IPv6 addresses.
*/ int rpcb_v4_register(struct net *net, const u32 program, const u32 version, conststruct sockaddr *address, constchar *netid)
{ struct rpcbind_args map = {
.r_prog = program,
.r_vers = version,
.r_netid = netid,
.r_owner = RPCB_OWNER_STRING,
}; struct rpc_message msg = {
.rpc_argp = &map,
}; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
if (sn->rpcb_local_clnt4 == NULL) return -EPROTONOSUPPORT;
if (address == NULL) return rpcb_unregister_all_protofamilies(sn, &msg);
/* * In the case where rpc clients have been cloned, we want to make * sure that we use the program number/version etc of the actual * owner of the xprt. To do so, we walk back up the tree of parents * to find whoever created the transport and/or whoever has the * autobind flag set.
*/ staticstruct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
{ struct rpc_clnt *parent = clnt->cl_parent; struct rpc_xprt_switch *xps = rcu_access_pointer(clnt->cl_xpi.xpi_xpswitch);
while (parent != clnt) { if (rcu_access_pointer(parent->cl_xpi.xpi_xpswitch) != xps) break; if (clnt->cl_autobind) break;
clnt = parent;
parent = parent->cl_parent;
} return clnt;
}
/** * rpcb_getport_async - obtain the port for a given RPC service on a given host * @task: task that is waiting for portmapper request * * This one can be called for an ongoing RPC request, and can be used in * an async (rpciod) context.
*/ void rpcb_getport_async(struct rpc_task *task)
{ struct rpc_clnt *clnt; conststruct rpc_procinfo *proc;
u32 bind_version; struct rpc_xprt *xprt; struct rpc_clnt *rpcb_clnt; struct rpcbind_args *map; struct rpc_task *child; struct sockaddr_storage addr; struct sockaddr *sap = (struct sockaddr *)&addr;
size_t salen; int status;
/* Put self on the wait queue to ensure we get notified if
* some other task is already attempting to bind the port */
rpc_sleep_on_timeout(&xprt->binding, task,
NULL, jiffies + xprt->bind_timeout);
if (xprt_test_and_set_binding(xprt)) {
xprt_put(xprt); return;
}
/* Someone else may have bound if we slept */ if (xprt_bound(xprt)) {
status = 0; goto bailout_nofree;
}
len = strlen(string);
WARN_ON_ONCE(len > maxstrlen); if (len > maxstrlen) /* truncate and hope for the best */
len = maxstrlen;
p = xdr_reserve_space(xdr, 4 + len);
xdr_encode_opaque(p, string, len);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.