Example #1
0
/** netlink_policy - 
 *
 * @param hdr - Data to check
 * @param enoent_ok - Boolean - OK or not OK.
 * @param text_said - String
 * @return boolean 
 */
static bool
netlink_policy(struct nlmsghdr *hdr, bool enoent_ok, const char *text_said)
{
    struct {
	struct nlmsghdr n;
	struct nlmsgerr e;
    } rsp;
    int error;

    rsp.n.nlmsg_type = NLMSG_ERROR;
    if (!send_netlink_msg(hdr, &rsp.n, sizeof(rsp), "policy", text_said))
    {
	return FALSE;
    }

    error = -rsp.e.error;
    if (!error)
    {
	return TRUE;
    }

    if (error == ENOENT && enoent_ok)
    {
	return TRUE;
    }

    loglog(RC_LOG_SERIOUS
	, "ERROR: netlink %s response for flow %s included errno %d: %s"
	, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
	, text_said
	, error
	, strerror(error));
    return FALSE;
}
Example #2
0
/* Handle PF_KEY messages from the kernel that are not dealt with
 * synchronously.  In other words, all but responses to PF_KEY messages
 * that we sent.
 */
static void
pfkey_async(pfkey_buf *buf)
{
    struct sadb_ext *extensions[SADB_EXT_MAX + 1];

    if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))
    {
	plog("pfkey_async:"
	    " unparseable PF_KEY message:"
	    " %s len=%d, errno=%d, seq=%d, pid=%d; message ignored"
	    , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
	    , buf->msg.sadb_msg_len
	    , buf->msg.sadb_msg_errno
	    , buf->msg.sadb_msg_seq
	    , buf->msg.sadb_msg_pid);
    }
    else
    {
	DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:"
	    " %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u"
	    , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
	    , buf->msg.sadb_msg_len
	    , buf->msg.sadb_msg_errno
	    , buf->msg.sadb_msg_satype
	    , buf->msg.sadb_msg_seq
	    , buf->msg.sadb_msg_pid));

	switch (buf->msg.sadb_msg_type)
	{
	case SADB_REGISTER:
	    kernel_ops->pfkey_register_response(&buf->msg);
	    break;
	case SADB_ACQUIRE:
	    /* to simulate loss of ACQUIRE, delete this call */
	    process_pfkey_acquire(buf, extensions);
	    break;
#ifdef NAT_TRAVERSAL
	case SADB_X_NAT_T_NEW_MAPPING:
	    process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
	    break;
#endif
	default:
	    /* ignored */
	    break;
	}
    }
}
Example #3
0
/* Finish (building, sending, accepting response for) PF_KEY message.
 * If response isn't NULL, the response from the kernel will be
 * placed there (and its errno field will not be examined).
 * Returns TRUE iff all appears well.
 */
static bool
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
, const char *description
, const char *text_said
, pfkey_buf *response)
{
    struct sadb_msg *pfkey_msg;
    bool success = TRUE;
    int error;

    error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);

    if (error != 0)
    {
	loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
	    , description, text_said, error);
	success = FALSE;
    }
    else
    {
	size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;

	DBG(DBG_KLIPS,
	    DBG_log("finish_pfkey_msg: %s message %u for %s %s"
		, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
		, pfkey_msg->sadb_msg_seq
		, description, text_said);
	    DBG_dump(NULL, (void *) pfkey_msg, len));

	if (!no_klips)
	{
	    ssize_t r = write(pfkeyfd, pfkey_msg, len);

	    if (r != (ssize_t)len)
	    {
		if (r < 0)
		{
		    log_errno((e
			, "pfkey write() of %s message %u"
			  " for %s %s failed"
			, sparse_val_show(pfkey_type_names
			    , pfkey_msg->sadb_msg_type)
			, pfkey_msg->sadb_msg_seq
			, description, text_said));
		}
		else
		{
		    loglog(RC_LOG_SERIOUS
			, "ERROR: pfkey write() of %s message %u"
			  " for %s %s truncated: %ld instead of %ld"
			, sparse_val_show(pfkey_type_names
			    , pfkey_msg->sadb_msg_type)
			, pfkey_msg->sadb_msg_seq
			, description, text_said
			, (long)r, (long)len);
		}
		success = FALSE;

		/* if we were compiled with debugging, but we haven't already
		 * dumped the KLIPS command, do so.
		 */
#ifdef DEBUG
		if ((cur_debugging & DBG_KLIPS) == 0)
		    DBG_dump(NULL, (void *) pfkey_msg, len);
#endif
	    }
	    else
	    {
		/* Check response from KLIPS.
		 * It ought to be an echo, perhaps with additional info.
		 * If the caller wants it, response will point to space.
		 */
		pfkey_buf b;
		pfkey_buf *bp = response != NULL? response : &b;

		if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
		{
		    loglog(RC_LOG_SERIOUS
			, "ERROR: no response to our PF_KEY %s message for %s %s"
			, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said);
		    success = FALSE;
		}
		else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
		{
		    loglog(RC_LOG_SERIOUS
			, "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
			, sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said
			, sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
		    success = FALSE;
		}
		else if (response == NULL && bp->msg.sadb_msg_errno != 0)
		{
		    /* KLIPS is signalling a problem */
		    loglog(RC_LOG_SERIOUS
			, "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
			, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
			, description, text_said
			, (unsigned) bp->msg.sadb_msg_errno
			, strerror(bp->msg.sadb_msg_errno));
		    success = FALSE;
		}
	    }
	}
    }

    /* all paths must exit this way to free resources */
    pfkey_extensions_free(extensions);
    pfkey_msg_free(&pfkey_msg);
    return success;
}
Example #4
0
/* get a PF_KEY message from kernel.
 * Returns TRUE is message found, FALSE if no message pending,
 * and aborts or keeps trying when an error is encountered.
 * The only validation of the message is that the message length
 * received matches that in the message header, and that the message
 * is for this process.
 */
static bool
pfkey_get(pfkey_buf *buf)
{
    for (;;)
    {
	/* len must be less than PFKEYv2_MAX_MSGSIZE,
	 * so it should fit in an int.  We use this fact when printing it.
	 */
	ssize_t len;

	if (!pfkey_input_ready())
	    return FALSE;

	len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));

	if (len < 0)
	{
	    if (errno == EAGAIN)
		return FALSE;

	    log_errno((e, "read() failed in pfkey_get()"));
	    return FALSE;
	}
	else if ((size_t) len < sizeof(buf->msg))
	{
	    plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"
		, (int) len);
	}
	else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
	{
	    plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"
		, (int) len
		, (unsigned) buf->msg.sadb_msg_len
		, (unsigned) IPSEC_PFKEYv2_ALIGN);
	}
	else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
	/*	for now, unsolicited messages can be: 
	 *	SADB_ACQUIRE, SADB_REGISTER, SADB_X_NAT_T_NEW_MAPPING
	 */
	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
#ifdef KERNEL_ALG
	|| (buf->msg.sadb_msg_type == SADB_REGISTER)
#endif
#ifdef NAT_TRAVERSAL
	|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)
#endif
	))
	{
	    /* not for us: ignore */
	    DBG(DBG_KLIPS,
		DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
		    , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
		    , buf->msg.sadb_msg_seq
		    , buf->msg.sadb_msg_pid));
	}
	else
	{
	    DBG(DBG_KLIPS,
		DBG_log("pfkey_get: %s message %u"
		    , sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
		    , buf->msg.sadb_msg_seq));
	    return TRUE;
	}
    }
}
Example #5
0
static bool
netlink_get(void)
{
    struct {
	struct nlmsghdr n;
	char data[1024];
    } rsp;
    ssize_t r;
    struct sockaddr_nl addr;
    socklen_t alen;

    alen = sizeof(addr);
    r = recvfrom(netlink_bcast_fd, &rsp, sizeof(rsp), 0
	, (struct sockaddr *)&addr, &alen);
    if (r < 0)
    {
	if (errno == EAGAIN)
	    return FALSE;
	if (errno != EINTR)
	    log_errno((e, "recvfrom() failed in netlink_get"));
	return TRUE;
    }
    else if ((size_t) r < sizeof(rsp.n))
    {
	openswan_log("netlink_get read truncated message: %ld bytes; ignore message"
	    , (long) r);
	return TRUE;
    }
    else if (addr.nl_pid != 0)
    {
	/* not for us: ignore */
	DBG(DBG_KLIPS,
	    DBG_log("netlink_get: ignoring %s message from process %u"
		, sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
		, addr.nl_pid));
	return TRUE;
    }
    else if ((size_t) r != rsp.n.nlmsg_len)
    {
	openswan_log("netlink_get read message with length %ld that doesn't equal nlmsg_len %lu bytes; ignore message"
	    , (long) r
	    , (unsigned long) rsp.n.nlmsg_len);
	return TRUE;
    }

    DBG(DBG_KLIPS,
	DBG_log("netlink_get: %s message"
		, sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));

    switch (rsp.n.nlmsg_type)
    {
    case XFRM_MSG_ACQUIRE:
	netlink_acquire(&rsp.n);
	break;
    case XFRM_MSG_POLEXPIRE:
	netlink_policy_expire(&rsp.n);
	break;
    default:
	/* ignored */
	break;
    }

    return TRUE;
}
Example #6
0
/** send_netlink_msg
 *
 * @param hdr - Data to be sent.
 * @param rbuf - Return Buffer - contains data returned from the send.
 * @param rbuf_len - Length of rbuf
 * @param description - String - user friendly description of what is 
 *                      being attempted.  Used for diagnostics
 * @param text_said - String
 * @return bool True if the message was succesfully sent.
 */
static bool
send_netlink_msg(struct nlmsghdr *hdr, struct nlmsghdr *rbuf, size_t rbuf_len
, const char *description, const char *text_said)
{
    struct {
	struct nlmsghdr n;
	struct nlmsgerr e;
	char data[1024];
    } rsp;
    size_t len;
    ssize_t r;
    struct sockaddr_nl addr;
    static uint32_t seq;

    if (no_klips)
    {
	return TRUE;
    }

    hdr->nlmsg_seq = ++seq;
    len = hdr->nlmsg_len;
    do {
	r = write(netlinkfd, hdr, len);
    } while (r < 0 && errno == EINTR);
    if (r < 0)
    {
	log_errno((e
	    , "netlink write() of %s message"
	      " for %s %s failed"
	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
	    , description, text_said));
	return FALSE;
    }
    else if ((size_t)r != len)
    {
	loglog(RC_LOG_SERIOUS
	    , "ERROR: netlink write() of %s message"
	      " for %s %s truncated: %ld instead of %lu"
	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
	    , description, text_said
	    , (long)r, (unsigned long)len);
	return FALSE;
    }

    for (;;) {
	socklen_t alen;

	alen = sizeof(addr);
	r = recvfrom(netlinkfd, &rsp, sizeof(rsp), 0
	    , (struct sockaddr *)&addr, &alen);
	if (r < 0)
	{
	    if (errno == EINTR)
	    {
		continue;
	    }
	    log_errno((e
		, "netlink recvfrom() of response to our %s message"
		  " for %s %s failed"
		, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
		, description, text_said));
	    return FALSE;
	}
	else if ((size_t) r < sizeof(rsp.n))
	{
	    openswan_log("netlink read truncated message: %ld bytes; ignore message"
		, (long) r);
	    continue;
	}
	else if (addr.nl_pid != 0)
	{
	    /* not for us: ignore */
	    DBG(DBG_KLIPS,
		DBG_log("netlink: ignoring %s message from process %u"
		    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)
		    , addr.nl_pid));
	    continue;
	}
	else if (rsp.n.nlmsg_seq != seq)
	{
	    DBG(DBG_KLIPS,
		DBG_log("netlink: ignoring out of sequence (%u/%u) message %s"
		    , rsp.n.nlmsg_seq, seq
		    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type)));
	    continue;
	}
	break;
    }

    if (rsp.n.nlmsg_len > (size_t) r)
    {
	loglog(RC_LOG_SERIOUS
	    , "netlink recvfrom() of response to our %s message"
	      " for %s %s was truncated: %ld instead of %lu"
	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
	    , description, text_said
	    , (long) len, (unsigned long) rsp.n.nlmsg_len);
	return FALSE;
    }
    else if (rsp.n.nlmsg_type != NLMSG_ERROR
    && (rbuf && rsp.n.nlmsg_type != rbuf->nlmsg_type))
    {
	loglog(RC_LOG_SERIOUS
	    , "netlink recvfrom() of response to our %s message"
	      " for %s %s was of wrong type (%s)"
	    , sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
	    , description, text_said
	    , sparse_val_show(xfrm_type_names, rsp.n.nlmsg_type));
	return FALSE;
    }
    else if (rbuf)
    {
	if ((size_t) r > rbuf_len)
	{
	    loglog(RC_LOG_SERIOUS
		, "netlink recvfrom() of response to our %s message"
		  " for %s %s was too long: %ld > %lu"
		, sparse_val_show(xfrm_type_names, hdr->nlmsg_type)
		, description, text_said
		, (long)r, (unsigned long)rbuf_len);
	    return FALSE;
	}
	memcpy(rbuf, &rsp, r);
	return TRUE;
    }
    else if (rsp.n.nlmsg_type == NLMSG_ERROR && rsp.e.error)
    {
	loglog(RC_LOG_SERIOUS
	    , "ERROR: netlink response for %s %s included errno %d: %s"
	    , description, text_said
	    , -rsp.e.error
	    , strerror(-rsp.e.error));
	return FALSE;
    }

    return TRUE;
}