📄 af_key.c
字号:
if (ext_type == SADB_EXT_ADDRESS_SRC || ext_type == SADB_EXT_ADDRESS_DST || ext_type == SADB_EXT_ADDRESS_PROXY || ext_type == SADB_X_EXT_NAT_T_OA) { if (verify_address_len(p)) return -EINVAL; } if (ext_type == SADB_X_EXT_SEC_CTX) { if (verify_sec_ctx_len(p)) return -EINVAL; } ext_hdrs[ext_type-1] = p; } p += ext_len; len -= ext_len; } return 0;}static uint16_tpfkey_satype2proto(uint8_t satype){ switch (satype) { case SADB_SATYPE_UNSPEC: return IPSEC_PROTO_ANY; case SADB_SATYPE_AH: return IPPROTO_AH; case SADB_SATYPE_ESP: return IPPROTO_ESP; case SADB_X_SATYPE_IPCOMP: return IPPROTO_COMP; break; default: return 0; } /* NOTREACHED */}static uint8_tpfkey_proto2satype(uint16_t proto){ switch (proto) { case IPPROTO_AH: return SADB_SATYPE_AH; case IPPROTO_ESP: return SADB_SATYPE_ESP; case IPPROTO_COMP: return SADB_X_SATYPE_IPCOMP; break; default: return 0; } /* NOTREACHED */}/* BTW, this scheme means that there is no way with PFKEY2 sockets to * say specifically 'just raw sockets' as we encode them as 255. */static uint8_t pfkey_proto_to_xfrm(uint8_t proto){ return (proto == IPSEC_PROTO_ANY ? 0 : proto);}static uint8_t pfkey_proto_from_xfrm(uint8_t proto){ return (proto ? proto : IPSEC_PROTO_ANY);}static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, xfrm_address_t *xaddr){ switch (((struct sockaddr*)(addr + 1))->sa_family) { case AF_INET: xaddr->a4 = ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr; return AF_INET;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6: memcpy(xaddr->a6, &((struct sockaddr_in6 *)(addr + 1))->sin6_addr, sizeof(struct in6_addr)); return AF_INET6;#endif default: return 0; } /* NOTREACHED */}static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs){ struct sadb_sa *sa; struct sadb_address *addr; uint16_t proto; unsigned short family; xfrm_address_t *xaddr; sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; if (sa == NULL) return NULL; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return NULL; /* sadb_address_len should be checked by caller */ addr = (struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1]; if (addr == NULL) return NULL; family = ((struct sockaddr *)(addr + 1))->sa_family; switch (family) { case AF_INET: xaddr = (xfrm_address_t *)&((struct sockaddr_in *)(addr + 1))->sin_addr; break;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6: xaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(addr + 1))->sin6_addr; break;#endif default: xaddr = NULL; } if (!xaddr) return NULL; return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family);}#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))static intpfkey_sockaddr_size(sa_family_t family){ switch (family) { case AF_INET: return PFKEY_ALIGN8(sizeof(struct sockaddr_in));#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6: return PFKEY_ALIGN8(sizeof(struct sockaddr_in6));#endif default: return 0; } /* NOTREACHED */}static inline int pfkey_mode_from_xfrm(int mode){ switch(mode) { case XFRM_MODE_TRANSPORT: return IPSEC_MODE_TRANSPORT; case XFRM_MODE_TUNNEL: return IPSEC_MODE_TUNNEL; case XFRM_MODE_BEET: return IPSEC_MODE_BEET; default: return -1; }}static inline int pfkey_mode_to_xfrm(int mode){ switch(mode) { case IPSEC_MODE_ANY: /*XXX*/ case IPSEC_MODE_TRANSPORT: return XFRM_MODE_TRANSPORT; case IPSEC_MODE_TUNNEL: return XFRM_MODE_TUNNEL; case IPSEC_MODE_BEET: return XFRM_MODE_BEET; default: return -1; }}static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc){ struct sk_buff *skb; struct sadb_msg *hdr; struct sadb_sa *sa; struct sadb_lifetime *lifetime; struct sadb_address *addr; struct sadb_key *key; struct sadb_x_sa2 *sa2; struct sockaddr_in *sin; struct sadb_x_sec_ctx *sec_ctx; struct xfrm_sec_ctx *xfrm_ctx; int ctx_size = 0;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct sockaddr_in6 *sin6;#endif int size; int auth_key_size = 0; int encrypt_key_size = 0; int sockaddr_size; struct xfrm_encap_tmpl *natt = NULL; int mode; /* address family check */ sockaddr_size = pfkey_sockaddr_size(x->props.family); if (!sockaddr_size) return ERR_PTR(-EINVAL); /* base, SA, (lifetime (HSC),) address(SD), (address(P),) key(AE), (identity(SD),) (sensitivity)> */ size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) + sizeof(struct sadb_lifetime) + ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) + ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) + sizeof(struct sadb_address)*2 + sockaddr_size*2 + sizeof(struct sadb_x_sa2); if ((xfrm_ctx = x->security)) { ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); size += sizeof(struct sadb_x_sec_ctx) + ctx_size; } /* identity & sensitivity */ if ((x->props.family == AF_INET && x->sel.saddr.a4 != x->props.saddr.a4)#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) || (x->props.family == AF_INET6 && memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr)))#endif ) size += sizeof(struct sadb_address) + sockaddr_size; if (add_keys) { if (x->aalg && x->aalg->alg_key_len) { auth_key_size = PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8); size += sizeof(struct sadb_key) + auth_key_size; } if (x->ealg && x->ealg->alg_key_len) { encrypt_key_size = PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8); size += sizeof(struct sadb_key) + encrypt_key_size; } } if (x->encap) natt = x->encap; if (natt && natt->encap_type) { size += sizeof(struct sadb_x_nat_t_type); size += sizeof(struct sadb_x_nat_t_port); size += sizeof(struct sadb_x_nat_t_port); } skb = alloc_skb(size + 16, GFP_ATOMIC); if (skb == NULL) return ERR_PTR(-ENOBUFS); /* call should fill header later */ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); memset(hdr, 0, size); /* XXX do we need this ? */ hdr->sadb_msg_len = size / sizeof(uint64_t); /* sa */ sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_spi = x->id.spi; sa->sadb_sa_replay = x->props.replay_window; switch (x->km.state) { case XFRM_STATE_VALID: sa->sadb_sa_state = x->km.dying ? SADB_SASTATE_DYING : SADB_SASTATE_MATURE; break; case XFRM_STATE_ACQ: sa->sadb_sa_state = SADB_SASTATE_LARVAL; break; default: sa->sadb_sa_state = SADB_SASTATE_DEAD; break; } sa->sadb_sa_auth = 0; if (x->aalg) { struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0); sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0; } sa->sadb_sa_encrypt = 0; BUG_ON(x->ealg && x->calg); if (x->ealg) { struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0); sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; } /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */ if (x->calg) { struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0); sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; } sa->sadb_sa_flags = 0; if (x->props.flags & XFRM_STATE_NOECN) sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; if (x->props.flags & XFRM_STATE_DECAP_DSCP) sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; if (x->props.flags & XFRM_STATE_NOPMTUDISC) sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; /* hard time */ if (hsc & 2) { lifetime = (struct sadb_lifetime *) skb_put(skb, sizeof(struct sadb_lifetime)); lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime)/sizeof(uint64_t); lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.hard_packet_limit); lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit); lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds; lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds; } /* soft time */ if (hsc & 1) { lifetime = (struct sadb_lifetime *) skb_put(skb, sizeof(struct sadb_lifetime)); lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime)/sizeof(uint64_t); lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.soft_packet_limit); lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit); lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds; lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds; } /* current time */ lifetime = (struct sadb_lifetime *) skb_put(skb, sizeof(struct sadb_lifetime)); lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime)/sizeof(uint64_t); lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; lifetime->sadb_lifetime_allocations = x->curlft.packets; lifetime->sadb_lifetime_bytes = x->curlft.bytes; lifetime->sadb_lifetime_addtime = x->curlft.add_time; lifetime->sadb_lifetime_usetime = x->curlft.use_time; /* src address */ addr = (struct sadb_address*) skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); addr->sadb_address_len = (sizeof(struct sadb_address)+sockaddr_size)/ sizeof(uint64_t); addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; /* "if the ports are non-zero, then the sadb_address_proto field, normally zero, MUST be filled in with the transport protocol's number." - RFC2367 */ addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; if (x->props.family == AF_INET) { addr->sadb_address_prefixlen = 32; sin = (struct sockaddr_in *) (addr + 1); sin->sin_family = AF_INET; sin->sin_addr.s_addr = x->props.saddr.a4; sin->sin_port = 0; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); }#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (x->props.family == AF_INET6) { addr->sadb_address_prefixlen = 128; sin6 = (struct sockaddr_in6 *) (addr + 1); sin6->sin6_family = AF_INET6; sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; memcpy(&sin6->sin6_addr, x->props.saddr.a6, sizeof(struct in6_addr)); sin6->sin6_scope_id = 0; }#endif else BUG(); /* dst address */ addr = (struct sadb_address*) skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); addr->sadb_address_len = (sizeof(struct sadb_address)+sockaddr_size)/ sizeof(uint64_t); addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; addr->sadb_address_proto = 0; addr->sadb_address_prefixlen = 32; /* XXX */ addr->sadb_address_reserved = 0; if (x->props.family == AF_INET) { sin = (struct sockaddr_in *) (addr + 1); sin->sin_family = AF_INET; sin->sin_addr.s_addr = x->id.daddr.a4; sin->sin_port = 0; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); if (x->sel.saddr.a4 != x->props.saddr.a4) { addr = (struct sadb_address*) skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); addr->sadb_address_len = (sizeof(struct sadb_address)+sockaddr_size)/ sizeof(uint64_t); addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; addr->sadb_address_proto = pfkey_proto_from_xfrm(x->sel.proto); addr->sadb_address_prefixlen = x->sel.prefixlen_s; addr->sadb_address_reserved = 0; sin = (struct sockaddr_in *) (addr + 1); sin->sin_family = AF_INET; sin->sin_addr.s_addr = x->sel.saddr.a4; sin->sin_port = x->sel.sport; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); } }#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (x->props.family == AF_INET6) { addr->sadb_address_prefixlen = 128; sin6 = (struct sockaddr_in6 *) (addr + 1); sin6->sin6_family = AF_INET6; sin6->sin6_port = 0; sin6->sin6_flowinfo = 0; memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr)); sin6->sin6_scope_id = 0; if (memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr))) { addr = (struct sadb_address *) skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); addr->sadb_address_len = (sizeof(struct sadb_address)+sockaddr_size)/ sizeof(uint64_t); addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; addr->sadb_address_proto = pfkey_proto_from_xfrm(x->sel.proto); addr->sadb_address_prefixlen = x->sel.prefixlen_s; addr->sadb_address_reserved = 0; sin6 = (struct sockaddr_in6 *) (addr + 1); sin6->sin6_family = AF_INET6; sin6->sin6_port = x->sel.sport; sin6->sin6_flowinfo = 0; memcpy(&sin6->sin6_addr, x->sel.saddr.a6, sizeof(struct in6_addr)); sin6->sin6_scope_id = 0; } }#endif else BUG(); /* auth key */ if (add_keys && auth_key_size) { key = (struct sadb_key *) skb_put(skb, sizeof(struct sadb_key)+auth_key_size); key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) / sizeof(uint64_t); key->sadb_key_exttype = SADB_EXT_KEY_AUTH; key->sadb_key_bits = x->aalg->alg_key_len; key->sadb_key_reserved = 0; memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8); } /* encrypt key */ if (add_keys && encrypt_key_size) { key = (struct sadb_key *) skb_put(skb, sizeof(struct sadb_key)+encrypt_key_size); key->sadb_key_len = (sizeof(struct sadb_key) + encrypt_key_size) / sizeof(uint64_t); key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; key->sadb_key_bits = x->ealg->alg_key_len; key->sadb_key_reserved = 0; memcpy(key + 1, x->ealg->alg_key, (x->ealg->alg_key_len+7)/8); } /* sa */ sa2 = (struct sadb_x_sa2 *) skb_put(skb, sizeof(struct sadb_x_sa2)); sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t); sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -