Ejemplo n.º 1
0
/*
 * Return a held reference to the default SP.
 */
static struct secpolicy *
key_allocsp_default(void)
{

	key_addref(V_def_policy);
	return (V_def_policy);
}
Ejemplo n.º 2
0
static struct secpolicy *
ipsec_getpcbpolicy(struct inpcb *inp, u_int dir)
{
	struct secpolicy *sp;
	int flags, downgrade;

	if (inp == NULL || inp->inp_sp == NULL)
		return (NULL);

	INP_LOCK_ASSERT(inp);

	flags = inp->inp_sp->flags;
	if (dir == IPSEC_DIR_OUTBOUND) {
		sp = inp->inp_sp->sp_out;
		flags &= INP_OUTBOUND_POLICY;
	} else {
		sp = inp->inp_sp->sp_in;
		flags &= INP_INBOUND_POLICY;
	}
	/*
	 * Check flags. If we have PCB SP, just return it.
	 * Otherwise we need to check that cached SP entry isn't stale.
	 */
	if (flags == 0) {
		if (sp == NULL)
			return (NULL);
		if (inp->inp_sp->genid != key_getspgen()) {
			/* Invalidate the cache. */
			downgrade = 0;
			if (!INP_WLOCKED(inp)) {
				if ((downgrade = INP_TRY_UPGRADE(inp)) == 0)
					return (NULL);
			}
			ipsec_invalidate_cache(inp, IPSEC_DIR_OUTBOUND);
			ipsec_invalidate_cache(inp, IPSEC_DIR_INBOUND);
			if (downgrade != 0)
				INP_DOWNGRADE(inp);
			return (NULL);
		}
		KEYDBG(IPSEC_STAMP,
		    printf("%s: PCB(%p): cache hit SP(%p)\n",
		    __func__, inp, sp));
		/* Return referenced cached policy */
	}
	key_addref(sp);
	return (sp);
}
Ejemplo n.º 3
0
/*
 * Return a held reference to the default SP.
 */
static struct secpolicy *
key_allocsp_default(const char* where, int tag)
{
	struct secpolicy *sp;

	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP key_allocsp_default from %s:%u\n", where, tag));

	sp = &V_ip4_def_policy;
	if (sp->policy != IPSEC_POLICY_DISCARD &&
	    sp->policy != IPSEC_POLICY_NONE) {
		ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n",
		    sp->policy, IPSEC_POLICY_NONE));
		sp->policy = IPSEC_POLICY_NONE;
	}
	key_addref(sp);

	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP key_allocsp_default returns SP:%p (%u)\n",
			sp, sp->refcnt));
	return (sp);
}
Ejemplo n.º 4
0
/*
 * For OUTBOUND packet having a socket. Searching SPD for packet,
 * and return a pointer to SP.
 * OUT:	NULL:	no apropreate SP found, the following value is set to error.
 *		0	: bypass
 *		EACCES	: discard packet.
 *		ENOENT	: ipsec_acquire() in progress, maybe.
 *		others	: error occured.
 *	others:	a pointer to SP
 *
 * NOTE: IPv6 mapped adddress concern is implemented here.
 */
static struct secpolicy *
ipsec_getpolicybysock(struct mbuf *m, u_int dir, struct inpcb *inp, int *error)
{
	struct inpcbpolicy *pcbsp;
	struct secpolicy *currsp = NULL;	/* Policy on socket. */
	struct secpolicy *sp;

	IPSEC_ASSERT(m != NULL, ("null mbuf"));
	IPSEC_ASSERT(inp != NULL, ("null inpcb"));
	IPSEC_ASSERT(error != NULL, ("null error"));
	IPSEC_ASSERT(dir == IPSEC_DIR_INBOUND || dir == IPSEC_DIR_OUTBOUND,
		("invalid direction %u", dir));

	/* Set spidx in pcb. */
	*error = ipsec_setspidx_inpcb(m, inp);
	if (*error)
		return (NULL);

	pcbsp = inp->inp_sp;
	IPSEC_ASSERT(pcbsp != NULL, ("null pcbsp"));
	switch (dir) {
	case IPSEC_DIR_INBOUND:
		currsp = pcbsp->sp_in;
		break;
	case IPSEC_DIR_OUTBOUND:
		currsp = pcbsp->sp_out;
		break;
	}
	IPSEC_ASSERT(currsp != NULL, ("null currsp"));

	if (pcbsp->priv) {			/* When privilieged socket. */
		switch (currsp->policy) {
		case IPSEC_POLICY_BYPASS:
		case IPSEC_POLICY_IPSEC:
			key_addref(currsp);
			sp = currsp;
			break;

		case IPSEC_POLICY_ENTRUST:
			/* Look for a policy in SPD. */
			sp = KEY_ALLOCSP(&currsp->spidx, dir);
			if (sp == NULL)		/* No SP found. */
				sp = KEY_ALLOCSP_DEFAULT();
			break;

		default:
			ipseclog((LOG_ERR, "%s: Invalid policy for PCB %d\n",
				__func__, currsp->policy));
			*error = EINVAL;
			return (NULL);
		}
	} else {				/* Unpriv, SPD has policy. */
		sp = KEY_ALLOCSP(&currsp->spidx, dir);
		if (sp == NULL) {		/* No SP found. */
			switch (currsp->policy) {
			case IPSEC_POLICY_BYPASS:
				ipseclog((LOG_ERR, "%s: Illegal policy for "
					"non-priviliged defined %d\n",
					__func__, currsp->policy));
				*error = EINVAL;
				return (NULL);

			case IPSEC_POLICY_ENTRUST:
				sp = KEY_ALLOCSP_DEFAULT();
				break;

			case IPSEC_POLICY_IPSEC:
				key_addref(currsp);
				sp = currsp;
				break;

			default:
				ipseclog((LOG_ERR, "%s: Invalid policy for "
					"PCB %d\n", __func__, currsp->policy));
				*error = EINVAL;
				return (NULL);
			}
		}
	}
	IPSEC_ASSERT(sp != NULL,
		("null SP (priv %u policy %u", pcbsp->priv, currsp->policy));
	KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
		printf("DP %s (priv %u policy %u) allocate SP:%p (refcnt %u)\n",
			__func__, pcbsp->priv, currsp->policy, sp, sp->refcnt));
	return (sp);
}
Ejemplo n.º 5
0
static void
ipsec_cachepolicy(struct inpcb *inp, struct secpolicy *sp, u_int dir)
{
	uint32_t genid;
	int downgrade;

	INP_LOCK_ASSERT(inp);

	if (dir == IPSEC_DIR_OUTBOUND) {
		/* Do we have configured PCB policy? */
		if (inp->inp_sp->flags & INP_OUTBOUND_POLICY)
			return;
		/* Another thread has already set cached policy */
		if (inp->inp_sp->sp_out != NULL)
			return;
		/*
		 * Do not cache OUTBOUND policy if PCB isn't connected,
		 * i.e. foreign address is INADDR_ANY/UNSPECIFIED.
		 */
#ifdef INET
		if ((inp->inp_vflag & INP_IPV4) != 0 &&
		    inp->inp_faddr.s_addr == INADDR_ANY)
			return;
#endif
#ifdef INET6
		if ((inp->inp_vflag & INP_IPV6) != 0 &&
		    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
			return;
#endif
	} else {
		/* Do we have configured PCB policy? */
		if (inp->inp_sp->flags & INP_INBOUND_POLICY)
			return;
		/* Another thread has already set cached policy */
		if (inp->inp_sp->sp_in != NULL)
			return;
		/*
		 * Do not cache INBOUND policy for listen socket,
		 * that is bound to INADDR_ANY/UNSPECIFIED address.
		 */
#ifdef INET
		if ((inp->inp_vflag & INP_IPV4) != 0 &&
		    inp->inp_faddr.s_addr == INADDR_ANY)
			return;
#endif
#ifdef INET6
		if ((inp->inp_vflag & INP_IPV6) != 0 &&
		    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr))
			return;
#endif
	}
	downgrade = 0;
	if (!INP_WLOCKED(inp)) {
		if ((downgrade = INP_TRY_UPGRADE(inp)) == 0)
			return;
	}
	if (dir == IPSEC_DIR_OUTBOUND)
		inp->inp_sp->sp_out = sp;
	else
		inp->inp_sp->sp_in = sp;
	/*
	 * SP is already referenced by the lookup code.
	 * We take extra reference here to avoid race in the
	 * ipsec_getpcbpolicy() function - SP will not be freed in the
	 * time between we take SP pointer from the cache and key_addref()
	 * call.
	 */
	key_addref(sp);
	genid = key_getspgen();
	if (genid != inp->inp_sp->genid) {
		ipsec_invalidate_cache(inp, dir);
		inp->inp_sp->genid = genid;
	}
	KEYDBG(IPSEC_STAMP,
	    printf("%s: PCB(%p): cached %s SP(%p)\n",
	    __func__, inp, dir == IPSEC_DIR_OUTBOUND ? "OUTBOUND":
	    "INBOUND", sp));
	if (downgrade != 0)
		INP_DOWNGRADE(inp);
}