Esempio n. 1
0
static int
linux_socket(struct proc *p, struct linux_socket_args *args, int *retval)
{
    struct linux_socket_args linux_args;
    struct socket_args /* {
	int domain;
	int type;
	int protocol;
    } */ bsd_args;
    int error;
    int retval_socket;

    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
	return error;
    bsd_args.protocol = linux_args.protocol;
    bsd_args.type = linux_args.type;
    bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
    if (bsd_args.domain == -1)
	return EINVAL;

    retval_socket = socket(p, &bsd_args, retval);

    if (retval_socket >= 0
	&& bsd_args.type == SOCK_RAW
	&& bsd_args.domain == AF_INET
	&& (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)) {
	/* It's a raw IP socket: set the IP_HDRINCL option. */
	struct setsockopt_args /* {
	    int s;
	    int level;
	    int name;
	    caddr_t val;
	    int valsize;
	} */ bsd_setsockopt_args;

	int retval_setsockopt, r;
	caddr_t sg;
//, hdrincl;
//	int hdrinclval = 1;
	int *hdrincl;

	sg = stackgap_init();
	hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
	*hdrincl = 1;

	bsd_setsockopt_args.s = *retval;
	bsd_setsockopt_args.level = IPPROTO_IP;
	bsd_setsockopt_args.name = IP_HDRINCL;
	bsd_setsockopt_args.val = (caddr_t)hdrincl;
	bsd_setsockopt_args.valsize = sizeof(*hdrincl);
	r = setsockopt(p, &bsd_setsockopt_args, &retval_setsockopt);
    }
    return retval_socket;
}
Esempio n. 2
0
static int
linux_socketpair(struct linux_socketpair_args *args, int *res)
{
	struct linux_socketpair_args linux_args;
	int error, domain, sockv[2];

	error = copyin(args, &linux_args, sizeof(linux_args));
	if (error)
		return (error);

	domain = linux_to_bsd_domain(linux_args.domain);
	if (domain == -1)
		return (EINVAL);
	error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
	    sockv);

	if (error == 0)
		error = copyout(sockv, linux_args.rsv, sizeof(sockv));
	return(error);
}
Esempio n. 3
0
static int
linux_socketpair(struct proc *p, struct linux_socketpair_args *args, int *retval)
{
    struct linux_socketpair_args linux_args;
    struct socketpair_args /* {
	int domain;
	int type;
	int protocol;
	int *rsv;
    } */ bsd_args;
    int error;

    if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args))))
	return error;
    bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
    if (bsd_args.domain == -1)
	return EINVAL;
    bsd_args.type = linux_args.type;
    bsd_args.protocol = linux_args.protocol;
    bsd_args.rsv = linux_args.rsv;
    return socketpair(p, &bsd_args, retval);
}
Esempio n. 4
0
static int
linux_socket(struct linux_socket_args *args, int *res)
{
	struct linux_socket_args linux_args;
	struct sockopt sopt;
	int error, domain, optval;

	error = copyin(args, &linux_args, sizeof(linux_args));
	if (error)
		return (error);

	domain = linux_to_bsd_domain(linux_args.domain);
	if (domain == -1)
		return (EINVAL);

	error = kern_socket(domain, linux_args.type, linux_args.protocol, res);

	/* Copy back the return value from socket() */
	if (error == 0 && linux_args.type == SOCK_RAW &&
	    (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
	    linux_args.domain == AF_INET) {
		/* It's a raw IP socket: set the IP_HDRINCL option. */
		optval = 1;
		sopt.sopt_dir = SOPT_SET;
		sopt.sopt_level = IPPROTO_IP;
		sopt.sopt_name = IP_HDRINCL;
		sopt.sopt_val = &optval;
		sopt.sopt_valsize = sizeof(optval);
		sopt.sopt_td = NULL;

		/* We ignore any error returned by setsockopt() */
		kern_setsockopt(*res, &sopt);
	}

	return (error);
}
Esempio n. 5
0
/*
 * Reads a linux sockaddr and does any necessary translation.
 * Linux sockaddrs don't have a length field, only a family.
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
{
	struct sockaddr *sa;
	struct osockaddr *kosa;
#ifdef INET6
	struct sockaddr_in6 *sin6;
	int oldv6size;
#endif
	char *name;
	int bdom, error, hdrlen, namelen;

	if (salen < 2 || salen > UCHAR_MAX || !osa)
		return (EINVAL);

#ifdef INET6
	oldv6size = 0;
	/*
	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
	 * if it's a v4-mapped address, so reserve the proper space
	 * for it.
	 */
	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
		salen += sizeof(uint32_t);
		oldv6size = 1;
	}
#endif

	kosa = malloc(salen, M_SONAME, M_WAITOK);

	if ((error = copyin(osa, kosa, salen)))
		goto out;

	bdom = linux_to_bsd_domain(kosa->sa_family);
	if (bdom == -1) {
		error = EAFNOSUPPORT;
		goto out;
	}

#ifdef INET6
	/*
	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
	 * which lacks the scope id compared with RFC2553 one. If we detect
	 * the situation, reject the address and write a message to system log.
	 *
	 * Still accept addresses for which the scope id is not used.
	 */
	if (oldv6size) {
		if (bdom == AF_INET6) {
			sin6 = (struct sockaddr_in6 *)kosa;
			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
				sin6->sin6_scope_id = 0;
			} else {
				log(LOG_DEBUG,
				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
				error = EINVAL;
				goto out;
			}
		} else
			salen -= sizeof(uint32_t);
	}
#endif
	if (bdom == AF_INET) {
		if (salen < sizeof(struct sockaddr_in)) {
			error = EINVAL;
			goto out;
		}
		salen = sizeof(struct sockaddr_in);
	}

	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
		hdrlen = offsetof(struct sockaddr_un, sun_path);
		name = ((struct sockaddr_un *)kosa)->sun_path;
		if (*name == '\0') {
			/*
		 	 * Linux abstract namespace starts with a NULL byte.
			 * XXX We do not support abstract namespace yet.
			 */
			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
		} else
			namelen = strnlen(name, salen - hdrlen);
		salen = hdrlen + namelen;
		if (salen > sizeof(struct sockaddr_un)) {
			error = ENAMETOOLONG;
			goto out;
		}
	}
Esempio n. 6
0
/*
 * Copy the osockaddr structure pointed to by osa to kernel, adjust
 * family and convert to sockaddr.
 */
static int
do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
    struct malloc_type *mtype)
{
	int error=0, bdom;
	struct sockaddr *sa;
	struct osockaddr *kosa;
	int alloclen;
#ifdef INET6
	int oldv6size;
	struct sockaddr_in6 *sin6;
#endif

	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
		return (EINVAL);

	alloclen = *osalen;
#ifdef INET6
	oldv6size = 0;
	/*
	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
	 * if it's a v4-mapped address, so reserve the proper space
	 * for it.
	 */
	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
		alloclen = sizeof (struct sockaddr_in6);
		oldv6size = 1;
	}
#endif

	kosa = malloc(alloclen, mtype, M_WAITOK);

	if ((error = copyin(osa, kosa, *osalen)))
		goto out;

	bdom = linux_to_bsd_domain(kosa->sa_family);
	if (bdom == -1) {
		error = EAFNOSUPPORT;
		goto out;
	}

#ifdef INET6
	/*
	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
	 * which lacks the scope id compared with RFC2553 one. If we detect
	 * the situation, reject the address and write a message to system log.
	 *
	 * Still accept addresses for which the scope id is not used.
	 */
	if (oldv6size && bdom == AF_INET6) {
		sin6 = (struct sockaddr_in6 *)kosa;
		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
			sin6->sin6_scope_id = 0;
		} else {
			log(LOG_DEBUG,
			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
			error = EINVAL;
			goto out;
		}
	} else
#endif
	if (bdom == AF_INET) {
		alloclen = sizeof(struct sockaddr_in);
		if (*osalen < alloclen) {
			error = EINVAL;
			goto out;
		}
	}

	sa = (struct sockaddr *) kosa;
	sa->sa_family = bdom;
	sa->sa_len = alloclen;

	*sap = sa;
	*osalen = alloclen;
	return (0);

out:
	free(kosa, mtype);
	return (error);
}
Esempio n. 7
0
static int
linux_socket(struct thread *td, struct linux_socket_args *args)
{
	struct socket_args /* {
		int domain;
		int type;
		int protocol;
	} */ bsd_args;
	int retval_socket, socket_flags;

	bsd_args.protocol = args->protocol;
	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
		return (EINVAL);
	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
		return (EINVAL);
	bsd_args.domain = linux_to_bsd_domain(args->domain);
	if (bsd_args.domain == -1)
		return (EAFNOSUPPORT);

	retval_socket = socket(td, &bsd_args);
	if (retval_socket)
		return (retval_socket);

	retval_socket = linux_set_socket_flags(td, td->td_retval[0],
	    socket_flags);
	if (retval_socket) {
		(void)kern_close(td, td->td_retval[0]);
		goto out;
	}

	if (bsd_args.type == SOCK_RAW
	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
	    && bsd_args.domain == PF_INET) {
		/* It's a raw IP socket: set the IP_HDRINCL option. */
		int hdrincl;

		hdrincl = 1;
		/* We ignore any error returned by kern_setsockopt() */
		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
	}
#ifdef INET6
	/*
	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
	 * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
	 * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
	 * sysctl value.
	 */
	if (bsd_args.domain == PF_INET6) {
		int v6only;

		v6only = 0;
		/* We ignore any error returned by setsockopt() */
		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
		    &v6only, UIO_SYSSPACE, sizeof(v6only));
	}
#endif

out:
	return (retval_socket);
}