예제 #1
0
/** Send using su_vsend(). Map IPv4 addresses as IPv6 addresses, if needed. */
ssize_t tport_send_dgram(tport_t const *self, msg_t *msg,
			 msg_iovec_t iov[],
			 size_t iovused)
{
  su_sockaddr_t su[1];
  socklen_t sulen = sizeof su;

  if (tport_is_connection_oriented(self))
    return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, NULL, 0);

  msg_get_address(msg, su, &sulen);

#if SU_HAVE_IN6 && defined(IN6_INADDR_TO_V4MAPPED)
  if (su->su_family == AF_INET && self->tp_addrinfo->ai_family == AF_INET6) {
    su_sockaddr_t su0[1];

    memset(su0, 0, sizeof su0);

    su0->su_family = self->tp_addrinfo->ai_family;
    su0->su_port = su->su_port;

    IN6_INADDR_TO_V4MAPPED(&su->su_sin.sin_addr, &su0->su_sin6.sin6_addr);

    memcpy(su, su0, sulen = sizeof(su0->su_sin6));
  }
#endif

  su_soerror(self->tp_socket); /* XXX - we *still* have a race condition */

  return su_vsend(self->tp_socket, iov, iovused, MSG_NOSIGNAL, su, sulen);
}
예제 #2
0
파일: rpc_soc.c 프로젝트: BjoKaSH/mac-zfs
/*
 * Get clients IP address.
 * don't use gethostbyname, which would invoke yellow pages
 * Remains only for backward compatibility reasons.
 * Used mainly by the portmapper so that it can register
 * with itself. Also used by pmap*() routines
 */
void
get_myaddress_ipv6(char *fmly, struct sockaddr *addr)
{
	if (fmly != 0 && strcmp(fmly, NC_INET6) == 0) {
		/* LINTED pointer cast */
		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
		(void) memset(sin6, 0, sizeof (*sin6));
		sin6->sin6_family = AF_INET6;
		sin6->sin6_port = htons(PMAPPORT);
		if (__can_use_af(AF_INET6)) {
			/* Local copy of in6addr_any to avoid -lsocket */
			struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
			sin6->sin6_addr = in6addr_any;
		} else {
			struct in_addr in4;
			in4.s_addr = INADDR_ANY;
			IN6_INADDR_TO_V4MAPPED(&in4, &sin6->sin6_addr);
		}
	} else {
		/* LINTED pointer cast */
		struct sockaddr_in	*sin = (struct sockaddr_in *)addr;
		(void) memset(sin, 0, sizeof (*sin));
		sin->sin_family = AF_INET;
		sin->sin_port = htons(PMAPPORT);
		sin->sin_addr.s_addr = INADDR_ANY;
	}
}
예제 #3
0
static boolean_t
addrmatch(struct addrinfo *ai, struct sockaddr_in6 *sin6from)
{

	/*
	 * Note: on a GC query, the ds->addr port numbers are
	 * the GC port, and our from addr has the LDAP port.
	 * Just compare the IP addresses.
	 */

	if (ai->ai_family == AF_INET6) {
		struct sockaddr_in6 *sin6p = (void *)ai->ai_addr;

		if (!memcmp(&sin6from->sin6_addr, &sin6p->sin6_addr,
		    sizeof (struct in6_addr)))
			return (B_TRUE);
	}

	if (ai->ai_family == AF_INET) {
		struct in6_addr in6;
		struct sockaddr_in *sin4p = (void *)ai->ai_addr;

		IN6_INADDR_TO_V4MAPPED(&sin4p->sin_addr, &in6);
		if (!memcmp(&sin6from->sin6_addr, &in6,
		    sizeof (struct in6_addr)))
			return (B_TRUE);
	}

	return (B_FALSE);
}
예제 #4
0
/*
 * Attempt a send of the LDAP request to all known addresses
 * for this candidate server.
 */
static void
send_to_cds(ad_disc_cds_t *send_cds, char *ber_buf, size_t be_len, int fd)
{
	struct sockaddr_in6 addr6;
	struct addrinfo *ai;
	int err;

	if (DBG(DISC, 2)) {
		logger(LOG_DEBUG, "send to: %s", send_cds->cds_ds.host);
	}

	for (ai = send_cds->cds_ai; ai != NULL; ai = ai->ai_next) {

		/*
		 * Build the "to" address.
		 */
		(void) memset(&addr6, 0, sizeof (addr6));
		if (ai->ai_family == AF_INET6) {
			(void) memcpy(&addr6, ai->ai_addr, sizeof (addr6));
		} else if (ai->ai_family == AF_INET) {
			struct sockaddr_in *sin =
			    (void *)ai->ai_addr;
			addr6.sin6_family = AF_INET6;
			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr,
			    &addr6.sin6_addr);
		} else {
			continue;
		}
		addr6.sin6_port = htons(LDAP_PORT);

		/*
		 * Send the "ping" to this address.
		 */
		err = sendto(fd, ber_buf, be_len, 0,
		    (struct sockaddr *)&addr6, sizeof (addr6));
		err = (err < 0) ? errno : 0;

		if (DBG(DISC, 2)) {
			char abuf[INET6_ADDRSTRLEN];
			const char *pa;

			pa = inet_ntop(AF_INET6,
			    &addr6.sin6_addr,
			    abuf, sizeof (abuf));
			logger(LOG_ERR, "  > %s rc=%d",
			    pa ? pa : "?", err);
		}
	}
}
예제 #5
0
/*
 * Returns 0 if the check failed and the restart should be refused,
 * 1 if the check succeeded.
 */
int
sctp_secure_restart_check(mblk_t *pkt, sctp_chunk_hdr_t *ich, uint32_t ports,
    int sleep, sctp_stack_t *sctps, ip_recv_attr_t *ira)
{
	sctp_faddr_t *fp, *fphead = NULL;
	sctp_parm_hdr_t *ph;
	ssize_t remaining;
	int isv4;
	ipha_t *iph;
	ip6_t *ip6h;
	in6_addr_t hdraddr[1];
	int retval = 0;
	sctp_tf_t *tf;
	sctp_t *sctp;
	int compres;
	sctp_init_chunk_t *init;
	int nadded = 0;

	/* extract the address from the IP header */
	isv4 = (IPH_HDR_VERSION(pkt->b_rptr) == IPV4_VERSION);
	if (isv4) {
		iph = (ipha_t *)pkt->b_rptr;
		IN6_IPADDR_TO_V4MAPPED(iph->ipha_src, hdraddr);
	} else {
		ip6h = (ip6_t *)pkt->b_rptr;
		hdraddr[0] = ip6h->ip6_src;
	}

	/* Walk the params in the INIT [ACK], pulling out addr params */
	remaining = ntohs(ich->sch_len) - sizeof (*ich) -
	    sizeof (sctp_init_chunk_t);
	if (remaining < sizeof (*ph)) {
		/* no parameters; restart OK */
		return (1);
	}
	init = (sctp_init_chunk_t *)(ich + 1);
	ph = (sctp_parm_hdr_t *)(init + 1);

	while (ph != NULL) {
		sctp_faddr_t *fpa = NULL;

		/* params will have already been byteordered when validating */
		if (ph->sph_type == htons(PARM_ADDR4)) {
			if (remaining >= PARM_ADDR4_LEN) {
				in6_addr_t addr;
				IN6_INADDR_TO_V4MAPPED((struct in_addr *)
				    (ph + 1), &addr);
				fpa = kmem_cache_alloc(sctp_kmem_faddr_cache,
				    sleep);
				if (fpa == NULL) {
					goto done;
				}
				bzero(fpa, sizeof (*fpa));
				fpa->faddr = addr;
				fpa->next = NULL;
			}
		} else if (ph->sph_type == htons(PARM_ADDR6)) {
			if (remaining >= PARM_ADDR6_LEN) {
				fpa = kmem_cache_alloc(sctp_kmem_faddr_cache,
				    sleep);
				if (fpa == NULL) {
					goto done;
				}
				bzero(fpa, sizeof (*fpa));
				bcopy(ph + 1, &fpa->faddr,
				    sizeof (fpa->faddr));
				fpa->next = NULL;
			}
		}
		/* link in the new addr, if it was an addr param */
		if (fpa != NULL) {
			if (fphead == NULL) {
				fphead = fpa;
			} else {
				fpa->next = fphead;
				fphead = fpa;
			}
		}

		ph = sctp_next_parm(ph, &remaining);
	}

	if (fphead == NULL) {
		/* no addr parameters; restart OK */
		return (1);
	}

	/*
	 * got at least one; make sure the header's addr is
	 * in the list
	 */
	fp = sctp_lookup_faddr_nosctp(fphead, hdraddr);
	if (fp == NULL) {
		/* not included; add it now */
		fp = kmem_cache_alloc(sctp_kmem_faddr_cache, sleep);
		if (fp == NULL) {
			goto done;
		}
		bzero(fp, sizeof (*fp));
		fp->faddr = *hdraddr;
		fp->next = fphead;
		fphead = fp;
	}

	/*
	 * Now, we can finally do the check: For each sctp instance
	 * on the hash line for ports, compare its faddr set against
	 * the new one. If the new one is a strict subset of any
	 * existing sctp's faddrs, the restart is OK. However, if there
	 * is an overlap, this could be an attack, so return failure.
	 * If all sctp's faddrs are disjoint, this is a legitimate new
	 * association.
	 */
	tf = &(sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps, ports)]);
	mutex_enter(&tf->tf_lock);

	for (sctp = tf->tf_sctp; sctp; sctp = sctp->sctp_conn_hash_next) {
		if (ports != sctp->sctp_connp->conn_ports) {
			continue;
		}
		compres = sctp_compare_faddrsets(fphead, sctp->sctp_faddrs);
		if (compres <= SCTP_ADDR_SUBSET) {
			retval = 1;
			mutex_exit(&tf->tf_lock);
			goto done;
		}
		if (compres == SCTP_ADDR_OVERLAP) {
			dprint(1,
			    ("new assoc from %x:%x:%x:%x overlaps with %p\n",
			    SCTP_PRINTADDR(*hdraddr), (void *)sctp));
			/*
			 * While we still hold the lock, we need to
			 * figure out which addresses have been
			 * added so we can include them in the abort
			 * we will send back. Since these faddrs will
			 * never be used, we overload the rto field
			 * here, setting it to 0 if the address was
			 * not added, 1 if it was added.
			 */
			for (fp = fphead; fp; fp = fp->next) {
				if (sctp_lookup_faddr(sctp, &fp->faddr)) {
					fp->rto = 0;
				} else {
					fp->rto = 1;
					nadded++;
				}
			}
			mutex_exit(&tf->tf_lock);
			goto done;
		}
	}
	mutex_exit(&tf->tf_lock);

	/* All faddrs are disjoint; legit new association */
	retval = 1;

done:
	/* If are attempted adds, send back an abort listing the addrs */
	if (nadded > 0) {
		void *dtail;
		size_t dlen;

		dtail = kmem_alloc(PARM_ADDR6_LEN * nadded, KM_NOSLEEP);
		if (dtail == NULL) {
			goto cleanup;
		}

		ph = dtail;
		dlen = 0;
		for (fp = fphead; fp; fp = fp->next) {
			if (fp->rto == 0) {
				continue;
			}
			if (IN6_IS_ADDR_V4MAPPED(&fp->faddr)) {
				ipaddr_t addr4;

				ph->sph_type = htons(PARM_ADDR4);
				ph->sph_len = htons(PARM_ADDR4_LEN);
				IN6_V4MAPPED_TO_IPADDR(&fp->faddr, addr4);
				ph++;
				bcopy(&addr4, ph, sizeof (addr4));
				ph = (sctp_parm_hdr_t *)
				    ((char *)ph + sizeof (addr4));
				dlen += PARM_ADDR4_LEN;
			} else {
				ph->sph_type = htons(PARM_ADDR6);
				ph->sph_len = htons(PARM_ADDR6_LEN);
				ph++;
				bcopy(&fp->faddr, ph, sizeof (fp->faddr));
				ph = (sctp_parm_hdr_t *)
				    ((char *)ph + sizeof (fp->faddr));
				dlen += PARM_ADDR6_LEN;
			}
		}

		/* Send off the abort */
		sctp_send_abort(sctp, sctp_init2vtag(ich),
		    SCTP_ERR_RESTART_NEW_ADDRS, dtail, dlen, pkt, 0, B_TRUE,
		    ira);

		kmem_free(dtail, PARM_ADDR6_LEN * nadded);
	}

cleanup:
	/* Clean up */
	if (fphead) {
		sctp_faddr_t *fpn;
		for (fp = fphead; fp; fp = fpn) {
			fpn = fp->next;
			if (fp->ixa != NULL) {
				ixa_refrele(fp->ixa);
				fp->ixa = NULL;
			}
			kmem_cache_free(sctp_kmem_faddr_cache, fp);
		}
	}

	return (retval);
}
예제 #6
0
/*
 * Sets the address parameters given in the INIT chunk into sctp's
 * faddrs; if psctp is non-NULL, copies psctp's saddrs. If there are
 * no address parameters in the INIT chunk, a single faddr is created
 * from the ip hdr at the beginning of pkt.
 * If there already are existing addresses hanging from sctp, merge
 * them in, if the old info contains addresses which are not present
 * in this new info, get rid of them, and clean the pointers if there's
 * messages which have this as their target address.
 *
 * We also re-adjust the source address list here since the list may
 * contain more than what is actually part of the association. If
 * we get here from sctp_send_cookie_echo(), we are on the active
 * side and psctp will be NULL and ich will be the INIT-ACK chunk.
 * If we get here from sctp_accept_comm(), ich will be the INIT chunk
 * and psctp will the listening endpoint.
 *
 * INIT processing: When processing the INIT we inherit the src address
 * list from the listener. For a loopback or linklocal association, we
 * delete the list and just take the address from the IP header (since
 * that's how we created the INIT-ACK). Additionally, for loopback we
 * ignore the address params in the INIT. For determining which address
 * types were sent in the INIT-ACK we follow the same logic as in
 * creating the INIT-ACK. We delete addresses of the type that are not
 * supported by the peer.
 *
 * INIT-ACK processing: When processing the INIT-ACK since we had not
 * included addr params for loopback or linklocal addresses when creating
 * the INIT, we just use the address from the IP header. Further, for
 * loopback we ignore the addr param list. We mark addresses of the
 * type not supported by the peer as unconfirmed.
 *
 * In case of INIT processing we look for supported address types in the
 * supported address param, if present. In both cases the address type in
 * the IP header is supported as well as types for addresses in the param
 * list, if any.
 *
 * Once we have the supported address types sctp_check_saddr() runs through
 * the source address list and deletes or marks as unconfirmed address of
 * types not supported by the peer.
 *
 * Returns 0 on success, sys errno on failure
 */
int
sctp_get_addrparams(sctp_t *sctp, sctp_t *psctp, mblk_t *pkt,
    sctp_chunk_hdr_t *ich, uint_t *sctp_options)
{
	sctp_init_chunk_t	*init;
	ipha_t			*iph;
	ip6_t			*ip6h;
	in6_addr_t		hdrsaddr[1];
	in6_addr_t		hdrdaddr[1];
	sctp_parm_hdr_t		*ph;
	ssize_t			remaining;
	int			isv4;
	int			err;
	sctp_faddr_t		*fp;
	int			supp_af = 0;
	boolean_t		check_saddr = B_TRUE;
	in6_addr_t		curaddr;
	sctp_stack_t		*sctps = sctp->sctp_sctps;
	conn_t			*connp = sctp->sctp_connp;

	if (sctp_options != NULL)
		*sctp_options = 0;

	/* extract the address from the IP header */
	isv4 = (IPH_HDR_VERSION(pkt->b_rptr) == IPV4_VERSION);
	if (isv4) {
		iph = (ipha_t *)pkt->b_rptr;
		IN6_IPADDR_TO_V4MAPPED(iph->ipha_src, hdrsaddr);
		IN6_IPADDR_TO_V4MAPPED(iph->ipha_dst, hdrdaddr);
		supp_af |= PARM_SUPP_V4;
	} else {
		ip6h = (ip6_t *)pkt->b_rptr;
		hdrsaddr[0] = ip6h->ip6_src;
		hdrdaddr[0] = ip6h->ip6_dst;
		supp_af |= PARM_SUPP_V6;
	}

	/*
	 * Unfortunately, we can't delay this because adding an faddr
	 * looks for the presence of the source address (from the ire
	 * for the faddr) in the source address list. We could have
	 * delayed this if, say, this was a loopback/linklocal connection.
	 * Now, we just end up nuking this list and taking the addr from
	 * the IP header for loopback/linklocal.
	 */
	if (psctp != NULL && psctp->sctp_nsaddrs > 0) {
		ASSERT(sctp->sctp_nsaddrs == 0);

		err = sctp_dup_saddrs(psctp, sctp, KM_NOSLEEP);
		if (err != 0)
			return (err);
	}
	/*
	 * We will add the faddr before parsing the address list as this
	 * might be a loopback connection and we would not have to
	 * go through the list.
	 *
	 * Make sure the header's addr is in the list
	 */
	fp = sctp_lookup_faddr(sctp, hdrsaddr);
	if (fp == NULL) {
		/* not included; add it now */
		err = sctp_add_faddr(sctp, hdrsaddr, KM_NOSLEEP, B_TRUE);
		if (err != 0)
			return (err);

		/* sctp_faddrs will be the hdr addr */
		fp = sctp->sctp_faddrs;
	}
	/* make the header addr the primary */

	if (cl_sctp_assoc_change != NULL && psctp == NULL)
		curaddr = sctp->sctp_current->faddr;

	sctp->sctp_primary = fp;
	sctp->sctp_current = fp;
	sctp->sctp_mss = fp->sfa_pmss;

	/* For loopback connections & linklocal get address from the header */
	if (sctp->sctp_loopback || sctp->sctp_linklocal) {
		if (sctp->sctp_nsaddrs != 0)
			sctp_free_saddrs(sctp);
		if ((err = sctp_saddr_add_addr(sctp, hdrdaddr, 0)) != 0)
			return (err);
		/* For loopback ignore address list */
		if (sctp->sctp_loopback)
			return (0);
		check_saddr = B_FALSE;
	}

	/* Walk the params in the INIT [ACK], pulling out addr params */
	remaining = ntohs(ich->sch_len) - sizeof (*ich) -
	    sizeof (sctp_init_chunk_t);
	if (remaining < sizeof (*ph)) {
		if (check_saddr) {
			sctp_check_saddr(sctp, supp_af, psctp == NULL ?
			    B_FALSE : B_TRUE, hdrdaddr);
		}
		ASSERT(sctp_saddr_lookup(sctp, hdrdaddr, 0) != NULL);
		return (0);
	}

	init = (sctp_init_chunk_t *)(ich + 1);
	ph = (sctp_parm_hdr_t *)(init + 1);

	/* params will have already been byteordered when validating */
	while (ph != NULL) {
		if (ph->sph_type == htons(PARM_SUPP_ADDRS)) {
			int		plen;
			uint16_t	*p;
			uint16_t	addrtype;

			ASSERT(psctp != NULL);
			plen = ntohs(ph->sph_len);
			p = (uint16_t *)(ph + 1);
			while (plen > 0) {
				addrtype = ntohs(*p);
				switch (addrtype) {
					case PARM_ADDR6:
						supp_af |= PARM_SUPP_V6;
						break;
					case PARM_ADDR4:
						supp_af |= PARM_SUPP_V4;
						break;
					default:
						break;
				}
				p++;
				plen -= sizeof (*p);
			}
		} else if (ph->sph_type == htons(PARM_ADDR4)) {
			if (remaining >= PARM_ADDR4_LEN) {
				in6_addr_t addr;
				ipaddr_t ta;

				supp_af |= PARM_SUPP_V4;
				/*
				 * Screen out broad/multicasts & loopback.
				 * If the endpoint only accepts v6 address,
				 * go to the next one.
				 *
				 * Subnet broadcast check is done in
				 * sctp_add_faddr().  If the address is
				 * a broadcast address, it won't be added.
				 */
				bcopy(ph + 1, &ta, sizeof (ta));
				if (ta == 0 ||
				    ta == INADDR_BROADCAST ||
				    ta == htonl(INADDR_LOOPBACK) ||
				    CLASSD(ta) || connp->conn_ipv6_v6only) {
					goto next;
				}
				IN6_INADDR_TO_V4MAPPED((struct in_addr *)
				    (ph + 1), &addr);

				/* Check for duplicate. */
				if (sctp_lookup_faddr(sctp, &addr) != NULL)
					goto next;

				/* OK, add it to the faddr set */
				err = sctp_add_faddr(sctp, &addr, KM_NOSLEEP,
				    B_FALSE);
				/* Something is wrong...  Try the next one. */
				if (err != 0)
					goto next;
			}
		} else if (ph->sph_type == htons(PARM_ADDR6) &&
		    connp->conn_family == AF_INET6) {
			/* An v4 socket should not take v6 addresses. */
			if (remaining >= PARM_ADDR6_LEN) {
				in6_addr_t *addr6;

				supp_af |= PARM_SUPP_V6;
				addr6 = (in6_addr_t *)(ph + 1);
				/*
				 * Screen out link locals, mcast, loopback
				 * and bogus v6 address.
				 */
				if (IN6_IS_ADDR_LINKLOCAL(addr6) ||
				    IN6_IS_ADDR_MULTICAST(addr6) ||
				    IN6_IS_ADDR_LOOPBACK(addr6) ||
				    IN6_IS_ADDR_V4MAPPED(addr6)) {
					goto next;
				}
				/* Check for duplicate. */
				if (sctp_lookup_faddr(sctp, addr6) != NULL)
					goto next;

				err = sctp_add_faddr(sctp,
				    (in6_addr_t *)(ph + 1), KM_NOSLEEP,
				    B_FALSE);
				/* Something is wrong...  Try the next one. */
				if (err != 0)
					goto next;
			}
		} else if (ph->sph_type == htons(PARM_FORWARD_TSN)) {
			if (sctp_options != NULL)
				*sctp_options |= SCTP_PRSCTP_OPTION;
		} /* else; skip */

next:
		ph = sctp_next_parm(ph, &remaining);
	}
	if (check_saddr) {
		sctp_check_saddr(sctp, supp_af, psctp == NULL ? B_FALSE :
		    B_TRUE, hdrdaddr);
	}
	ASSERT(sctp_saddr_lookup(sctp, hdrdaddr, 0) != NULL);
	/*
	 * We have the right address list now, update clustering's
	 * knowledge because when we sent the INIT we had just added
	 * the address the INIT was sent to.
	 */
	if (psctp == NULL && cl_sctp_assoc_change != NULL) {
		uchar_t	*alist;
		size_t	asize;
		uchar_t	*dlist;
		size_t	dsize;

		asize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
		alist = kmem_alloc(asize, KM_NOSLEEP);
		if (alist == NULL) {
			SCTP_KSTAT(sctps, sctp_cl_assoc_change);
			return (ENOMEM);
		}
		/*
		 * Just include the address the INIT was sent to in the
		 * delete list and send the entire faddr list. We could
		 * do it differently (i.e include all the addresses in the
		 * add list even if it contains the original address OR
		 * remove the original address from the add list etc.), but
		 * this seems reasonable enough.
		 */
		dsize = sizeof (in6_addr_t);
		dlist = kmem_alloc(dsize, KM_NOSLEEP);
		if (dlist == NULL) {
			kmem_free(alist, asize);
			SCTP_KSTAT(sctps, sctp_cl_assoc_change);
			return (ENOMEM);
		}
		bcopy(&curaddr, dlist, sizeof (curaddr));
		sctp_get_faddr_list(sctp, alist, asize);
		(*cl_sctp_assoc_change)(connp->conn_family, alist, asize,
		    sctp->sctp_nfaddrs, dlist, dsize, 1, SCTP_CL_PADDR,
		    (cl_sctp_handle_t)sctp);
		/* alist and dlist will be freed by the clustering module */
	}
	return (0);
}
예제 #7
0
int
sctp_del_ip(sctp_t *sctp, const void *addrs, uint32_t cnt, uchar_t *ulist,
    size_t usize)
{
	struct sockaddr_in	*sin4;
	struct sockaddr_in6	*sin6;
	mblk_t			*mp;
	int			error = 0;
	int			i;
	int			addrcnt = 0;
	sctp_addip4_t		*ad4;
	sctp_addip6_t		*ad6;
	sctp_asconf_t		asc[1];
	sctp_saddr_ipif_t	*nsp;
	uint16_t		type = htons(PARM_DEL_IP);
	boolean_t		v4mapped = B_FALSE;
	in6_addr_t		addr;
	boolean_t		asconf = B_TRUE;
	uint_t			ifindex;
	sctp_cl_ainfo_t		*ainfo = NULL;
	uchar_t			*p = ulist;
	boolean_t		check_lport = B_FALSE;
	sctp_stack_t		*sctps = sctp->sctp_sctps;
	conn_t			*connp = sctp->sctp_connp;

	/* Does the peer understand ASCONF and Add-IP? */
	if (sctp->sctp_state <= SCTPS_LISTEN || !sctps->sctps_addip_enabled ||
	    !sctp->sctp_understands_asconf || !sctp->sctp_understands_addip) {
		asconf = B_FALSE;
	}

	if (sctp->sctp_state > SCTPS_BOUND)
		check_lport = B_TRUE;

	if (asconf) {
		/*
		 * On a clustered node, we need to pass this list when
		 * we get an ASCONF-ACK. We only pre-allocate memory for the
		 * list, but fill in the addresses when it is processed
		 * successfully after we get an ASCONF-ACK.
		 */
		if (cl_sctp_assoc_change != NULL) {
			ainfo = kmem_alloc(sizeof (*ainfo), KM_SLEEP);
			ainfo->sctp_cl_dsize = sizeof (in6_addr_t) * cnt;
			ainfo->sctp_cl_dlist = kmem_alloc(ainfo->sctp_cl_dsize,
			    KM_SLEEP);
		}
		sctp_asconf_init(asc);
	}
	/*
	 * Screen addresses:
	 * If adding:
	 *   o Must not already be a part of the association
	 *   o Must be AF_INET or AF_INET6
	 *   o XXX Must be valid source address for this node
	 *   o Must be unicast
	 *   o XXX Must fit scoping rules
	 * If deleting:
	 *   o Must be part of the association
	 */
	for (i = 0; i < cnt; i++) {
		ifindex = 0;

		switch (connp->conn_family) {
		case AF_INET:
			sin4 = (struct sockaddr_in *)addrs + i;
			if (check_lport &&
			    sin4->sin_port != connp->conn_lport) {
				error = EINVAL;
				goto fail;
			}
			v4mapped = B_TRUE;
			IN6_IPADDR_TO_V4MAPPED(sin4->sin_addr.s_addr, &addr);
			break;

		case AF_INET6:
			sin6 = (struct sockaddr_in6 *)addrs + i;
			if (check_lport &&
			    sin6->sin6_port != connp->conn_lport) {
				error = EINVAL;
				goto fail;
			}
			addr = sin6->sin6_addr;
			ifindex = sin6->sin6_scope_id;
			break;
		}
		nsp = sctp_saddr_lookup(sctp, &addr, ifindex);
		if (nsp == NULL) {
			error = EADDRNOTAVAIL;
			goto fail;
		}

		/* Collect the list of addresses, if required */
		if (usize >= sizeof (addr)) {
			bcopy(&addr, p, sizeof (addr));
			p += sizeof (addr);
			usize -= sizeof (addr);
		}
		if (!asconf)
			continue;

		nsp->saddr_ipif_delete_pending = 1;
		nsp->saddr_ipif_dontsrc = 1;
		addrcnt++;
		if (v4mapped) {
			mp = allocb(sizeof (*ad4), BPRI_MED);
			if (mp == NULL) {
				error = ENOMEM;
				goto fail;
			}
			mp->b_wptr += sizeof (*ad4);
			ad4 = (sctp_addip4_t *)mp->b_rptr;
			ad4->sad4_addip_ph.sph_type = type;
			ad4->sad4_addip_ph.sph_len =
			    htons(sizeof (sctp_parm_hdr_t) +
			    PARM_ADDR4_LEN + sizeof (ad4->asconf_req_cid));
			ad4->sad4_addr4_ph.sph_type = htons(PARM_ADDR4);
			ad4->sad4_addr4_ph.sph_len = htons(PARM_ADDR4_LEN);
			ad4->sad4_addr = sin4->sin_addr.s_addr;
		} else {
			mp = allocb(sizeof (*ad6), BPRI_MED);
			if (mp == NULL) {
				error = ENOMEM;
				goto fail;
			}
			mp->b_wptr += sizeof (*ad6);
			ad6 = (sctp_addip6_t *)mp->b_rptr;
			ad6->sad6_addip_ph.sph_type = type;
			ad6->sad6_addip_ph.sph_len =
			    htons(sizeof (sctp_parm_hdr_t) + PARM_ADDR6_LEN +
			    sizeof (ad6->asconf_req_cid));
			ad6->sad6_addr6_ph.sph_type = htons(PARM_ADDR6);
			ad6->sad6_addr6_ph.sph_len = htons(PARM_ADDR6_LEN);
			ad6->sad6_addr = addr;
		}

		error = sctp_asconf_add(asc, mp);
		if (error != 0)
			goto fail;
	}

	if (!asconf) {
		sctp_del_saddr_list(sctp, addrs, cnt, B_FALSE);
		return (0);
	}
	error = sctp_asconf_send(sctp, asc, sctp->sctp_current, ainfo);
	if (error != 0)
		goto fail;
	sctp_redo_faddr_srcs(sctp);
	return (0);

fail:
	if (ainfo != NULL) {
		kmem_free(ainfo->sctp_cl_dlist, ainfo->sctp_cl_dsize);
		ainfo->sctp_cl_dsize = 0;
		kmem_free(ainfo, sizeof (*ainfo));
	}
	if (!asconf)
		return (error);
	for (i = 0; i < addrcnt; i++) {
		ifindex = 0;

		switch (connp->conn_family) {
		case AF_INET:
			sin4 = (struct sockaddr_in *)addrs + i;
			IN6_INADDR_TO_V4MAPPED(&(sin4->sin_addr), &addr);
			break;
		case AF_INET6:
			sin6 = (struct sockaddr_in6 *)addrs + i;
			addr = sin6->sin6_addr;
			ifindex = sin6->sin6_scope_id;
			break;
		}
		nsp = sctp_saddr_lookup(sctp, &addr, ifindex);
		ASSERT(nsp != NULL);
		nsp->saddr_ipif_delete_pending = 0;
		nsp->saddr_ipif_dontsrc = 0;
	}
	sctp_asconf_destroy(asc);

	return (error);
}
예제 #8
0
파일: rcmd.c 프로젝트: andreiw/polaris
int rcmd_af(char **ahost, unsigned short rport, const char *locuser,
    const char *remuser, const char *cmd, int *fd2p, int af)
{
	int s, timo = 1;
	ssize_t retval;
	pid_t pid;
	struct sockaddr_storage caddr, faddr;
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;
	struct addrinfo hints;
	struct addrinfo *res, *resp;
	size_t addrlen;
	int rc;
#define	MAX_SHORTSTRLEN 6
	char aport[MAX_SHORTSTRLEN];
	char c;
	int lport = 0;
#ifdef SYSV
	sigset_t oldmask;
	sigset_t newmask;
	struct sigaction oldaction;
	struct sigaction newaction;
#else
	int oldmask;
#endif /* SYSV */
	fd_set fdset;
	int selret;
	char *addr;
	static char hostname[MAXHOSTNAMELEN];
	socklen_t len;
	char abuf[INET6_ADDRSTRLEN];

	if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
		errno = EAFNOSUPPORT;
		return (-1);
	}

	pid = getpid();
	memset(&hints, 0, sizeof (hints));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_CANONNAME;
	if (af == AF_INET6) {
		hints.ai_flags |= AI_V4MAPPED;
		hints.ai_family = AF_UNSPEC;
	} else {
		hints.ai_family = af;
	}
	(void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
	rc = getaddrinfo(*ahost, aport, &hints, &res);
	if (rc != 0) {
		(void) fprintf(stderr,
		    _dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"),
		    *ahost, rc == EAI_AGAIN ? " (try again later)" : "");
		return (-1);
	}
	resp = res;
	(void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
	*ahost = hostname;
#ifdef SYSV
	/* ignore SIGPIPE */
	bzero((char *)&newaction, sizeof (newaction));
	newaction.sa_handler = SIG_IGN;
	(void) _sigaction(SIGPIPE, &newaction, &oldaction);

	/* block SIGURG */
	bzero((char *)&newmask, sizeof (newmask));
	(void) _sigaddset(&newmask, SIGURG);
	(void) _sigprocmask(SIG_BLOCK, &newmask, &oldmask);
#else
	oldmask = _sigblock(sigmask(SIGURG));
#endif /* SYSV */
	for (;;) {
		s = rresvport_af(&lport, res->ai_family);
		if (s < 0) {
			int af = res->ai_family;

			/*
			 * See if we have any addresses of a different type
			 * to try.
			 */
			while (res != NULL && res->ai_family == af)
				res = res->ai_next;

			if (res != NULL)
				continue;

			if (errno == EAGAIN)
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
				    "socket: All ports in use\n"));
			else
				perror("rcmd: socket");
#ifdef SYSV
			/* restore original SIGPIPE handler */
			(void) _sigaction(SIGPIPE, &oldaction,
			    (struct sigaction *)0);

			/* restore original signal mask */
			(void) _sigprocmask(SIG_SETMASK, &oldmask,
			    (sigset_t *)0);
#else
			sigsetmask(oldmask);
#endif /* SYSV */
			freeaddrinfo(resp);
			return (-1);
		}
		bzero((char *)&caddr, sizeof (caddr));
		bcopy(res->ai_addr, &caddr, res->ai_addrlen);
		addrlen = res->ai_addrlen;
		if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) {
			struct in6_addr ia6;
			struct sockaddr_in6 *in6addr;
			IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *)
			    res->ai_addr)->sin_addr, &ia6);
			in6addr = (struct sockaddr_in6 *)&caddr;
			in6addr->sin6_addr = ia6;
			in6addr->sin6_family = AF_INET6;
			addrlen = sizeof (struct sockaddr_in6);
		}
		(void) _fcntl(s, F_SETOWN, pid);
		if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0)
			break;
		(void) close(s);
		if (errno == EADDRINUSE) {
			lport = 0;
			continue;
		}
		if (errno == ECONNREFUSED && timo <= 16) {
			(void) sleep(timo);
			timo *= 2;
			continue;
		}
		if (res->ai_next != NULL) {
			int oerrno = errno;
			if (res->ai_addr->sa_family == AF_INET6)
				addr = (char *)&((struct sockaddr_in6 *)
				    res->ai_addr)->sin6_addr;
			else
				addr = (char *)&((struct sockaddr_in *)
				    res->ai_addr)->sin_addr;
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN, "connect to address %s: "),
			    inet_ntop(res->ai_addr->sa_family, addr,
			    abuf, sizeof (abuf)));
			errno = oerrno;
			perror(0);
			res = res->ai_next;
			if (res->ai_addr->sa_family == AF_INET6)
				addr = (char *)&((struct sockaddr_in6 *)
				    res->ai_addr)->sin6_addr;
			else
				addr = (char *)&((struct sockaddr_in *)
				    res->ai_addr)->sin_addr;
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN, "Trying %s...\n"),
			    inet_ntop(res->ai_addr->sa_family, addr,
			    abuf, sizeof (abuf)));
			continue;
		}
		perror(*ahost);
		freeaddrinfo(resp);
#ifdef SYSV
		/* restore original SIGPIPE handler */
		(void) _sigaction(SIGPIPE, &oldaction,
		    (struct sigaction *)0);

		/* restore original signal mask */
		(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
		sigsetmask(oldmask);
#endif /* SYSV */
		return (-1);
	}
	lport = 0;
	if (fd2p == 0) {
		(void) write(s, "", 1);
	} else {
		int s2 = rresvport_af(&lport, res->ai_family), s3;

		len = (socklen_t)sizeof (faddr);

		if (s2 < 0)
			goto bad;
		(void) listen(s2, 1);
		(void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport);
		if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) {
			perror(_dgettext(TEXT_DOMAIN,
			    "write: setting up stderr"));
			(void) close(s2);
			goto bad;
		}
		FD_ZERO(&fdset);
		FD_SET(s, &fdset);
		FD_SET(s2, &fdset);
		while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0,
		    (fd_set *)0, (struct timeval *)0)) > 0) {
			if (FD_ISSET(s, &fdset)) {
				/*
				 *	Something's wrong:  we should get no
				 *	data on this connection at this point,
				 *	so we assume that the connection has
				 *	gone away.
				 */
				(void) close(s2);
				goto bad;
			}
			if (FD_ISSET(s2, &fdset)) {
				/*
				 *	We assume this is an incoming connect
				 *	request and proceed normally.
				 */
				s3 = accept(s2, (struct sockaddr *)&faddr,
				    &len);
				FD_CLR(s2, &fdset);
				(void) close(s2);
				if (s3 < 0) {
					perror("accept");
					lport = 0;
					goto bad;
				}
				else
					break;
			}
		}
		if (selret == -1) {
			/*
			 *	This should not happen, and we treat it as
			 *	a fatal error.
			 */
			(void) close(s2);
			goto bad;
		}

		*fd2p = s3;
		switch (faddr.ss_family) {
		case AF_INET:
			sin = (struct sockaddr_in *)&faddr;
			if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
					"socket: protocol failure in circuit "
					"setup.\n"));
				goto bad2;
			}
			break;
		case AF_INET6:
			sin6 = (struct sockaddr_in6 *)&faddr;
			if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) {
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
					"socket: protocol failure in circuit "
					"setup.\n"));
				goto bad2;
			}
			break;
		default:
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "socket: protocol failure in circuit setup.\n"));
			goto bad2;
		}
	}
	(void) write(s, locuser, strlen(locuser)+1);
	(void) write(s, remuser, strlen(remuser)+1);
	(void) write(s, cmd, strlen(cmd)+1);
	retval = read(s, &c, 1);
	if (retval != 1) {
		if (retval == 0) {
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "Protocol error, %s closed connection\n"),
			    *ahost);
		} else if (retval < 0) {
			perror(*ahost);
		} else {
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "Protocol error, %s sent %d bytes\n"),
			    *ahost, retval);
		}
		goto bad2;
	}
	if (c != 0) {
		while (read(s, &c, 1) == 1) {
			(void) write(2, &c, 1);
			if (c == '\n')
				break;
		}
		goto bad2;
	}
#ifdef SYSV
	/* restore original SIGPIPE handler */
	(void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);

	/* restore original signal mask */
	(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
	sigsetmask(oldmask);
#endif /* SYSV */
	freeaddrinfo(resp);
	return (s);
bad2:
	if (lport)
		(void) close(*fd2p);
bad:
	(void) close(s);
#ifdef SYSV
	/* restore original SIGPIPE handler */
	(void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);

	/* restore original signal mask */
	(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
	sigsetmask(oldmask);
#endif /* SYSV */
	freeaddrinfo(resp);
	return (-1);
}
예제 #9
0
/*
 * Connect to a peer - this function inserts the sctp in the
 * bind and conn fanouts, sends the INIT, and replies to the client
 * with an OK ack.
 */
int
sctp_connect(sctp_t *sctp, const struct sockaddr *dst, uint32_t addrlen,
    cred_t *cr, pid_t pid)
{
	sin_t		*sin;
	sin6_t		*sin6;
	in6_addr_t	dstaddr;
	in_port_t	dstport;
	mblk_t		*initmp;
	sctp_tf_t	*tbf;
	sctp_t		*lsctp;
	char		buf[INET6_ADDRSTRLEN];
	int		sleep = sctp->sctp_cansleep ? KM_SLEEP : KM_NOSLEEP;
	int		err;
	sctp_faddr_t	*cur_fp;
	sctp_stack_t	*sctps = sctp->sctp_sctps;
	conn_t		*connp = sctp->sctp_connp;
	uint_t		scope_id = 0;
	ip_xmit_attr_t	*ixa;

	/*
	 * Determine packet type based on type of address passed in
	 * the request should contain an IPv4 or IPv6 address.
	 * Make sure that address family matches the type of
	 * family of the address passed down.
	 */
	if (addrlen < sizeof (sin_t)) {
		return (EINVAL);
	}
	switch (dst->sa_family) {
	case AF_INET:
		sin = (sin_t *)dst;

		/* Check for attempt to connect to non-unicast */
		if (CLASSD(sin->sin_addr.s_addr) ||
		    (sin->sin_addr.s_addr == INADDR_BROADCAST)) {
			ip0dbg(("sctp_connect: non-unicast\n"));
			return (EINVAL);
		}
		if (connp->conn_ipv6_v6only)
			return (EAFNOSUPPORT);

		/* convert to v6 mapped */
		/* Check for attempt to connect to INADDR_ANY */
		if (sin->sin_addr.s_addr == INADDR_ANY)  {
			struct in_addr v4_addr;
			/*
			 * SunOS 4.x and 4.3 BSD allow an application
			 * to connect a TCP socket to INADDR_ANY.
			 * When they do this, the kernel picks the
			 * address of one interface and uses it
			 * instead.  The kernel usually ends up
			 * picking the address of the loopback
			 * interface.  This is an undocumented feature.
			 * However, we provide the same thing here
			 * in case any TCP apps that use this feature
			 * are being ported to SCTP...
			 */
			v4_addr.s_addr = htonl(INADDR_LOOPBACK);
			IN6_INADDR_TO_V4MAPPED(&v4_addr, &dstaddr);
		} else {
			IN6_INADDR_TO_V4MAPPED(&sin->sin_addr, &dstaddr);
		}
		dstport = sin->sin_port;
		break;
	case AF_INET6:
		sin6 = (sin6_t *)dst;
		/* Check for attempt to connect to non-unicast. */
		if ((addrlen < sizeof (sin6_t)) ||
		    IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
			ip0dbg(("sctp_connect: non-unicast\n"));
			return (EINVAL);
		}
		if (connp->conn_ipv6_v6only &&
		    IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
			return (EAFNOSUPPORT);
		}
		/* check for attempt to connect to unspec */
		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
			dstaddr = ipv6_loopback;
		} else {
			dstaddr = sin6->sin6_addr;
			if (IN6_IS_ADDR_LINKLOCAL(&dstaddr)) {
				sctp->sctp_linklocal = 1;
				scope_id = sin6->sin6_scope_id;
			}
		}
		dstport = sin6->sin6_port;
		connp->conn_flowinfo = sin6->sin6_flowinfo;
		break;
	default:
		dprint(1, ("sctp_connect: unknown family %d\n",
		    dst->sa_family));
		return (EAFNOSUPPORT);
	}

	(void) inet_ntop(AF_INET6, &dstaddr, buf, sizeof (buf));
	dprint(1, ("sctp_connect: attempting connect to %s...\n", buf));

	RUN_SCTP(sctp);

	if (connp->conn_family != dst->sa_family ||
	    (connp->conn_state_flags & CONN_CLOSING)) {
		WAKE_SCTP(sctp);
		return (EINVAL);
	}

	/* We update our cred/cpid based on the caller of connect */
	if (connp->conn_cred != cr) {
		crhold(cr);
		crfree(connp->conn_cred);
		connp->conn_cred = cr;
	}
	connp->conn_cpid = pid;

	/* Cache things in conn_ixa without any refhold */
	ixa = connp->conn_ixa;
	ixa->ixa_cred = cr;
	ixa->ixa_cpid = pid;
	if (is_system_labeled()) {
		/* We need to restart with a label based on the cred */
		ip_xmit_attr_restore_tsl(ixa, ixa->ixa_cred);
	}

	switch (sctp->sctp_state) {
	case SCTPS_IDLE: {
		struct sockaddr_storage	ss;

		/*
		 * We support a quick connect capability here, allowing
		 * clients to transition directly from IDLE to COOKIE_WAIT.
		 * sctp_bindi will pick an unused port, insert the connection
		 * in the bind hash and transition to BOUND state. SCTP
		 * picks and uses what it considers the optimal local address
		 * set (just like specifiying INADDR_ANY to bind()).
		 */
		dprint(1, ("sctp_connect: idle, attempting bind...\n"));
		ASSERT(sctp->sctp_nsaddrs == 0);

		bzero(&ss, sizeof (ss));
		ss.ss_family = connp->conn_family;
		WAKE_SCTP(sctp);
		if ((err = sctp_bind(sctp, (struct sockaddr *)&ss,
		    sizeof (ss))) != 0) {
			return (err);
		}
		RUN_SCTP(sctp);
		/* FALLTHRU */
	}

	case SCTPS_BOUND:
		ASSERT(sctp->sctp_nsaddrs > 0);

		/* do the connect */
		/* XXX check for attempt to connect to self */
		connp->conn_fport = dstport;

		ASSERT(sctp->sctp_iphc);
		ASSERT(sctp->sctp_iphc6);

		/*
		 * Don't allow this connection to completely duplicate
		 * an existing connection.
		 *
		 * Ensure that the duplicate check and insertion is atomic.
		 */
		sctp_conn_hash_remove(sctp);
		tbf = &sctps->sctps_conn_fanout[SCTP_CONN_HASH(sctps,
		    connp->conn_ports)];
		mutex_enter(&tbf->tf_lock);
		lsctp = sctp_lookup(sctp, &dstaddr, tbf, &connp->conn_ports,
		    SCTPS_COOKIE_WAIT);
		if (lsctp != NULL) {
			/* found a duplicate connection */
			mutex_exit(&tbf->tf_lock);
			SCTP_REFRELE(lsctp);
			WAKE_SCTP(sctp);
			return (EADDRINUSE);
		}

		/*
		 * OK; set up the peer addr (this may grow after we get
		 * the INIT ACK from the peer with additional addresses).
		 */
		if ((err = sctp_add_faddr(sctp, &dstaddr, sleep,
		    B_FALSE)) != 0) {
			mutex_exit(&tbf->tf_lock);
			WAKE_SCTP(sctp);
			return (err);
		}
		cur_fp = sctp->sctp_faddrs;
		ASSERT(cur_fp->ixa != NULL);

		/* No valid src addr, return. */
		if (cur_fp->state == SCTP_FADDRS_UNREACH) {
			mutex_exit(&tbf->tf_lock);
			WAKE_SCTP(sctp);
			return (EADDRNOTAVAIL);
		}

		sctp->sctp_primary = cur_fp;
		sctp->sctp_current = cur_fp;
		sctp->sctp_mss = cur_fp->sfa_pmss;
		sctp_conn_hash_insert(tbf, sctp, 1);
		mutex_exit(&tbf->tf_lock);

		ixa = cur_fp->ixa;
		ASSERT(ixa->ixa_cred != NULL);

		if (scope_id != 0) {
			ixa->ixa_flags |= IXAF_SCOPEID_SET;
			ixa->ixa_scopeid = scope_id;
		} else {
			ixa->ixa_flags &= ~IXAF_SCOPEID_SET;
		}

		/* initialize composite headers */
		if ((err = sctp_set_hdraddrs(sctp)) != 0) {
			sctp_conn_hash_remove(sctp);
			WAKE_SCTP(sctp);
			return (err);
		}

		if ((err = sctp_build_hdrs(sctp, KM_SLEEP)) != 0) {
			sctp_conn_hash_remove(sctp);
			WAKE_SCTP(sctp);
			return (err);
		}

		/*
		 * Turn off the don't fragment bit on the (only) faddr,
		 * so that if one of the messages exchanged during the
		 * initialization sequence exceeds the path mtu, it
		 * at least has a chance to get there. SCTP does no
		 * fragmentation of initialization messages.  The DF bit
		 * will be turned on again in sctp_send_cookie_echo()
		 * (but the cookie echo will still be sent with the df bit
		 * off).
		 */
		cur_fp->df = B_FALSE;

		/* Mark this address as alive */
		cur_fp->state = SCTP_FADDRS_ALIVE;

		/* Send the INIT to the peer */
		SCTP_FADDR_TIMER_RESTART(sctp, cur_fp, cur_fp->rto);
		sctp->sctp_state = SCTPS_COOKIE_WAIT;
		/*
		 * sctp_init_mp() could result in modifying the source
		 * address list, so take the hash lock.
		 */
		mutex_enter(&tbf->tf_lock);
		initmp = sctp_init_mp(sctp, cur_fp);
		if (initmp == NULL) {
			mutex_exit(&tbf->tf_lock);
			/*
			 * It may happen that all the source addresses
			 * (loopback/link local) are removed.  In that case,
			 * faile the connect.
			 */
			if (sctp->sctp_nsaddrs == 0) {
				sctp_conn_hash_remove(sctp);
				SCTP_FADDR_TIMER_STOP(cur_fp);
				WAKE_SCTP(sctp);
				return (EADDRNOTAVAIL);
			}

			/* Otherwise, let the retransmission timer retry */
			WAKE_SCTP(sctp);
			goto notify_ulp;
		}
		mutex_exit(&tbf->tf_lock);

		/*
		 * On a clustered note send this notification to the clustering
		 * subsystem.
		 */
		if (cl_sctp_connect != NULL) {
			uchar_t		*slist;
			uchar_t		*flist;
			size_t		ssize;
			size_t		fsize;

			fsize = sizeof (in6_addr_t) * sctp->sctp_nfaddrs;
			ssize = sizeof (in6_addr_t) * sctp->sctp_nsaddrs;
			slist = kmem_alloc(ssize, KM_SLEEP);
			flist = kmem_alloc(fsize, KM_SLEEP);
			/* The clustering module frees the lists */
			sctp_get_saddr_list(sctp, slist, ssize);
			sctp_get_faddr_list(sctp, flist, fsize);
			(*cl_sctp_connect)(connp->conn_family, slist,
			    sctp->sctp_nsaddrs, connp->conn_lport,
			    flist, sctp->sctp_nfaddrs, connp->conn_fport,
			    B_TRUE, (cl_sctp_handle_t)sctp);
		}
		ASSERT(ixa->ixa_cred != NULL);
		ASSERT(ixa->ixa_ire != NULL);

		(void) conn_ip_output(initmp, ixa);
		BUMP_LOCAL(sctp->sctp_opkts);
		WAKE_SCTP(sctp);

notify_ulp:
		sctp_set_ulp_prop(sctp);

		return (0);
	default:
		ip0dbg(("sctp_connect: invalid state. %d\n", sctp->sctp_state));
		WAKE_SCTP(sctp);
		return (EINVAL);
	}
}
예제 #10
0
/*
 * This is the IPv6 interface for "gethostbyaddr".
 */
struct hostent *
getipnodebyaddr(const void *src, size_t len, int type, int *error_num)
{
	struct in6_addr *addr6 = 0;
	struct in_addr *addr4 = 0;
	nss_XbyY_buf_t *buf = 0;
	nss_XbyY_buf_t *res = 0;
	struct netconfig *nconf;
	struct hostent *hp = 0;
	struct	nss_netdirbyaddr_in nssin;
	union	nss_netdirbyaddr_out nssout;
	int neterr;
	char tmpbuf[64];

	if (type == AF_INET6) {
		if ((addr6 = (struct in6_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else if (type == AF_INET) {
		if ((addr4 = (struct in_addr *)src) == NULL) {
			*error_num = HOST_NOT_FOUND;
			return (NULL);
		}
	} else {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Specific case: query for "::"
	 */
	if (type == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(addr6)) {
		*error_num = HOST_NOT_FOUND;
		return (NULL);
	}
	/*
	 * Step 1: IPv4-mapped address  or IPv4 Compat
	 */
	if ((type == AF_INET6 && len == 16) &&
	    ((IN6_IS_ADDR_V4MAPPED(addr6)) ||
	    (IN6_IS_ADDR_V4COMPAT(addr6)))) {
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			__IPv6_cleanup(buf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			(void) memcpy(tmpbuf, addr6, sizeof (*addr6));
			tmpbuf[10] = 0xffU;
			tmpbuf[11] = 0xffU;
			nssin.arg.nss.host.addr = (const char *)tmpbuf;
		} else {
			nssin.arg.nss.host.addr = (const char *)addr6;
		}
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			if (!gethostbyaddr_r(((char *)addr6) + 12,
			    sizeof (in_addr_t), AF_INET, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			/* Found one, now format it into mapped/compat addr */
			if ((res = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
				__IPv6_cleanup(buf);
				*error_num = NO_RECOVERY;
				return (NULL);
			}
			/* Convert IPv4 to mapped/compat address w/name */
			hp = res->result;
			(void) __mapv4tov6(buf->result, 0, res,
			    IN6_IS_ADDR_V4MAPPED(addr6));
			__IPv6_cleanup(buf);
			free(res);
			return (hp);
		}
		/*
		 * At this point, we'll have a v4mapped hostent. If that's
		 * what was passed in, just return. If the request was a compat,
		 * twiggle the two bytes to make the mapped address a compat.
		 */
		hp = buf->result;
		if (IN6_IS_ADDR_V4COMPAT(addr6)) {
			/* LINTED pointer cast */
			addr6 = (struct in6_addr *)hp->h_addr_list[0];
			addr6->s6_addr[10] = 0;
			addr6->s6_addr[11] = 0;
		}
		free(buf);
		return (hp);
	}
	/*
	 * Step 2: AF_INET, v4 lookup. Since we're going to search the
	 * ipnodes (v6) path first, we need to treat this as a v4mapped
	 * address. nscd(1m) caches v4 from ipnodes as mapped v6's. The
	 * switch backend knows to lookup v4's (not v4mapped) from the
	 * name services.
	 */
	if (type == AF_INET) {
		struct in6_addr v4mapbuf;
		addr6 = &v4mapbuf;

		IN6_INADDR_TO_V4MAPPED(addr4, addr6);
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = sizeof (struct in6_addr);
		nssin.arg.nss.host.type = AF_INET6;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			/* Failover case, try hosts db for v4 address */
			hp = buf->result;
			if (!gethostbyaddr_r(src, len, type, buf->result,
			    buf->buffer, buf->buflen, error_num)) {
				__IPv6_cleanup(buf);
				return (NULL);
			}
			free(buf);
			return (hp);
		}
		if ((hp = __mappedtov4(buf->result, error_num)) == NULL) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		__IPv6_cleanup(buf);
		return (hp);
	}
	/*
	 * Step 3: AF_INET6, plain vanilla v6 getipnodebyaddr() call.
	 */
	if (type == AF_INET6) {
		if ((nconf = __rpc_getconfip("udp")) == NULL &&
		    (nconf = __rpc_getconfip("tcp")) == NULL) {
			*error_num = NO_RECOVERY;
			return (NULL);
		}
		if ((buf = __IPv6_alloc(NSS_BUFLEN_IPNODES)) == 0) {
			*error_num = NO_RECOVERY;
			freenetconfigent(nconf);
			return (NULL);
		}
		nssin.op_t = NSS_HOST6;
		nssin.arg.nss.host.addr = (const char *)addr6;
		nssin.arg.nss.host.len = len;
		nssin.arg.nss.host.type = type;
		nssin.arg.nss.host.buf = buf->buffer;
		nssin.arg.nss.host.buflen = buf->buflen;

		nssout.nss.host.hent = buf->result;
		nssout.nss.host.herrno_p = error_num;
		/*
		 * We pass in nconf and let the implementation of the
		 * long-named func decide whether to use the switch based on
		 * nc_nlookups.
		 */
		neterr =
		    _get_hostserv_inetnetdir_byaddr(nconf, &nssin, &nssout);

		(void) freenetconfigent(nconf);
		if (neterr != ND_OK) {
			__IPv6_cleanup(buf);
			return (NULL);
		}
		free(buf);
		return (nssout.nss.host.hent);
	}
	/*
	 * If we got here, unknown type.
	 */
	*error_num = HOST_NOT_FOUND;
	return (NULL);
}
static NSS_STATUS
parse_response(int af, nss_XbyY_args_t* argp, struct winbindd_response *response)
{
	struct hostent *he = (struct hostent *)argp->buf.result;
	char *buffer = argp->buf.buffer;
	int buflen =  argp->buf.buflen;
	NSS_STATUS ret;

	char *p, *data;
	int addrcount = 0;
	int len = 0;
	struct in_addr *addrp;
#if defined(AF_INET6)
	struct in6_addr *addrp6;
#endif
	int i;

	/* response is tab separated list of ip addresses with hostname
	   and newline at the end. so at first we will strip newline
	   then construct list of addresses for hostent.
	*/
	p = strchr(response->data.winsresp, '\n');
	if(p) *p = '\0';
	else {/* it must be broken */
		argp->h_errno = NO_DATA;
		return NSS_STATUS_UNAVAIL;
	}

	for(; p != response->data.winsresp; p--) {
		if(*p == '\t') addrcount++;
	}

	if(addrcount == 0) {/* it must be broken */
		argp->h_errno = NO_DATA;
		return NSS_STATUS_UNAVAIL;
	}

	/* allocate space for addresses and h_addr_list */
	he->h_addrtype = af;
	if( he->h_addrtype == AF_INET) {
		he->h_length =  sizeof(struct in_addr);
		addrp = (struct in_addr *)ROUND_DOWN(buffer + buflen,
						sizeof(struct in_addr));
		addrp -= addrcount;
		he->h_addr_list = (char **)ROUND_DOWN(addrp, sizeof (char*));
		he->h_addr_list -= addrcount+1;
	}
#if defined(AF_INET6)
        else {
		he->h_length = sizeof(struct in6_addr);
		addrp6 = (struct in6_addr *)ROUND_DOWN(buffer + buflen,
						sizeof(struct in6_addr));
		addrp6 -= addrcount;
		he->h_addr_list = (char **)ROUND_DOWN(addrp6, sizeof (char*));
		he->h_addr_list -= addrcount+1;
	}
#endif

	/* buffer too small?! */
	if((char *)he->h_addr_list < buffer ) {
		argp->erange = 1;
		return NSS_STR_PARSE_ERANGE;
	}
	
	data = response->data.winsresp;
	for( i = 0; i < addrcount; i++) {
		p = strchr(data, '\t');
		if(p == NULL) break; /* just in case... */

		*p = '\0'; /* terminate the string */
		if(he->h_addrtype == AF_INET) {
		  he->h_addr_list[i] = (char *)&addrp[i];
		  if ((addrp[i].s_addr = inet_addr(data)) == -1) {
		    argp->erange = 1;
		    return NSS_STR_PARSE_ERANGE;
		  }
		}
#if defined(AF_INET6)
                else {
		  he->h_addr_list[i] = (char *)&addrp6[i];
		  if (strchr(data, ':') != 0) {
			if (inet_pton(AF_INET6, data, &addrp6[i]) != 1) {
			  argp->erange = 1;
			  return NSS_STR_PARSE_ERANGE;
			}
		  } else {
			struct in_addr in4;
			if ((in4.s_addr = inet_addr(data)) == -1) {
			  argp->erange = 1;
			  return NSS_STR_PARSE_ERANGE;
			}
			IN6_INADDR_TO_V4MAPPED(&in4, &addrp6[i]);
		  }
		}
#endif
		data = p+1;
	}

	he->h_addr_list[i] = (char *)NULL;

	len = strlen(data);
	if(len > he->h_addr_list - (char**)argp->buf.buffer) {
		argp->erange = 1;
		return NSS_STR_PARSE_ERANGE;
	}

	/* this is a bit overkill to use _nss_netdb_aliases here since
	   there seems to be no aliases but it will create all data for us */
	he->h_aliases = _nss_netdb_aliases(data, len, buffer,
				((char*) he->h_addr_list) - buffer);
	if(he->h_aliases == NULL) {
	    argp->erange = 1;
	    ret = NSS_STR_PARSE_ERANGE;
	} else {
	    he->h_name = he->h_aliases[0];
	    he->h_aliases++;
	    ret = NSS_STR_PARSE_SUCCESS;
	}

	argp->returnval = (void*)he;
	return ret;
}
예제 #12
0
dladm_status_t
do_check_ip_addr(char *addr_str, boolean_t local, flow_desc_t *fd)
{
	dladm_status_t	status;
	int		prefix_max, prefix_len = 0;
	char		*prefix_str, *endp = NULL;
	flow_mask_t	mask;
	in6_addr_t	*addr;
	uchar_t		*netmask;
	struct in_addr	v4addr;
	struct in6_addr	v6addr;
	int		family;

	if ((prefix_str = strchr(addr_str, '/')) != NULL) {
		*prefix_str++ = '\0';
		errno = 0;
		prefix_len = (int)strtol(prefix_str, &endp, 10);
		if (errno != 0 || prefix_len == 0 || *endp != '\0')
			return (DLADM_STATUS_INVALID_PREFIXLEN);
	}
	if (inet_pton(AF_INET, addr_str, &v4addr.s_addr) == 1) {
		family = AF_INET;
	} else if (inet_pton(AF_INET6, addr_str, v6addr.s6_addr) == 1) {
		family = AF_INET6;
	} else {
		return (DLADM_STATUS_INVALID_IP);
	}

	mask = FLOW_IP_VERSION;
	if (local) {
		mask |= FLOW_IP_LOCAL;
		addr = &fd->fd_local_addr;
		netmask = (uchar_t *)&fd->fd_local_netmask;
	} else {
		mask |= FLOW_IP_REMOTE;
		addr = &fd->fd_remote_addr;
		netmask = (uchar_t *)&fd->fd_remote_netmask;
	}

	if (family == AF_INET) {
		IN6_INADDR_TO_V4MAPPED(&v4addr, addr);
		prefix_max = IP_ABITS;
		fd->fd_ipversion = IPV4_VERSION;
		netmask = (uchar_t *)
		    &(V4_PART_OF_V6((*((in6_addr_t *)(void *)netmask))));
	} else {
		*addr = v6addr;
		prefix_max = IPV6_ABITS;
		fd->fd_ipversion = IPV6_VERSION;
	}

	if (prefix_len == 0)
		prefix_len = prefix_max;

	status = dladm_prefixlen2mask(prefix_len, prefix_max, netmask);

	if (status != DLADM_STATUS_OK) {
		return (DLADM_STATUS_INVALID_PREFIXLEN);
	}

	fd->fd_mask |= mask;
	return (DLADM_STATUS_OK);
}