Beispiel #1
0
/**
 * Parse a Linux connection table (/proc/net/tcp or /proc/net/udp) and filter
 * connection: only keep session user connections in state "SYN packet sent".
 * Add connections to the our table using tcptable_add().
 */
int parse_tcptable_file(nuauth_session_t * session, conntable_t * ct, char *filename,
			FILE ** file, int protocol, int use_ipv6)
{
	char *buf;
	char fullbuf[1024*256];
	conn_t c;
	const char state_char = '2';	/* TCP_SYN_SENT written in hexadecimal */
	int state_pos;
	int uid_pos;
	char session_uid[20];
	int session_uid_len;
	int ret;
	char *pos;
	int fdfile;
	int i = 0;
	int readlen = 0;

	fdfile = open(filename, O_RDONLY);
	if (fdfile == -1) {
		panic("Unable to open proc file");
	}
	/* read all file */
	buf = fullbuf;
	while ( ((1024*256 - (buf - fullbuf)) > 0) &&
		(i = read(fdfile, buf, 1024*256 - (buf - fullbuf)))) {
		buf += i;
		readlen += i;
	}
	close(fdfile);

	/* convert session user identifier to string */
	secure_snprintf(session_uid, sizeof(session_uid), "%5lu",
			(long)session->userid);
	session_uid_len = strlen(session_uid);

	/* get state field position in header */
	pos = strstr(fullbuf, " st ");
	if (pos == NULL)
		panic
		    ("Can't find position of state field in /proc/net/tcp header!");
	state_pos = pos - fullbuf + 2;

	/* get user identifier position in header (it's just after 'retrnsmt' field) */
	pos = strstr(fullbuf, " retrnsmt ");
	if (pos == NULL)
		panic
		    ("Can't find position of user identifier field in /proc/net/tcp header!");
	uid_pos = pos - fullbuf + strlen(" retrnsmt ");

	buf = fullbuf;
	while (buf - fullbuf < readlen - uid_pos) {

		buf = strchr(buf, '\n') + 1;
		/* only keep connections in state "SYN packet sent" */
		if (buf[state_pos] != state_char) {
			continue;
		}

		/* only keep session user connections */
		if (strncmp(buf + uid_pos, session_uid, session_uid_len) !=
		    0) {
			continue;
		}

		/* get all fields */
		if (!use_ipv6) {
			uint32_t src, dst;
			ret = sscanf(buf,
				     "%*d: "
				     "%" SCNx32 ":%hx "
				     "%" SCNx32 ":%hx "
				     "%*x %*x:%*x %*x:%*x %x "
				     "%lu %*d %lu",
				     &src, &c.port_src,
				     &dst, &c.port_dst,
				     &c.retransmit, &c.uid,
				     &c.inode);
			if (ret != 7) {
				continue;
			}
			uint32_to_ipv6(src, &c.ip_src);
			uint32_to_ipv6(dst, &c.ip_dst);
		} else {
			char ip_src[33];
			char ip_dst[33];
			ret = sscanf(buf,
				     "%*d: "
				     "%32s"
				     ":%hx "
				     "%32s"
				     ":%hx "
				     "%*x %*x:%*x %*x:%*x %x "
				     "%lu %*d %lu",
				     ip_src,
				     &c.port_src,
				     ip_dst,
				     &c.port_dst,
				     &c.retransmit, &c.uid, &c.inode);
			if (ret != 7) {
				continue;
			}
			if (!hex2ipv6(ip_src, &c.ip_src))
				continue;
			if (!hex2ipv6(ip_dst, &c.ip_dst))
				continue;
		}

		/* skip nul inodes */
		if (c.inode == 0) {
			continue;
		}
#if DEBUG
		/*  Check if there is a matching rule in the filters list */
		printf("Packet dst = %ld (%lx)\n", c.rmt, c.rmt);
#endif

		c.protocol = protocol;
		tcptable_add(ct, &c);
	}
	return 1;
}
Beispiel #2
0
static int ip2bin(struct ulogd_key* inp, int index, int oindex)
{
	char family = ikey_get_u8(&inp[KEY_OOB_FAMILY]);
	char convfamily = family;
	unsigned char *addr8;
	struct in6_addr *addr;
	struct in6_addr ip4_addr;
	char *buffer;
	int i, written;

	if (family == AF_BRIDGE) {
		if (!pp_is_valid(inp, KEY_OOB_PROTOCOL)) {
			ulogd_log(ULOGD_NOTICE,
				  "No protocol inside AF_BRIDGE packet\n");
			return ULOGD_IRET_ERR;
		}
		switch (ikey_get_u16(&inp[KEY_OOB_PROTOCOL])) {
		case ETH_P_IPV6:
			convfamily = AF_INET6;
			break;
		case ETH_P_IP:
			convfamily = AF_INET;
			break;
		case ETH_P_ARP:
			convfamily = AF_INET;
			break;
		default:
			ulogd_log(ULOGD_NOTICE,
				  "Unknown protocol inside AF_BRIDGE packet\n");
			return ULOGD_IRET_ERR;
		}
	}

	switch (convfamily) {
		case AF_INET6:
			addr = (struct in6_addr *)ikey_get_u128(&inp[index]);
			break;
		case AF_INET:
			/* Convert IPv4 to IPv4 in IPv6 */
			addr = &ip4_addr;
			uint32_to_ipv6(ikey_get_u32(&inp[index]), addr);
			break;
		default:
			/* TODO handle error */
			ulogd_log(ULOGD_NOTICE, "Unknown protocol family\n");
			return ULOGD_IRET_ERR;
	}

	buffer = ipbin_array[oindex];
	/* format IPv6 to BINARY(16) as "0x..." */
	buffer[0] = '0';
	buffer[1] = 'x';
	buffer += 2;
	addr8 = &addr->s6_addr[0];
	for (i = 0; i < 4; i++) {
		written = sprintf(buffer, "%02x%02x%02x%02x",
				addr8[0], addr8[1], addr8[2], addr8[3]);
		if (written != 2 * 4) {
			buffer[0] = 0;
			return ULOGD_IRET_ERR;
		}
		buffer += written;
		addr8 += 4;
	}
	buffer[0] = 0;

	return ULOGD_IRET_OK;
}
Beispiel #3
0
/**
 * On Linux: Parse connection table /proc/net/tcp and /proc/net/udp to get
 * connections in state "SYN sent" from session user.
 *
 * On FreeBSD: Use sysctl with "net.inet.tcp.pcblist" to get the connection
 * table. Add connections to the our table using tcptable_add().
 */
int tcptable_read(nuauth_session_t * session, conntable_t * ct)
{
#ifdef LINUX
	static FILE *fd_tcp = NULL;
	static FILE *fd_udp = NULL;

#ifdef IPV6
	static FILE *fd_tcp6 = NULL;
#endif

#if DEBUG
	assert(ct != NULL);
	assert(TCP_SYN_SENT == 2);
#endif
	if (!parse_tcptable_file
	    (session, ct, "/proc/net/tcp", &fd_tcp, IPPROTO_TCP, 0))
		return 0;

#ifdef IPV6
	parse_tcptable_file(session, ct, "/proc/net/tcp6", &fd_tcp6,
			    IPPROTO_TCP, 1);
#endif

	if (!parse_tcptable_file
	    (session, ct, "/proc/net/udp", &fd_udp, IPPROTO_UDP, 0))
		return 0;
	return 1;
#elif defined(FREEBSD)
	conn_t c;
	int istcp;
	char *buf;
	const char *mibvar;
	struct tcpcb *tp = NULL;
	struct inpcb *inp;
	struct xinpgen *xig, *oxig;
	struct xsocket *so;
	size_t len;
	int proto = IPPROTO_TCP;
#if 0
	istcp = 0;
	switch (proto) {
	case IPPROTO_TCP:
#endif
		istcp = 1;
		mibvar = "net.inet.tcp.pcblist";
#if 0
		break;
	case IPPROTO_UDP:
		mibvar = "net.inet.udp.pcblist";
		break;
	}
#endif
	/* get connection table size, and then allocate a buffer */
	len = 0;
	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
		if (errno != ENOENT)
			printf("sysctl: %s", mibvar);
		return 0;
	}
	buf = malloc(len);
	if (buf == NULL) {
		printf("malloc %lu bytes", (u_long) len);
		return 0;
	}

	/* read connection table */
	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
		printf("sysctl: %s", mibvar);
		free(buf);
		return 0;
	}

	oxig = xig = (struct xinpgen *) buf;
	for (xig = (struct xinpgen *) ((char *) xig + xig->xig_len);
	     xig->xig_len > sizeof(struct xinpgen);
	     xig = (struct xinpgen *) ((char *) xig + xig->xig_len)) {
		if (istcp) {
			tp = &((struct xtcpcb *) xig)->xt_tp;
			inp = &((struct xtcpcb *) xig)->xt_inp;
			so = &((struct xtcpcb *) xig)->xt_socket;
		} else {
			inp = &((struct xinpcb *) xig)->xi_inp;
			so = &((struct xinpcb *) xig)->xi_socket;
		}

		/* Ignore sockets for protocols other than the desired one. */
		if (so->xso_protocol != (int) proto)
			continue;

		/* Ignore PCBs which were freed during copyout. */
		if (inp->inp_gencnt > oxig->xig_gen)
			continue;

		/* only do IPV4 for now */
		if ((inp->inp_vflag & INP_IPV4) == 0)
			continue;

		/* check SYN_SENT and get rid of NULL address */
		if ((istcp && tp->t_state != TCPS_SYN_SENT)
		    || (inet_lnaof(inp->inp_laddr) == INADDR_ANY))
			continue;

		uint32_to_ipv6(inp->inp_laddr.s_addr, &c.ip_src);
		c.port_src = ntohs(inp->inp_lport);

		uint32_to_ipv6(inp->inp_faddr.s_addr, &c.ip_dst);
		c.port_dst = ntohs(inp->inp_fport);
		c.protocol = IPPROTO_TCP;

		tcptable_add(ct, &c);
	}
	free(buf);
	return 1;
#endif
}