Пример #1
0
/*
 * Checks whether the tuple is complete. If not, marks the pcb for
 * late binding.
 */
static bool
iscompletetuple(struct inpcb_hdr *inp_hdr)
{
#ifdef INET6
	struct in6pcb *in6p;
#endif

	switch (inp_hdr->inph_af) {
#ifdef INET
	case AF_INET: {
		struct inpcb *inp = (struct inpcb *)(void *)inp_hdr;
		if (inp->inp_fport == 0 || in_nullhost(inp->inp_faddr)) {
			DPRINTF("%s fport or faddr missing, delaying port "
			    "to connect/send\n", __func__);
			inp->inp_bindportonsend = true;
			return false;
		} else {
			inp->inp_bindportonsend = false;
		}
		break;
	}
#endif
#ifdef INET6
	case AF_INET6: {
		in6p = (struct in6pcb *)(void *)inp_hdr;
		if (in6p->in6p_fport == 0 || memcmp(&in6p->in6p_faddr,
		    &in6addr_any, sizeof(in6p->in6p_faddr)) == 0) {
			DPRINTF("%s fport or faddr missing, delaying port "
			    "to connect/send\n", __func__);
			in6p->in6p_bindportonsend = true;
			return false;
		} else {
			in6p->in6p_bindportonsend = false;
		}
		break;
	}
#endif
	default:
		DPRINTF("%s incorrect address family\n", __func__);
		return false;
	}

	return true;
}
Пример #2
0
static int
dump_table_entry(struct radix_node *rn, void *arg)
{
	struct table_entry * const n = (struct table_entry *)rn;
	ipfw_table * const tbl = arg;
	ipfw_table_entry *ent;

	if (tbl->cnt == tbl->size)
		return (1);
	ent = &tbl->ent[tbl->cnt];
	ent->tbl = tbl->tbl;
	if (in_nullhost(n->mask.sin_addr))
		ent->masklen = 0;
	else
		ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
	ent->addr = n->addr.sin_addr.s_addr;
	ent->value = n->value;
	tbl->cnt++;
	return (0);
}
Пример #3
0
int
in_pcbbind(void *v, struct mbuf *nam)
{
	struct inpcb *inp = v;
	struct sockaddr_in *sin = NULL; /* XXXGCC */
	struct sockaddr_in lsin;
	int error;

	if (inp->inp_af != AF_INET)
		return (EINVAL);

	if (TAILQ_FIRST(&in_ifaddrhead) == 0)
		return (EADDRNOTAVAIL);
	if (inp->inp_lport || !in_nullhost(inp->inp_laddr))
		return (EINVAL);

	if (nam != NULL) {
		sin = mtod(nam, struct sockaddr_in *);
		if (nam->m_len != sizeof (*sin))
			return (EINVAL);
	} else {
Пример #4
0
static int
dump_table_xentry_base(struct radix_node *rn, void *arg)
{
	struct table_entry * const n = (struct table_entry *)rn;
	ipfw_xtable * const tbl = arg;
	ipfw_table_xentry *xent;

	/* Out of memory, returning */
	if (tbl->cnt == tbl->size)
		return (1);
	xent = &tbl->xent[tbl->cnt];
	xent->len = sizeof(ipfw_table_xentry);
	xent->tbl = tbl->tbl;
	if (in_nullhost(n->mask.sin_addr))
		xent->masklen = 0;
	else
		xent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr));
	/* Save IPv4 address as deprecated IPv6 compatible */
	xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
	xent->value = n->value;
	tbl->cnt++;
	return (0);
}
Пример #5
0
static int
in_pcbbind_addr(struct inpcb *inp, struct sockaddr_in *sin)
{
	if (sin->sin_family != AF_INET)
		return (EAFNOSUPPORT);

	if (IN_MULTICAST(sin->sin_addr.s_addr)) {
		/* Always succeed; port reuse handled in in_pcbbind_port(). */
	} else if (!in_nullhost(sin->sin_addr)) {
		struct in_ifaddr *ia = NULL;

		INADDR_TO_IA(sin->sin_addr, ia);
		/* check for broadcast addresses */
		if (ia == NULL)
			ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
		if (ia == NULL)
			return (EADDRNOTAVAIL);
	}

	inp->inp_laddr = sin->sin_addr;

	return (0);
}
Пример #6
0
static int
in_pcbbind_port(struct inpcb *inp, struct sockaddr_in *sin)
{
	struct inpcbtable *table = inp->inp_table;
	struct socket *so = inp->inp_socket;
	int reuseport = (so->so_options & SO_REUSEPORT);
	int wild = 0, error;

	if (IN_MULTICAST(sin->sin_addr.s_addr)) {
		/*
		 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
		 * allow complete duplication of binding if
		 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
		 * and a multicast address is bound on both
		 * new and duplicated sockets.
		 */
		if (so->so_options & SO_REUSEADDR)
			reuseport = SO_REUSEADDR|SO_REUSEPORT;
	} 

	if (sin->sin_port == 0) {
		error = in_pcbsetport(sin, inp);
		if (error)
			return (error);
	} else {
		struct inpcb *t;
		vestigial_inpcb_t vestige;
#ifdef INET6
		struct in6pcb *t6;
		struct in6_addr mapped;
#endif
		//enum kauth_network_req req;

		if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
			wild = 1;

#ifndef IPNOPRIVPORTS
//		if (ntohs(sin->sin_port) < IPPORT_RESERVED)
//			req = KAUTH_REQ_NETWORK_BIND_PRIVPORT;
//		else
#endif /* !IPNOPRIVPORTS */
//			req = KAUTH_REQ_NETWORK_BIND_PORT;

//		error = kauth_authorize_network(cred, KAUTH_NETWORK_BIND, req,
//		    so, sin, NULL);
//		if (error)
//			return (EACCES);

#ifdef INET6
		memset(&mapped, 0, sizeof(mapped));
		mapped.s6_addr16[5] = 0xffff;
		memcpy(&mapped.s6_addr32[3], &sin->sin_addr,
		    sizeof(mapped.s6_addr32[3]));
		t6 = in6_pcblookup_port(table, &mapped, sin->sin_port, wild, &vestige);
		if (t6 && (reuseport & t6->in6p_socket->so_options) == 0)
			return (EADDRINUSE);
		if (!t6 && vestige.valid) {
		    if (!!reuseport != !!vestige.reuse_port) {
			return EADDRINUSE;
		    }
		}
#endif
#if 0 /* VADIM - disabled*/
		/* XXX-kauth */
		if (so->so_uidinfo->ui_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
			t = in_pcblookup_port(table, sin->sin_addr, sin->sin_port, 1, &vestige);
			/*
			 * XXX:	investigate ramifications of loosening this
			 *	restriction so that as long as both ports have
			 *	SO_REUSEPORT allow the bind
			 */
			if (t &&
			    (!in_nullhost(sin->sin_addr) ||
			     !in_nullhost(t->inp_laddr) ||
			     (t->inp_socket->so_options & SO_REUSEPORT) == 0)
			    && (so->so_uidinfo->ui_uid != t->inp_socket->so_uidinfo->ui_uid)) {
				return (EADDRINUSE);
			}

			if (!t && vestige.valid) {
				if ((!in_nullhost(sin->sin_addr)
				     || !in_nullhost(vestige.laddr.v4)
				     || !vestige.reuse_port)
				    && so->so_uidinfo->ui_uid != vestige.uid) {
					return EADDRINUSE;
				}
			}

		}
#endif
		t = in_pcblookup_port(table, sin->sin_addr, sin->sin_port, wild, &vestige);
		if (t && (reuseport & t->inp_socket->so_options) == 0)
			return (EADDRINUSE);
		if (!t
		    && vestige.valid
		    && !(reuseport && vestige.reuse_port))
			return EADDRINUSE;

		inp->inp_lport = sin->sin_port;
		in_pcbstate(inp, INP_BOUND);
	}

	LIST_REMOVE(&inp->inp_head, inph_lhash);
	LIST_INSERT_HEAD(INPCBHASH_PORT(table, inp->inp_lport), &inp->inp_head,
	    inph_lhash);

	return (0);
}