Ejemplo n.º 1
0
int sadb_msg_dump_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply)
{
	int error = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

err:
	return error;
}
Ejemplo n.º 2
0
int sadb_msg_expire_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = -EINVAL;

#if 0 /* kernel never receive SADB_EXPIRE message */

	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1];

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

err:
#endif /* kernel never receive SADB_EXPIRE message */

	return error;
}
int sadb_msg_add_parse(struct sock *sk, struct sadb_msg *msg, struct sadb_msg **reply)
{
	int error = 0;
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	struct sadb_sa *sa;
	struct sadb_address *src;
	struct sadb_address *dst;
	struct ipsec_sa *sa_entry = NULL;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");
		error = -EINVAL;
		goto rtn;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (ext_msgs[SADB_EXT_SA] &&
		ext_msgs[SADB_EXT_ADDRESS_SRC] &&
		ext_msgs[SADB_EXT_ADDRESS_DST])
	{
		sa  = (struct sadb_sa*)ext_msgs[SADB_EXT_SA];

		if ( ((!sa->sadb_sa_auth && !sa->sadb_sa_encrypt) && msg->sadb_msg_satype != SADB_X_SATYPE_COMP) || 
				sa->sadb_sa_auth > SADB_AALG_MAX || 
				sa->sadb_sa_encrypt > SADB_EALG_MAX ) {
			PFKEY_DEBUG("sa has no transform or invalid transform value\n");
			error = -EINVAL;
			goto rtn;
		}

		switch (msg->sadb_msg_satype) {

		case SADB_SATYPE_AH:
		case SADB_SATYPE_ESP:
		case SADB_X_SATYPE_COMP:
			break;
		case SADB_SATYPE_RSVP:
		case SADB_SATYPE_OSPFV2:
		case SADB_SATYPE_RIPV2:
		case SADB_SATYPE_MIP:
		default:
			PFKEY_DEBUG("invalid sa type\n");
			error = -EINVAL;
			goto rtn;
		}

		if (msg->sadb_msg_satype == SADB_SATYPE_ESP && !(sa->sadb_sa_encrypt)) {
			PFKEY_DEBUG("sa type is esp but no algorithm\n");
			error = -EINVAL;
			goto rtn;
		}

		sa_entry = ipsec_sa_kmalloc();
		if (!sa_entry) {
			PFKEY_DEBUG("sa_entry: null\n");
			error = -ENOMEM;
			goto err;
		}

		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		sa_entry->ipsec_proto = msg->sadb_msg_satype;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved for our internal use.  */
		if (ntohl(sa->sadb_sa_spi) < 258 && sa_entry->ipsec_proto != SADB_X_SATYPE_COMP) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		sa_entry->spi = sa->sadb_sa_spi;

		error = sadb_address_to_sockaddr( src,
				(struct sockaddr*)&sa_entry->src);
		if (error) {
			PFKEY_DEBUG("src translation failed\n");
			goto err;
		}
		error = sadb_address_to_sockaddr( dst,
				(struct sockaddr*)&sa_entry->dst);
		if (error) {
			PFKEY_DEBUG("dst translation failed\n");
			goto err;
		}

		if (src->sadb_address_proto == dst->sadb_address_proto) {
			sa_entry->proto = src->sadb_address_proto;
		} else {
			error = -EINVAL;
			goto err;
		} 

		sa_entry->prefixlen_s = src->sadb_address_prefixlen;
		sa_entry->prefixlen_d = dst->sadb_address_prefixlen;

		if (sa->sadb_sa_auth) {
			if( (ext_msgs[SADB_EXT_KEY_AUTH]) ) {
				error = sadb_key_to_auth(sa->sadb_sa_auth,
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_AUTH], sa_entry);
				if (error)
					goto err;
			} else {
				PFKEY_DEBUG("SA has auth algo but there is no key for auth\n");
				error = -EINVAL;
				goto err;
			}
		}

		if (sa->sadb_sa_encrypt) {
			if (sa->sadb_sa_encrypt == SADB_EALG_NULL && 
					sa->sadb_sa_auth == SADB_AALG_NONE) {
				error = -EINVAL;
				goto err;
			}
			if (msg->sadb_msg_satype != SADB_X_SATYPE_COMP) {
				error = sadb_key_to_esp(sa->sadb_sa_encrypt, 
					(struct sadb_key*) ext_msgs[SADB_EXT_KEY_ENCRYPT], sa_entry);
				if (error)
					goto err;
			}
		}

		if (ext_msgs[SADB_EXT_ADDRESS_PROXY]) {
			printk(KERN_WARNING "PFKEY proxy translation is not supported.\n");
			goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_HARD]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_HARD],
						&sa_entry->lifetime_h);
			if (error) goto err;
		}

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT]) {
			error = sadb_lifetime_to_lifetime((struct sadb_lifetime*)ext_msgs[SADB_EXT_LIFETIME_SOFT],
						&sa_entry->lifetime_s);
			if (error) goto err;
		}

		sa_entry->state = SADB_SASTATE_MATURE;

		error = sadb_append(sa_entry);	
		if (error) goto err;	

		reply_ext_msgs[0] = (struct sadb_ext*) msg;
		reply_ext_msgs[SADB_EXT_SA] = ext_msgs[SADB_EXT_SA];
		reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
		reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];

		if (ext_msgs[SADB_EXT_LIFETIME_HARD])
			reply_ext_msgs[SADB_EXT_LIFETIME_HARD] = ext_msgs[SADB_EXT_LIFETIME_HARD];

		if (ext_msgs[SADB_EXT_LIFETIME_SOFT])
			reply_ext_msgs[SADB_EXT_LIFETIME_SOFT] = ext_msgs[SADB_EXT_LIFETIME_SOFT];

		error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
		goto rtn;
	} else {
		PFKEY_DEBUG("extensions not enough\n");
		error = -EINVAL;
		goto err;
	}

err:
	ipsec_sa_kfree(sa_entry);
rtn:
	return error;
}
int sadb_msg_getspi_parse(struct sock *sk, struct sadb_msg* msg, struct sadb_msg **reply) 
{
	struct sadb_ext *ext_msgs[SADB_EXT_MAX+1], *reply_ext_msgs[SADB_EXT_MAX+1];
	int error = 0, found_avail = 0;
	__u32 newspi = 0;
	__u32 spi_max = 0, spi_min = 0;
	struct ipsec_sa sadb_entry;
	struct sadb_address *src, *dst;

	if (!msg) {
		PFKEY_DEBUG("msg==null\n");

		error = -EINVAL;
		goto err;
	}

	memset(ext_msgs, 0, sizeof(ext_msgs));
	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));
	error = sadb_msg_detect_ext(msg, ext_msgs);

	if (error) {
		PFKEY_DEBUG("error in sadb_msg_detect_ext\n");
		goto err;
	}

	memset(reply_ext_msgs, 0, sizeof(reply_ext_msgs));

	if (ext_msgs[SADB_EXT_ADDRESS_SRC] &&
	    ext_msgs[SADB_EXT_ADDRESS_DST] &&
	    ext_msgs[SADB_EXT_SPIRANGE])
	{
		src = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_SRC];
		dst = (struct sadb_address*)ext_msgs[SADB_EXT_ADDRESS_DST];

		memset(&sadb_entry, 0, sizeof(struct ipsec_sa));
		error = sadb_address_to_sockaddr(src, (struct sockaddr*)&sadb_entry.src);
		if (error) {
			PFKEY_DEBUG("error in translate src address\n");
			goto err;
		}
		sadb_entry.prefixlen_s = src->sadb_address_prefixlen;

		error = sadb_address_to_sockaddr(dst, (struct sockaddr*)&sadb_entry.dst);
		if (error) {
			PFKEY_DEBUG("error in translate dst address\n");
		}
		sadb_entry.prefixlen_d = dst->sadb_address_prefixlen;

		spi_min = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_min;
		spi_max = ((struct sadb_spirange*)ext_msgs[SADB_EXT_SPIRANGE])->sadb_spirange_max;

		/* SPI which is under 255 is reserved by IANA. 
		 * Additionally, 256 and 257 reserved ofr internal use.  */
		if (spi_min < 258) {
			PFKEY_DEBUG("SPI value is reserved.(SPI<258)\n");
			goto err;
		}

		if (spi_min == spi_max) {
			PFKEY_DEBUG("spi_min and spi_max are equal\n");

			error = sadb_find_by_address_proto_spi((struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
								(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
								spi_min, msg->sadb_msg_type, NULL /*only check*/);
				
			if (error == -ESRCH) {
				newspi = spi_min;
				found_avail = 1;
			} else {
				PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
				goto err;
			}

		} else if (ntohl(spi_min) < ntohl(spi_max)) {
			/* This codes are derived from FreeS/WAN */
			int i = 0;
                	__u32 rand_val;
			__u32 spi_diff;

			PFKEY_DEBUG("spi_min and spi_max are defference\n");

			while ( ( i < (spi_diff = (ntohl(spi_max) - ntohl(spi_min)))) && !found_avail ) {
				get_random_bytes((void*) &rand_val,
				/* sizeof(extr->tdb->tdb_said.spi) */
                                         ( (spi_diff < (2^8))  ? 1 :
                                           ( (spi_diff < (2^16)) ? 2 :
                                             ( (spi_diff < (2^24)) ? 3 :
                                           4 ) ) ) );
				newspi = htonl(ntohl(spi_min) +
					(rand_val % (spi_diff + 1)));
				PFKEY_DEBUG("new spi is %d\n", ntohl(newspi));

				i++;
				error = sadb_find_by_address_proto_spi( (struct sockaddr*)&sadb_entry.src, sadb_entry.prefixlen_s, 
									(struct sockaddr*)&sadb_entry.dst, sadb_entry.prefixlen_d, 
									newspi, msg->sadb_msg_type, NULL /* only check */);
				if (error == -ESRCH) {
					found_avail = 1;
					break;
				} else {
					PFKEY_DEBUG("sadb_find_by_address_proto_spi return %d\n", error);
					goto err;
				}
			}

		} else {
			PFKEY_DEBUG("invalid spi range\n");
			error = -EINVAL;
			goto err;
		}

		if (found_avail) {
			sadb_entry.spi = newspi;
			sadb_entry.state = SADB_SASTATE_LARVAL;
			error = sadb_append(&sadb_entry);
			if (error) {
				PFKEY_DEBUG("sadb_append return %d\n", error);
				goto err;
			}
		} else {
			PFKEY_DEBUG("could not find available spi\n");
			goto err;
		}

	} else {
		PFKEY_DEBUG("necessary ext messages are not available\n");
		error = -EINVAL;
		goto err;
	}

	error = pfkey_sa_build(&reply_ext_msgs[SADB_EXT_SA], SADB_EXT_SA,
			newspi, 0, 0, 0, 0, SADB_SAFLAGS_PFS);
	if (error) {
		PFKEY_DEBUG("pfkey_address_build faild\n");
		goto err;
	}

	reply_ext_msgs[0] = (struct sadb_ext*) msg;
	reply_ext_msgs[SADB_EXT_ADDRESS_SRC] = ext_msgs[SADB_EXT_ADDRESS_SRC];
	reply_ext_msgs[SADB_EXT_ADDRESS_DST] = ext_msgs[SADB_EXT_ADDRESS_DST];
	error = pfkey_msg_build(reply, reply_ext_msgs, EXT_BITS_OUT);
err:
	return error;
}