static void
gather_inet(int proto)
{
	struct xinpgen *xig, *exig;
	struct xinpcb *xip;
	struct xtcpcb *xtp;
	struct inpcb *inp;
	struct xsocket *so;
	struct sock *sock;
	const char *varname, *protoname;
	size_t len, bufsize;
	void *buf;
	int hash, retry, vflag;

	vflag = 0;
	if (opt_4)
		vflag |= INP_IPV4;
	if (opt_6)
		vflag |= INP_IPV6;

	switch (proto) {
	case IPPROTO_TCP:
		varname = "net.inet.tcp.pcblist";
		protoname = "tcp";
		break;
	case IPPROTO_UDP:
		varname = "net.inet.udp.pcblist";
		protoname = "udp";
		break;
	case IPPROTO_DIVERT:
		varname = "net.inet.divert.pcblist";
		protoname = "div";
		break;
	default:
		errx(1, "protocol %d not supported", proto);
	}

	buf = NULL;
	bufsize = 8192;
	retry = 5;
	do {
		for (;;) {
			if ((buf = realloc(buf, bufsize)) == NULL)
				err(1, "realloc()");
			len = bufsize;
			if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
				break;
			if (errno == ENOENT)
				goto out;
			if (errno != ENOMEM || len != bufsize)
				err(1, "sysctlbyname()");
			bufsize *= 2;
		}
		xig = (struct xinpgen *)buf;
		exig = (struct xinpgen *)(void *)
		    ((char *)buf + len - sizeof *exig);
		if (xig->xig_len != sizeof *xig ||
		    exig->xig_len != sizeof *exig)
			errx(1, "struct xinpgen size mismatch");
	} while (xig->xig_gen != exig->xig_gen && retry--);

	if (xig->xig_gen != exig->xig_gen && opt_v)
		warnx("warning: data may be inconsistent");

	for (;;) {
		xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
		if (xig >= exig)
			break;
		switch (proto) {
		case IPPROTO_TCP:
			xtp = (struct xtcpcb *)xig;
			if (xtp->xt_len != sizeof *xtp) {
				warnx("struct xtcpcb size mismatch");
				goto out;
			}
			inp = &xtp->xt_inp;
			so = &xtp->xt_socket;
			protoname = xtp->xt_tp.t_flags & TF_TOE ? "toe" : "tcp";
			break;
		case IPPROTO_UDP:
		case IPPROTO_DIVERT:
			xip = (struct xinpcb *)xig;
			if (xip->xi_len != sizeof *xip) {
				warnx("struct xinpcb size mismatch");
				goto out;
			}
			inp = &xip->xi_inp;
			so = &xip->xi_socket;
			break;
		default:
			errx(1, "protocol %d not supported", proto);
		}
		if ((inp->inp_vflag & vflag) == 0)
			continue;
		if (inp->inp_vflag & INP_IPV4) {
			if ((inp->inp_fport == 0 && !opt_l) ||
			    (inp->inp_fport != 0 && !opt_c))
				continue;
#define __IN_IS_ADDR_LOOPBACK(pina) \
	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
			if (opt_L &&
			    (__IN_IS_ADDR_LOOPBACK(&inp->inp_faddr) ||
			     __IN_IS_ADDR_LOOPBACK(&inp->inp_laddr)))
				continue;
#undef __IN_IS_ADDR_LOOPBACK
		} else if (inp->inp_vflag & INP_IPV6) {
			if ((inp->inp_fport == 0 && !opt_l) ||
			    (inp->inp_fport != 0 && !opt_c))
				continue;
			if (opt_L &&
			    (IN6_IS_ADDR_LOOPBACK(&inp->in6p_faddr) ||
			     IN6_IS_ADDR_LOOPBACK(&inp->in6p_laddr)))
				continue;
		} else {
			if (opt_v)
				warnx("invalid vflag 0x%x", inp->inp_vflag);
			continue;
		}
		if ((sock = (struct sock *)calloc(1, sizeof *sock)) == NULL)
			err(1, "malloc()");
		sock->socket = so->xso_so;
		sock->proto = proto;
		if (inp->inp_vflag & INP_IPV4) {
			sock->family = AF_INET;
			sockaddr(&sock->laddr, sock->family,
			    &inp->inp_laddr, inp->inp_lport);
			sockaddr(&sock->faddr, sock->family,
			    &inp->inp_faddr, inp->inp_fport);
		} else if (inp->inp_vflag & INP_IPV6) {
			sock->family = AF_INET6;
			sockaddr(&sock->laddr, sock->family,
			    &inp->in6p_laddr, inp->inp_lport);
			sockaddr(&sock->faddr, sock->family,
			    &inp->in6p_faddr, inp->inp_fport);
		}
		sock->vflag = inp->inp_vflag;
		sock->protoname = protoname;
		hash = (int)((uintptr_t)sock->socket % HASHSIZE);
		sock->next = sockhash[hash];
		sockhash[hash] = sock;
	}
out:
	free(buf);
}
예제 #2
0
파일: sockstat.c 프로젝트: frlen/freebsd
static void
gather_sctp(void)
{
	struct sock *sock;
	struct addr *laddr, *prev_laddr, *faddr, *prev_faddr;
	struct xsctp_inpcb *xinpcb;
	struct xsctp_tcb *xstcb;
	struct xsctp_raddr *xraddr;
	struct xsctp_laddr *xladdr;
	const char *varname;
	size_t len, offset;
	char *buf;
	int hash, vflag;
	int no_stcb, local_all_loopback, foreign_all_loopback;

	vflag = 0;
	if (opt_4)
		vflag |= INP_IPV4;
	if (opt_6)
		vflag |= INP_IPV6;

	varname = "net.inet.sctp.assoclist";
	if (sysctlbyname(varname, 0, &len, 0, 0) < 0) {
		if (errno != ENOENT)
			err(1, "sysctlbyname()");
		return;
	}
	if ((buf = (char *)malloc(len)) == NULL) {
		err(1, "malloc()");
		return;
	}
	if (sysctlbyname(varname, buf, &len, 0, 0) < 0) {
		err(1, "sysctlbyname()");
		free(buf);
		return;
	}
	xinpcb = (struct xsctp_inpcb *)(void *)buf;
	offset = sizeof(struct xsctp_inpcb);
	while ((offset < len) && (xinpcb->last == 0)) {
		if ((sock = calloc(1, sizeof *sock)) == NULL)
			err(1, "malloc()");
		sock->socket = xinpcb->socket;
		sock->proto = IPPROTO_SCTP;
		sock->protoname = "sctp";
		if (xinpcb->flags & SCTP_PCB_FLAGS_UNBOUND)
			sock->state = SCTP_CLOSED;
		else if (xinpcb->maxqlen == 0)
			sock->state = SCTP_BOUND;
		else
			sock->state = SCTP_LISTEN;
		if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) {
			sock->family = AF_INET6;
			sock->vflag = INP_IPV6;
		} else {
			sock->family = AF_INET;
			sock->vflag = INP_IPV4;
		}
		prev_laddr = NULL;
		local_all_loopback = 1;
		while (offset < len) {
			xladdr = (struct xsctp_laddr *)(void *)(buf + offset);
			offset += sizeof(struct xsctp_laddr);
			if (xladdr->last == 1)
				break;
			if ((laddr = calloc(1, sizeof(struct addr))) == NULL)
				err(1, "malloc()");
			switch (xladdr->address.sa.sa_family) {
			case AF_INET:
#define __IN_IS_ADDR_LOOPBACK(pina) \
	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
				if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr))
					local_all_loopback = 0;
#undef __IN_IS_ADDR_LOOPBACK
				sockaddr(&laddr->address,
				         AF_INET,
				         &xladdr->address.sin.sin_addr,
				         htons(xinpcb->local_port));
				break;
			case AF_INET6:
				if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr))
					local_all_loopback = 0;
				sockaddr(&laddr->address,
				         AF_INET6,
				         &xladdr->address.sin6.sin6_addr,
				         htons(xinpcb->local_port));
				break;
			default:
				errx(1, "adress family %d not supported",
				     xladdr->address.sa.sa_family);
			}
			laddr->next = NULL;
			if (prev_laddr == NULL)
				sock->laddr = laddr;
			else
				prev_laddr->next = laddr;
			prev_laddr = laddr;
		}
		if (sock->laddr == NULL) {
			if ((sock->laddr = calloc(1, sizeof(struct addr))) == NULL)
				err(1, "malloc()");
			sock->laddr->address.ss_family = sock->family;
			if (sock->family == AF_INET)
				sock->laddr->address.ss_len = sizeof(struct sockaddr_in);
			else
				sock->laddr->address.ss_len = sizeof(struct sockaddr_in);
			local_all_loopback = 0;
		}
		if ((sock->faddr = calloc(1, sizeof(struct addr))) == NULL)
			err(1, "malloc()");
		sock->faddr->address.ss_family = sock->family;
		if (sock->family == AF_INET)
			sock->faddr->address.ss_len = sizeof(struct sockaddr_in);
		else
			sock->faddr->address.ss_len = sizeof(struct sockaddr_in);
		no_stcb = 1;
		while (offset < len) {
			xstcb = (struct xsctp_tcb *)(void *)(buf + offset);
			offset += sizeof(struct xsctp_tcb);
			if (no_stcb) {
				if (opt_l &&
				    (!opt_L || !local_all_loopback) &&
				    ((xinpcb->flags & SCTP_PCB_FLAGS_UDPTYPE) ||
				     (xstcb->last == 1))) {
					hash = (int)((uintptr_t)sock->socket % HASHSIZE);
					sock->next = sockhash[hash];
					sockhash[hash] = sock;
				} else {
					free_socket(sock);
				}
			}
			if (xstcb->last == 1)
				break;
			no_stcb = 0;
			if (opt_c) {
				if ((sock = calloc(1, sizeof *sock)) == NULL)
					err(1, "malloc()");
				sock->socket = xinpcb->socket;
				sock->proto = IPPROTO_SCTP;
				sock->protoname = "sctp";
				sock->state = (int)xstcb->state;
				if (xinpcb->flags & SCTP_PCB_FLAGS_BOUND_V6) {
					sock->family = AF_INET6;
					sock->vflag = INP_IPV6;
				} else {
					sock->family = AF_INET;
					sock->vflag = INP_IPV4;
				}
			}
			prev_laddr = NULL;
			local_all_loopback = 1;
			while (offset < len) {
				xladdr = (struct xsctp_laddr *)(void *)(buf + offset);
				offset += sizeof(struct xsctp_laddr);
				if (xladdr->last == 1)
					break;
				if (!opt_c)
					continue;
				if ((laddr = calloc(1, sizeof(struct addr))) == NULL)
					err(1, "malloc()");
				switch (xladdr->address.sa.sa_family) {
				case AF_INET:
#define __IN_IS_ADDR_LOOPBACK(pina) \
	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
					if (!__IN_IS_ADDR_LOOPBACK(&xladdr->address.sin.sin_addr))
						local_all_loopback = 0;
#undef __IN_IS_ADDR_LOOPBACK
					sockaddr(&laddr->address,
						 AF_INET,
						 &xladdr->address.sin.sin_addr,
						 htons(xstcb->local_port));
					break;
				case AF_INET6:
					if (!IN6_IS_ADDR_LOOPBACK(&xladdr->address.sin6.sin6_addr))
						local_all_loopback = 0;
					sockaddr(&laddr->address,
						 AF_INET6,
						 &xladdr->address.sin6.sin6_addr,
						 htons(xstcb->local_port));
					break;
				default:
					errx(1, "adress family %d not supported",
					     xladdr->address.sa.sa_family);
				}
				laddr->next = NULL;
				if (prev_laddr == NULL)
					sock->laddr = laddr;
				else
					prev_laddr->next = laddr;
				prev_laddr = laddr;
			}
			prev_faddr = NULL;
			foreign_all_loopback = 1;
			while (offset < len) {
				xraddr = (struct xsctp_raddr *)(void *)(buf + offset);
				offset += sizeof(struct xsctp_raddr);
				if (xraddr->last == 1)
					break;
				if (!opt_c)
					continue;
				if ((faddr = calloc(1, sizeof(struct addr))) == NULL)
					err(1, "malloc()");
				switch (xraddr->address.sa.sa_family) {
				case AF_INET:
#define __IN_IS_ADDR_LOOPBACK(pina) \
	((ntohl((pina)->s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)
					if (!__IN_IS_ADDR_LOOPBACK(&xraddr->address.sin.sin_addr))
						foreign_all_loopback = 0;
#undef __IN_IS_ADDR_LOOPBACK
					sockaddr(&faddr->address,
						 AF_INET,
						 &xraddr->address.sin.sin_addr,
						 htons(xstcb->remote_port));
					break;
				case AF_INET6:
					if (!IN6_IS_ADDR_LOOPBACK(&xraddr->address.sin6.sin6_addr))
						foreign_all_loopback = 0;
					sockaddr(&faddr->address,
						 AF_INET6,
						 &xraddr->address.sin6.sin6_addr,
						 htons(xstcb->remote_port));
					break;
				default:
					errx(1, "adress family %d not supported",
					     xraddr->address.sa.sa_family);
				}
				faddr->next = NULL;
				if (prev_faddr == NULL)
					sock->faddr = faddr;
				else
					prev_faddr->next = faddr;
				prev_faddr = faddr;
			}
			if (opt_c) {
				if (!opt_L || !(local_all_loopback || foreign_all_loopback)) {
					hash = (int)((uintptr_t)sock->socket % HASHSIZE);
					sock->next = sockhash[hash];
					sockhash[hash] = sock;
				} else {
					free_socket(sock);
				}
			}
		}
		xinpcb = (struct xsctp_inpcb *)(void *)(buf + offset);
		offset += sizeof(struct xsctp_inpcb);
	}
	free(buf);
}