/* * 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; }
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); }
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 {
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); }
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); }
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); }