Beispiel #1
0
/* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port).  */
static u_int8_t *
nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
    size_t *hashlen)
{
	struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
	struct hash	 *hash;
	u_int8_t	 *res;
	in_port_t	  port;

	hash = hash_get(ie->hash->type);
	if (hash == NULL) {
		log_print ("nat_t_generate_nat_d_hash: no hash");
		return NULL;
	}

	*hashlen = hash->hashsize;

	res = malloc(*hashlen);
	if (!res) {
		log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
		    (unsigned long)*hashlen);
		*hashlen = 0;
		return NULL;
	}

	port = sockaddr_port(sa);
	bzero(res, *hashlen);

	hash->Init(hash->ctx);
	hash->Update(hash->ctx, msg->exchange->cookies,
	    sizeof msg->exchange->cookies);
	hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
	hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
	hash->Final(res, hash->ctx);
	return res;
}
/*
 * When we are "the server", this starts SET/ACK mode
 * When we are "the client", this starts REQ/REPLY mode
 */
static int
cfg_initiator_send_ATTR(struct message *msg)
{
	struct sa      *isakmp_sa = msg->isakmp_sa;
	struct ipsec_exch *ie = msg->exchange->data;
	u_int8_t       *hashp = 0, *attrp, *attr;
	size_t          attrlen, off;
	char           *id_string, *cfg_mode, *field;
	struct sockaddr *sa;
#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN	/* XXX */
	bitstr_t        bit_decl(attrbits, CFG_ATTR_BIT_MAX);
	u_int16_t       bit, length;
	u_int32_t       life;

	if (msg->exchange->phase == 2) {
		hashp = cfg_add_hash(msg);
		if (!hashp)
			return -1;
	}
	/* We initiated this exchange, check isakmp_sa for other side.  */
	if (isakmp_sa->initiator)
		id_string = ipsec_id_string(isakmp_sa->id_r,
		    isakmp_sa->id_r_len);
	else
		id_string = ipsec_id_string(isakmp_sa->id_i,
		    isakmp_sa->id_i_len);
	if (!id_string) {
		log_print("cfg_initiator_send_ATTR: cannot parse ID");
		goto fail;
	}
	/* Check for attribute list to send to the other side */
	attrlen = 0;
	bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1);

	cfg_mode = conf_get_str(id_string, "Mode");
	if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) {
		/* SET/ACK mode */
		ie->cfg_type = ISAKMP_CFG_SET;

		LOG_DBG((LOG_NEGOTIATION, 10,
		    "cfg_initiator_send_ATTR: SET/ACK mode"));

#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do				\
	{								\
		if ((sa = conf_get_address (id_string, STR)) != NULL)	\
			switch (sa->sa_family) {			\
			case AF_INET:					\
				bit_set (attrbits, ATTR4);		\
				attrlen += ISAKMP_ATTR_SZ + LEN4;	\
				break;					\
			case AF_INET6:					\
				bit_set (attrbits, ATTR6);		\
				attrlen += ISAKMP_ATTR_SZ + LEN6;	\
				break;					\
			default:					\
				break;					\
			}						\
		free (sa);						\
	} while (0)

		/*
		 * XXX We don't simultaneously support IPv4 and IPv6
		 * addresses.
		 */
		ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16);
		ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16);
		ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16);
		ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16);
		ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16);
#ifdef notyet
		ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17);
#endif
#undef ATTRFIND

		if (conf_get_str(id_string, "Lifetime")) {
			bit_set(attrbits,
			    ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
			attrlen += ISAKMP_ATTR_SZ + 4;
		}
	} else {
		struct conf_list *alist;
		struct conf_list_node *anode;

		ie->cfg_type = ISAKMP_CFG_REQUEST;

		LOG_DBG((LOG_NEGOTIATION, 10,
		    "cfg_initiator_send_ATTR: REQ/REPLY mode"));

		alist = conf_get_list(id_string, "Attributes");
		if (alist) {
			for (anode = TAILQ_FIRST(&alist->fields); anode;
			    anode = TAILQ_NEXT(anode, link)) {
				if (strcasecmp(anode->field, "Address") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field, "Netmask")
				    == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "Nameserver") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "WINS-server") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "DHCP-server") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "Lifetime") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
					attrlen += ISAKMP_ATTR_SZ;
				} else {
					log_print("cfg_initiator_send_ATTR: "
					    "unknown attribute %.20s in "
					    "section [%s]", anode->field,
					    id_string);
				}
			}

			conf_free_list(alist);
		}
	}

	if (attrlen == 0) {
		/* No data found.  */
		log_print("cfg_initiator_send_ATTR: no IKECFG attributes "
		    "found for [%s]", id_string);

		/*
		 * We can continue, but this indicates a configuration error
		 * that the user probably will want to correct.
		 */
		free(id_string);
		return 0;
	}
	attrlen += ISAKMP_ATTRIBUTE_SZ;
	attrp = calloc(1, attrlen);
	if (!attrp) {
		log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed",
		    (unsigned long)attrlen);
		goto fail;
	}
	if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
	    1)) {
		free(attrp);
		goto fail;
	}
	SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type);
	getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id);
	SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id);

	off = ISAKMP_ATTRIBUTE_SZ;

	/*
	 * Use the bitstring built previously to collect the right
	 * parameters for attrp.
         */
	for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++)
		if (bit_test(attrbits, bit)) {
			attr = attrp + off;
			SET_ISAKMP_ATTR_TYPE(attr, bit);

			if (ie->cfg_type == ISAKMP_CFG_REQUEST) {
				off += ISAKMP_ATTR_SZ;
				continue;
			}
			/* All the other are similar, this is the odd one.  */
			if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) {
				life = conf_get_num(id_string, "Lifetime",
				    1200);
				SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4);
				encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life);
				off += ISAKMP_ATTR_SZ + 4;
				continue;
			}
			switch (bit) {
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
				length = 4;
				break;

			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
				length = 16;
				break;

			default:
				length = 0;	/* Silence gcc.  */
			}

			switch (bit) {
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
				field = "Address";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
				field = "Netmask";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
				field = "Nameserver";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
				field = "DHCP-server";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
				field = "WINS-server";
				break;
			default:
				field = 0;	/* Silence gcc.  */
			}

			sa = conf_get_address(id_string, field);

			SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length);
			memcpy(attr + ISAKMP_ATTR_VALUE_OFF,
			    sockaddr_addrdata(sa), length);

			free(sa);

			off += ISAKMP_ATTR_SZ + length;
		}
	if (msg->exchange->phase == 2)
		if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
			goto fail;

	return 0;

fail:
	free(id_string);
	return -1;
}
Beispiel #3
0
/* Receive ID.  */
int
ike_phase_1_recv_ID (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct payload *payload;
    char header[80], *rs = 0, *rid = 0, *p;
    int initiator = exchange->initiator;
    u_int8_t **id, id_type;
    size_t *id_len, sz;
    struct sockaddr *sa;

    payload = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_ID]);

    if (exchange->name)
        rs = conf_get_str (exchange->name, "Remote-ID");

    if (rs)
    {
        sz = ipsec_id_size (rs, &id_type);
        if (sz == -1)
        {
            log_print ("ike_phase_1_recv_ID: could not handle specified "
                       "Remote-ID [%s]", rs);
            return -1;
        }

        rid = malloc (sz);
        if (!rid)
        {
            log_error ("ike_phase_1_recv_ID: malloc (%lu) failed",
                       (unsigned long)sz);
            return -1;
        }

        switch (id_type)
        {
        case IPSEC_ID_IPV4_ADDR:
        case IPSEC_ID_IPV6_ADDR:
            p = conf_get_str (rs, "Address");
            if (!p)
            {
                log_print ("ike_phase_1_recv_ID: "
                           "failed to get Address in Remote-ID section [%s]",
                           rs);
                free (rid);
                return -1;
            }

            if (text2sockaddr (p, 0, &sa) == -1)
            {
                log_print ("ike_phase_1_recv_ID: failed to parse address %s", p);
                free (rid);
                return -1;
            }

            if ((id_type == IPSEC_ID_IPV4_ADDR && sa->sa_family != AF_INET)
                    || (id_type == IPSEC_ID_IPV6_ADDR && sa->sa_family != AF_INET6))
            {
                log_print ("ike_phase_1_recv_ID: "
                           "address %s not of expected family", p);
                free (rid);
                free (sa);
                return -1;
            }

            memcpy (rid, sockaddr_addrdata (sa), sockaddr_addrlen (sa));
            free (sa);
            break;

        case IPSEC_ID_FQDN:
        case IPSEC_ID_USER_FQDN:
        case IPSEC_ID_KEY_ID:
            p = conf_get_str (rs, "Name");
            if (!p)
            {
                log_print ("ike_phase_1_recv_ID: "
                           "failed to get Name in Remote-ID section [%s]", rs);
                free (rid);
                return -1;
            }

            memcpy (rid, p, sz);
            break;

        default:
            log_print ("ike_phase_1_recv_ID: unsupported ID type %d", id_type);
            free (rid);
            return -1;
        }

        /* Compare expected/desired and received remote ID */
        if (bcmp (rid, payload->p + ISAKMP_ID_DATA_OFF, sz))
        {
            free (rid);
            log_print ("ike_phase_1_recv_ID: "
                       "received remote ID other than expected %s", p);
            return -1;
        }

        free (rid);
    }

    /* Choose the right fields to fill in */
    id = initiator ? &exchange->id_r : &exchange->id_i;
    id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len;

    *id_len = GET_ISAKMP_GEN_LENGTH (payload->p) - ISAKMP_GEN_SZ;
    *id = malloc (*id_len);
    if (!*id)
    {
        log_error ("ike_phase_1_recv_ID: malloc (%lu) failed",
                   (unsigned long)*id_len);
        return -1;
    }
    memcpy (*id, payload->p + ISAKMP_GEN_SZ, *id_len);
    snprintf (header, sizeof header, "ike_phase_1_recv_ID: %s",
              constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (payload->p)));
    LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, payload->p + ISAKMP_ID_DATA_OFF,
                  *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF));
    payload->flags |= PL_MARK;

    return 0;
}
/*
 * Encode list of attributes from ie->attrs into a attribute payload.
 */
static int
cfg_encode_attributes(struct isakmp_cfg_attr_head *attrs, u_int32_t type,
    u_int32_t cfg_id, char *id_string, u_int8_t **attrp, u_int16_t *len)
{
	struct isakmp_cfg_attr *attr;
	struct sockaddr *sa;
	sa_family_t     family;
	u_int32_t       value;
	u_int16_t       off;
	char           *field;

	/* Compute length */
	*len = ISAKMP_ATTRIBUTE_SZ;
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
		/* With ACK we only include the attrs we've actually used.  */
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
			continue;

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
			attr->length = 4;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
			attr->length = 8;
			break;

		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
			/* XXX So far no version identifier of isakmpd here. */
			attr->length = 0;
			break;

		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
			attr->length = 2 * 15;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			attr->length = 16;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
			attr->length = 17;
			break;

		default:
			attr->ignore++;
			/* XXX Log!  */
		}
		*len += ISAKMP_ATTR_SZ + attr->length;
	}

	/* Allocate enough space for the payload */
	*attrp = calloc(1, *len);
	if (!*attrp) {
		log_error("cfg_encode_attributes: calloc (1, %lu) failed",
		    (unsigned long)*len);
		return -1;
	}
	SET_ISAKMP_ATTRIBUTE_TYPE(*attrp, type);
	SET_ISAKMP_ATTRIBUTE_ID(*attrp, cfg_id);

	off = ISAKMP_ATTRIBUTE_SZ;
	for (attr = LIST_FIRST(attrs); attr; attr = LIST_NEXT(attr, link)) {
		/* With ACK we only include the attrs we've actually used.  */
		if (type == ISAKMP_CFG_ACK && attr->attr_used == 0)
			continue;

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
			family = AF_INET;
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			family = AF_INET6;
			break;

		default:
			family = 0;
			break;
		}

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
			field = "Address";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET:
			field = "Network";	/* XXX or just "Address" */
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
			field = "Netmask";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
			field = "DHCP-server";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
			field = "Nameserver";
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			field = "WINS-server";
			break;

		default:
			field = 0;
		}

		switch (attr->type) {
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
		case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
			sa = conf_get_address(id_string, field);
			if (!sa) {
				LOG_DBG((LOG_NEGOTIATION, 10,
				    "cfg_responder_send_ATTR: "
				    "attribute not found: %s", field));
				attr->length = 0;
				break;
			}
			if (sa->sa_family != family) {
				log_print("cfg_responder_send_ATTR: "
				    "attribute %s - expected %s got %s data",
				    field,
				    (family == AF_INET ? "IPv4" : "IPv6"),
				    (sa->sa_family ==
					AF_INET ? "IPv4" : "IPv6"));
				free(sa);
				attr->length = 0;
				break;
			}
			/* Temporary limit length for the _SUBNET types. */
			if (attr->type == ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET)
				attr->length = 4;
			else if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET)
				attr->length = 16;

			memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF,
			    sockaddr_addrdata(sa), attr->length);
			free(sa);

			/* _SUBNET types need some extra work. */
			if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET) {
				sa = conf_get_address(id_string, "Netmask");
				if (!sa) {
					LOG_DBG((LOG_NEGOTIATION, 10,
					    "cfg_responder_send_ATTR: "
					   "attribute not found: Netmask"));
					attr->length = 0;
					break;
				}
				if (sa->sa_family != AF_INET) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute Netmask - expected "
					    "IPv4 got IPv6 data");
					free(sa);
					attr->length = 0;
					break;
				}
				memcpy(*attrp + off + ISAKMP_ATTR_VALUE_OFF +
				    attr->length, sockaddr_addrdata(sa),
				    attr->length);
				attr->length = 8;
				free(sa);
			} else if (attr->type ==
			    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET) {
				int prefix = conf_get_num(id_string, "Prefix",
				    -1);

				if (prefix == -1) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute not found: Prefix");
					attr->length = 0;
					break;
				} else if (prefix < -1 || prefix > 128) {
					log_print("cfg_responder_send_ATTR: "
					    "attribute Prefix - invalid "
					    "value %d", prefix);
					attr->length = 0;
					break;
				}
				*(*attrp + off + ISAKMP_ATTR_VALUE_OFF + 16) =
				    (u_int8_t)prefix;
				attr->length = 17;
			}
			break;

		case ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY:
			value = conf_get_num(id_string, "Lifetime", 1200);
			encode_32(*attrp + off + ISAKMP_ATTR_VALUE_OFF, value);
			break;

		case ISAKMP_CFG_ATTR_APPLICATION_VERSION:
			/* XXX So far no version identifier of isakmpd here. */
			break;

		case ISAKMP_CFG_ATTR_SUPPORTED_ATTRIBUTES:
			break;

		default:
			break;
		}

		SET_ISAKMP_ATTR_TYPE(*attrp + off, attr->type);
		SET_ISAKMP_ATTR_LENGTH_VALUE(*attrp + off, attr->length);
		off += ISAKMP_ATTR_VALUE_OFF + attr->length;
	}

	return 0;
}
Beispiel #5
0
int
ike_phase_1_send_ID (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    u_int8_t *buf;
    char header[80];
    ssize_t sz;
    struct sockaddr *src;
    int initiator = exchange->initiator;
    u_int8_t **id;
    size_t *id_len;
    char *my_id = 0;
    u_int8_t id_type;

    /* Choose the right fields to fill-in.  */
    id = initiator ? &exchange->id_i : &exchange->id_r;
    id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len;

    if (exchange->name)
        my_id = conf_get_str (exchange->name, "ID");

    if (!my_id)
        my_id = conf_get_str ("General", "Default-phase-1-ID");

    msg->transport->vtbl->get_src (msg->transport, &src);
    sz = my_id ? ipsec_id_size (my_id, &id_type) : sockaddr_addrlen (src);
    if (sz == -1)
        return -1;

    sz += ISAKMP_ID_DATA_OFF;
    buf = malloc (sz);
    if (!buf)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)sz);
        return -1;
    }

    SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    if (my_id)
    {
        SET_ISAKMP_ID_TYPE (buf, id_type);
        switch (id_type)
        {
        case IPSEC_ID_IPV4_ADDR:
        case IPSEC_ID_IPV6_ADDR:
            /* Already in network byteorder.  */
            memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                    sockaddr_addrlen (src));
            break;

        case IPSEC_ID_FQDN:
        case IPSEC_ID_USER_FQDN:
        case IPSEC_ID_KEY_ID:
            memcpy (buf + ISAKMP_ID_DATA_OFF, conf_get_str (my_id, "Name"),
                    sz - ISAKMP_ID_DATA_OFF);
            break;

        default:
            log_print ("ike_phase_1_send_ID: unsupported ID type %d", id_type);
            free (buf);
            return -1;
        }
    }
    else
    {
        switch (src->sa_family)
        {
        case AF_INET:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR);
            break;
        case AF_INET6:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV6_ADDR);
            break;
        }
        /* Already in network byteorder.  */
        memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                sockaddr_addrlen (src));
    }

    if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1))
    {
        free (buf);
        return -1;
    }
    *id_len = sz - ISAKMP_GEN_SZ;
    *id = malloc (*id_len);
    if (!*id)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)*id_len);
        return -1;
    }
    memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len);
    snprintf (header, sizeof header, "ike_phase_1_send_ID: %s",
              constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf)));
    LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,
                  sz - ISAKMP_ID_DATA_OFF));

    return 0;
}