首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 操作系统 > UNIXLINUX >

Linux内核中PF_KEY协议族的兑现(4)

2012-09-03 
Linux内核中PF_KEY协议族的实现(4)本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请

Linux内核中PF_KEY协议族的实现(4)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

6. 通知回调处理6.1 初始化在pf_key的初始化函数中定义了通知回调结构pfkeyv2_mgr: err = xfrm_register_km(&pfkeyv2_mgr);该结构定义如下:static struct xfrm_mgr pfkeyv2_mgr ={ .id  = "pfkeyv2", .notify  = pfkey_send_notify, .acquire = pfkey_send_acquire, .compile_policy = pfkey_compile_policy, .new_mapping = pfkey_send_new_mapping, .notify_policy = pfkey_send_policy_notify,};6.2 登记/*  net/xfrm/xfrm_state.c */// 就是把xfrm_mgr结构挂接到xfrm_km_list链表int xfrm_register_km(struct xfrm_mgr *km){ write_lock_bh(&xfrm_km_lock);// 将结构挂接到xfrm_km_list链表 list_add_tail(&km->list, &xfrm_km_list); write_unlock_bh(&xfrm_km_lock); return 0;}EXPORT_SYMBOL(xfrm_register_km);6.3 发送通知在pf_key中调用以下两个函数来调用通知回调函数, 分别针对安全策略操作和SA操作:// 安全策略通知回调void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c){ struct xfrm_mgr *km; read_lock(&xfrm_km_lock);// 状态的通知回调函数为notify_policy list_for_each_entry(km, &xfrm_km_list, list)  if (km->notify_policy)   km->notify_policy(xp, dir, c); read_unlock(&xfrm_km_lock);}// SA状态通知回调void km_state_notify(struct xfrm_state *x, struct km_event *c){ struct xfrm_mgr *km; read_lock(&xfrm_km_lock);// 状态的通知回调函数为notify list_for_each_entry(km, &xfrm_km_list, list)  if (km->notify)   km->notify(x, c); read_unlock(&xfrm_km_lock);}调用这些通知函数前要填写事件的相关参数, 如:static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs){ unsigned proto; struct km_event c; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0)  return -EINVAL; xfrm_state_flush(proto);// 填写事件参数// 协议 c.data.proto = proto;// 序列号 c.seq = hdr->sadb_msg_seq;// sock对方(用户空间进程)的pid c.pid = hdr->sadb_msg_pid;// 事件 c.event = XFRM_MSG_FLUSHSA; km_state_notify(NULL, &c); return 0;}6.4 pf_key通知回调函数6.4.1  发送SA消息时的通知回调// 状态通知回调, 在SA操作后调用static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c){// 根据事件类型来发送相关通知 switch (c->event) { case XFRM_MSG_EXPIRE:// SA到期的通知, SA消息类型为SADB_EXPIRE,只是进行了登记的PF_KEY socket可以收到  return key_notify_sa_expire(x, c); case XFRM_MSG_DELSA: case XFRM_MSG_NEWSA: case XFRM_MSG_UPDSA:// SA的通知, SA消息类型为分别为SADB_DELETE, SADB_ADD和SADB_UPDATE,// 所有PF_KEY socket都可以收到  return key_notify_sa(x, c); case XFRM_MSG_FLUSHSA:// 删除全部SA的通知, SA消息类型为分别为SADB_FLUSH, 所有PF_KEY socket都可以收到  return key_notify_sa_flush(c); case XFRM_MSG_NEWAE: /* not yet supported */  break; default:  printk("pfkey: Unknown SA event %d\n", c->event);  break; } return 0;}6.4.2 发送ACQUIRE关于ACQUIRE的作用, 摘一段UNP vol.1, r3中的话:chapter19.5:"When the kernel needs to communicate with a peer and policy says that an SA is required but one is not available, the kernel sends an SADB_ACQUIRE message to key management sockets that have registered the SA type required, containing a proposal extension describing the kernel's proposed algorithms and key lengths. The proposal may be a combination of what is supported by the system and preconfigured policy that limits what is permitted for this communication. The proposal is a list of algorithms, key lengths, and lifetimes, in order of preference. When a key management daemon receives an SADB_ACQUIRE message, it performs the acts required to choose a key that fits one of the kernel's proposed combinations, and installs this key in the kernel. " static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir){ struct sk_buff *skb; struct sadb_msg *hdr; struct sadb_address *addr; struct sadb_x_policy *pol; struct sockaddr_in *sin;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct sockaddr_in6 *sin6;#endif int sockaddr_size; int size; struct sadb_x_sec_ctx *sec_ctx; struct xfrm_sec_ctx *xfrm_ctx; int ctx_size = 0;  sockaddr_size = pfkey_sockaddr_size(x->props.family); if (!sockaddr_size)  return -EINVAL;// 消息长度包括SA基本头, 两个SA地址, 两个网络地址和策略 size = sizeof(struct sadb_msg) +  (sizeof(struct sadb_address) * 2) +  (sockaddr_size * 2) +  sizeof(struct sadb_x_policy);// 还添加AH或ESP中所有算法描述的长度 if (x->id.proto == IPPROTO_AH)  size += count_ah_combs(t); else if (x->id.proto == IPPROTO_ESP)  size += count_esp_combs(t); if ((xfrm_ctx = x->security)) {  ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len);  size +=  sizeof(struct sadb_x_sec_ctx) + ctx_size; }// 分配skb skb =  alloc_skb(size + 16, GFP_ATOMIC); if (skb == NULL)  return -ENOMEM;// 先填基本SA消息头信息  hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_type = SADB_ACQUIRE; hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); hdr->sadb_msg_len = size / sizeof(uint64_t); hdr->sadb_msg_errno = 0; hdr->sadb_msg_reserved = 0; hdr->sadb_msg_seq = x->km.seq = get_acqseq(); hdr->sadb_msg_pid = 0; /* src address */// 填充SA源地址信息 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; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; if (x->props.family == AF_INET) {// IPV4地址  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) {// IPV6地址  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 */// 填充SA目的地址信息 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_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->id.daddr.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->id.daddr.a6, sizeof(struct in6_addr));  sin6->sin6_scope_id = 0; }#endif else  BUG();// 填充策略信息 pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy)); pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; pol->sadb_x_policy_dir = dir+1; pol->sadb_x_policy_id = xp->index; /* Set sadb_comb's. */// 填充AH或ESP的可用算法信息 if (x->id.proto == IPPROTO_AH)  dump_ah_combs(skb, t); else if (x->id.proto == IPPROTO_ESP)  dump_esp_combs(skb, t); /* security context */ if (xfrm_ctx) {// 填充安全上下文信息  sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb,    sizeof(struct sadb_x_sec_ctx) + ctx_size);  sec_ctx->sadb_x_sec_len =    (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t);  sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX;  sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi;  sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg;  sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len;  memcpy(sec_ctx + 1, xfrm_ctx->ctx_str,         xfrm_ctx->ctx_len); }// 广播到进行了登记的PF_KEY套接口 return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);}6.4.3 编译策略// 将sadb_x_policy(标准接口格式)编译为xfrm_policy(内核具体实现格式)static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,                                                u8 *data, int len, int *dir){ struct xfrm_policy *xp; struct sadb_x_policy *pol = (struct sadb_x_policy*)data; struct sadb_x_sec_ctx *sec_ctx;// 选项opt必须是IP_IPSEC_POLICY, 否则出错 switch (sk->sk_family) { case AF_INET:  if (opt != IP_IPSEC_POLICY) {   *dir = -EOPNOTSUPP;   return NULL;  }  break;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) case AF_INET6:  if (opt != IPV6_IPSEC_POLICY) {   *dir = -EOPNOTSUPP;   return NULL;  }  break;#endif default:  *dir = -EINVAL;  return NULL; } *dir = -EINVAL; if (len < sizeof(struct sadb_x_policy) ||     pol->sadb_x_policy_len*8 > len ||     pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS ||     (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))  return NULL;// 分配策略空间 xp = xfrm_policy_alloc(GFP_ATOMIC); if (xp == NULL) {  *dir = -ENOBUFS;  return NULL; }// 填写策略动作 xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?        XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);// 填写策略有效期参数 xp->lft.soft_byte_limit = XFRM_INF; xp->lft.hard_byte_limit = XFRM_INF; xp->lft.soft_packet_limit = XFRM_INF; xp->lft.hard_packet_limit = XFRM_INF; xp->family = sk->sk_family; xp->xfrm_nr = 0;// 解析ipsec请求 if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&     (*dir = parse_ipsecrequests(xp, pol)) < 0)  goto out; /* security context too */ if (len >= (pol->sadb_x_policy_len*8 +     sizeof(struct sadb_x_sec_ctx))) {// 转换安全上下文  char *p = (char *)pol;  struct xfrm_user_sec_ctx *uctx;  p += pol->sadb_x_policy_len*8;  sec_ctx = (struct sadb_x_sec_ctx *)p;  if (len < pol->sadb_x_policy_len*8 +      sec_ctx->sadb_x_sec_len) {   *dir = -EINVAL;   goto out;  }  if ((*dir = verify_sec_ctx_len(p)))   goto out;  uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx);  *dir = security_xfrm_policy_alloc(xp, uctx);  kfree(uctx);  if (*dir)   goto out; } *dir = pol->sadb_x_policy_dir-1; return xp;out: security_xfrm_policy_free(xp); kfree(xp); return NULL;}6.4.4 NAT穿越映射// 发送新映射(NAT穿越)SA消息, 包含SA头, SA, 转换前地址,端口, 转换后的地址端口static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport){ struct sk_buff *skb; struct sadb_msg *hdr; struct sadb_sa *sa; struct sadb_address *addr; struct sadb_x_nat_t_port *n_port; struct sockaddr_in *sin;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct sockaddr_in6 *sin6;#endif int sockaddr_size; int size; __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0); struct xfrm_encap_tmpl *natt = NULL;// 协议的地址长度 sockaddr_size = pfkey_sockaddr_size(x->props.family); if (!sockaddr_size)  return -EINVAL; if (!satype)  return -EINVAL; if (!x->encap)  return -EINVAL;// NAT转换结构 natt = x->encap; /* Build an SADB_X_NAT_T_NEW_MAPPING message:  *  * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) |  * ADDRESS_DST (new addr) | NAT_T_DPORT (new port)  */// 消息总长: SA消息头+SA+两个SA地址+两个协议地址+2个NAT端口  size = sizeof(struct sadb_msg) +  sizeof(struct sadb_sa) +  (sizeof(struct sadb_address) * 2) +  (sockaddr_size * 2) +  (sizeof(struct sadb_x_nat_t_port) * 2);// 分配skb  skb =  alloc_skb(size + 16, GFP_ATOMIC); if (skb == NULL)  return -ENOMEM;// 填写SA头  hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING; hdr->sadb_msg_satype = satype; hdr->sadb_msg_len = size / sizeof(uint64_t); hdr->sadb_msg_errno = 0; hdr->sadb_msg_reserved = 0; hdr->sadb_msg_seq = x->km.seq = get_acqseq(); hdr->sadb_msg_pid = 0; /* SA */// 填写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 = 0; sa->sadb_sa_state = 0; sa->sadb_sa_auth = 0; sa->sadb_sa_encrypt = 0; sa->sadb_sa_flags = 0; /* ADDRESS_SRC (old addr) */// 转换前SA地址参数 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; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; if (x->props.family == AF_INET) {// 填写转换前IPV4协议地址具体参数  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) {// 填写转换前IPV6协议地址具体参数  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(); /* NAT_T_SPORT (old port) */// 填写转换前端口参数 n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; n_port->sadb_x_nat_t_port_port = natt->encap_sport; n_port->sadb_x_nat_t_port_reserved = 0; /* ADDRESS_DST (new 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_DST; addr->sadb_address_proto = 0; addr->sadb_address_reserved = 0; if (x->props.family == AF_INET) {// 填写转换后IPV4协议地址具体参数  addr->sadb_address_prefixlen = 32;  sin = (struct sockaddr_in *) (addr + 1);  sin->sin_family = AF_INET;  sin->sin_addr.s_addr = ipaddr->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) {// 填写转换后IPV6协议地址具体参数  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, &ipaddr->a6, sizeof(struct in6_addr));  sin6->sin6_scope_id = 0; }#endif else  BUG(); /* NAT_T_DPORT (new port) */// 填写转换前端口参数 n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; n_port->sadb_x_nat_t_port_port = sport; n_port->sadb_x_nat_t_port_reserved = 0;// 发送给进行登记了的PF_KEY套接口 return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);}6.4.5 发送策略的通知// 策略通知回调, 在安全策略操作后调用static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c){ if (xp && xp->type != XFRM_POLICY_TYPE_MAIN)  return 0; switch (c->event) { case XFRM_MSG_POLEXPIRE:// 策略到期通知, 空函数  return key_notify_policy_expire(xp, c); case XFRM_MSG_DELPOLICY: case XFRM_MSG_NEWPOLICY: case XFRM_MSG_UPDPOLICY:// 策略的通知, SA消息类型为分别为SADB_X_SPDDELETE, SADB_X_SPDADD, SADB_X_SPDUPDATE等,// 所有PF_KEY socket都可以收到  return key_notify_policy(xp, dir, c); case XFRM_MSG_FLUSHPOLICY:  if (c->data.type != XFRM_POLICY_TYPE_MAIN)   break;// 策略的通知, SA消息类型为分别为SADB_X_FLUSH, 所有PF_KEY socket都可以收到  return key_notify_policy_flush(c); default:  printk("pfkey: Unknown policy event %d\n", c->event);  break; } return 0;}在pf_key.c中只用到了6.4.1和6.4.5的这两个函数....... 待续 ......

热点排行