コード例 #1
0
ファイル: network.c プロジェクト: AllardJ/Tomato
/*
 * Use the portmapper to discover whether or not the service we want is
 * available. The lists 'versions' and 'protos' define ordered sequences
 * of service versions and udp/tcp protocols to probe for.
 *
 * Returns 1 if the requested service port is unambiguous and pingable;
 * @pmap is filled in with the version, port, and transport protocol used
 * during the successful ping.  Note that if a port is already specified
 * in @pmap and it matches the rpcbind query result, nfs_probe_port() does
 * not perform an RPC ping.
 * 
 * If an error occurs or the requested service isn't available, zero is
 * returned; rpccreateerr.cf_stat is set to reflect the nature of the error.
 */
static int nfs_probe_port(const struct sockaddr *sap, const socklen_t salen,
			  struct pmap *pmap, const unsigned long *versions,
			  const unsigned int *protos)
{
	struct sockaddr_storage address;
	struct sockaddr *saddr = (struct sockaddr *)&address;
	const unsigned long prog = pmap->pm_prog, *p_vers;
	const unsigned int prot = (u_int)pmap->pm_prot, *p_prot;
	const u_short port = (u_short) pmap->pm_port;
	unsigned long vers = pmap->pm_vers;
	unsigned short p_port;

	memcpy(saddr, sap, salen);
	p_prot = prot ? &prot : protos;
	p_vers = vers ? &vers : versions;
	rpc_createerr.cf_stat = 0;

	for (;;) {
		p_port = nfs_getport(saddr, salen, prog, *p_vers, *p_prot);
		if (p_port) {
			if (!port || port == p_port) {
				nfs_set_port(saddr, p_port);
				nfs_pp_debug(saddr, salen, prog, *p_vers,
						*p_prot, p_port);
				if (nfs_rpc_ping(saddr, salen, prog,
							*p_vers, *p_prot, NULL))
					goto out_ok;
			}
		}
		if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
		    rpc_createerr.cf_stat != RPC_TIMEDOUT &&
		    rpc_createerr.cf_stat != RPC_CANTRECV &&
		    rpc_createerr.cf_stat != RPC_PROGVERSMISMATCH)
			goto out_bad;

		if (!prot) {
			if (*++p_prot)
				continue;
			p_prot = protos;
		}
		if (rpc_createerr.cf_stat == RPC_TIMEDOUT ||
		    rpc_createerr.cf_stat == RPC_CANTRECV)
			goto out_bad;

		if (vers || !*++p_vers)
			break;
	}

out_bad:
	return 0;

out_ok:
	if (!vers)
		pmap->pm_vers = *p_vers;
	if (!prot)
		pmap->pm_prot = *p_prot;
	if (!port)
		pmap->pm_port = p_port;
	rpc_createerr.cf_stat = 0;
	return 1;
}
コード例 #2
0
ファイル: gssd_proc.c プロジェクト: Distrotech/nfs-utils
/*
 * If the port isn't already set, do an rpcbind query to the remote server
 * using the program and version and get the port.
 *
 * Newer kernels send the value of the port= mount option in the "info"
 * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
 * of the port= option or '2049'. The port field in a new sockaddr should
 * reflect the value that was sent by the kernel.
 */
static int
populate_port(struct sockaddr *sa, const socklen_t salen,
	      const rpcprog_t program, const rpcvers_t version,
	      const unsigned short protocol)
{
	struct sockaddr_in	*s4 = (struct sockaddr_in *) sa;
#ifdef IPV6_SUPPORTED
	struct sockaddr_in6	*s6 = (struct sockaddr_in6 *) sa;
#endif /* IPV6_SUPPORTED */
	unsigned short		port;

	/*
	 * Newer kernels send the port in the upcall. If we already have
	 * the port, there's no need to look it up.
	 */
	switch (sa->sa_family) {
	case AF_INET:
		if (s4->sin_port != 0) {
			printerr(4, "DEBUG: port already set to %d\n",
				 ntohs(s4->sin_port));
			return 1;
		}
		break;
#ifdef IPV6_SUPPORTED
	case AF_INET6:
		if (s6->sin6_port != 0) {
			printerr(4, "DEBUG: port already set to %d\n",
				 ntohs(s6->sin6_port));
			return 1;
		}
		break;
#endif /* IPV6_SUPPORTED */
	default:
		printerr(0, "ERROR: unsupported address family %d\n",
			    sa->sa_family);
		return 0;
	}

	/*
	 * Newer kernels that send the port in the upcall set the value to
	 * 2049 for NFSv4 mounts when one isn't specified. The check below is
	 * only for kernels that don't send the port in the upcall. For those
	 * we either have to do an rpcbind query or set it to the standard
	 * port. Doing a query could be problematic (firewalls, etc), so take
	 * the latter approach.
	 */
	if (program == 100003 && version == 4) {
		port = 2049;
		goto set_port;
	}

	port = nfs_getport(sa, salen, program, version, protocol);
	if (!port) {
		printerr(0, "ERROR: unable to obtain port for prog %ld "
			    "vers %ld\n", program, version);
		return 0;
	}

set_port:
	printerr(2, "DEBUG: setting port to %hu for prog %lu vers %lu\n", port,
		 program, version);

	switch (sa->sa_family) {
	case AF_INET:
		s4->sin_port = htons(port);
		break;
#ifdef IPV6_SUPPORTED
	case AF_INET6:
		s6->sin6_port = htons(port);
		break;
#endif /* IPV6_SUPPORTED */
	}

	return 1;
}