Ejemplo n.º 1
0
static int inet_diag_bc_run(const struct nlattr *_bc,
			    const struct inet_diag_entry *entry)
{
	const void *bc = nla_data(_bc);
	int len = nla_len(_bc);

	while (len > 0) {
		int yes = 1;
		const struct inet_diag_bc_op *op = bc;

		switch (op->code) {
		case INET_DIAG_BC_NOP:
			break;
		case INET_DIAG_BC_JMP:
			yes = 0;
			break;
		case INET_DIAG_BC_S_GE:
			yes = entry->sport >= op[1].no;
			break;
		case INET_DIAG_BC_S_LE:
			yes = entry->sport <= op[1].no;
			break;
		case INET_DIAG_BC_D_GE:
			yes = entry->dport >= op[1].no;
			break;
		case INET_DIAG_BC_D_LE:
			yes = entry->dport <= op[1].no;
			break;
		case INET_DIAG_BC_AUTO:
			yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
			break;
		case INET_DIAG_BC_S_COND:
		case INET_DIAG_BC_D_COND: {
			const struct inet_diag_hostcond *cond;
			const __be32 *addr;

			cond = (const struct inet_diag_hostcond *)(op + 1);
			if (cond->port != -1 &&
			    cond->port != (op->code == INET_DIAG_BC_S_COND ?
					     entry->sport : entry->dport)) {
				yes = 0;
				break;
			}

			if (op->code == INET_DIAG_BC_S_COND)
				addr = entry->saddr;
			else
				addr = entry->daddr;

			if (cond->family != AF_UNSPEC &&
			    cond->family != entry->family) {
				if (entry->family == AF_INET6 &&
				    cond->family == AF_INET) {
					if (addr[0] == 0 && addr[1] == 0 &&
					    addr[2] == htonl(0xffff) &&
					    bitstring_match(addr + 3,
							    cond->addr,
							    cond->prefix_len))
						break;
				}
				yes = 0;
				break;
			}

			if (cond->prefix_len == 0)
				break;
			if (bitstring_match(addr, cond->addr,
					    cond->prefix_len))
				break;
			yes = 0;
			break;
		}
		}

		if (yes) {
			len -= op->yes;
			bc += op->yes;
		} else {
			len -= op->no;
			bc += op->no;
		}
	}
	return len == 0;
}
Ejemplo n.º 2
0
int tcpdiag_bc_run(char *bc, int len, struct sock *sk)
{
	while (len > 0) {
		int yes = 1;
		struct tcpdiag_bc_op *op = (struct tcpdiag_bc_op*)bc;

		switch (op->code) {
		case TCPDIAG_BC_NOP:
			break;
		case TCPDIAG_BC_JMP:
			yes = 0;
			break;
		case TCPDIAG_BC_S_GE:
			yes = (sk->num >= op[1].no);
			break;
		case TCPDIAG_BC_S_LE:
			yes = (sk->num <= op[1].no);
			break;
		case TCPDIAG_BC_D_GE:
			yes = (ntohs(sk->dport) >= op[1].no);
			break;
		case TCPDIAG_BC_D_LE:
			yes = (ntohs(sk->dport) <= op[1].no);
			break;
		case TCPDIAG_BC_AUTO:
			yes = !(sk->userlocks&SOCK_BINDPORT_LOCK);
			break;
		case TCPDIAG_BC_S_COND:
		case TCPDIAG_BC_D_COND:
		{
			struct tcpdiag_hostcond *cond = (struct tcpdiag_hostcond*)(op+1);
			u32 *addr;

			if (cond->port != -1 &&
			    cond->port != (op->code == TCPDIAG_BC_S_COND ? sk->num : ntohs(sk->dport))) {
				yes = 0;
				break;
			}
			
			if (cond->prefix_len == 0)
				break;

#ifdef CONFIG_IPV6
			if (sk->family == AF_INET6) {
				if (op->code == TCPDIAG_BC_S_COND)
					addr = (u32*)&sk->net_pinfo.af_inet6.rcv_saddr;
				else
					addr = (u32*)&sk->net_pinfo.af_inet6.daddr;
			} else
#endif
			{
				if (op->code == TCPDIAG_BC_S_COND)
					addr = &sk->rcv_saddr;
				else
					addr = &sk->daddr;
			}

			if (bitstring_match(addr, cond->addr, cond->prefix_len))
				break;
			if (sk->family == AF_INET6 && cond->family == AF_INET) {
				if (addr[0] == 0 && addr[1] == 0 &&
				    addr[2] == __constant_htonl(0xffff) &&
				    bitstring_match(addr+3, cond->addr, cond->prefix_len))
					break;
			}
			yes = 0;
			break;
		}
		}

		if (yes) { 
			len -= op->yes;
			bc += op->yes;
		} else {
			len -= op->no;
			bc += op->no;
		}
	}
	return (len == 0);
}