📄 kernel_netlink.c
字号:
{ break; } else if (proto_info[0].encapsulation != ENCAPSULATION_MODE_TUNNEL && satype != SADB_X_SATYPE_INT) { break; } else { req.u.p.dir = XFRM_POLICY_FWD; } ok &= netlink_policy(&req.n, enoent_ok, text_said); break; } return ok;}/** netlink_add_sa - Add an SA into the kernel SPDB via netlink * * @param sa Kernel SA to add/modify * @param replace boolean - true if this replaces an existing SA * @return bool True if successfull */static boolnetlink_add_sa(const struct kernel_sa *sa, bool replace){ struct { struct nlmsghdr n; struct xfrm_usersa_info p; char data[1024]; } req; struct rtattr *attr; memset(&req, 0, sizeof(req)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; ip2xfrm(sa->src, &req.p.saddr); ip2xfrm(sa->dst, &req.p.id.daddr); req.p.id.spi = sa->spi; req.p.id.proto = satype2proto(sa->satype); req.p.family = sa->src->u.v4.sin_family; req.p.mode = (sa->encapsulation == ENCAPSULATION_MODE_TUNNEL); req.p.replay_window = sa->replay_window; req.p.reqid = sa->reqid; req.p.lft.soft_byte_limit = XFRM_INF; req.p.lft.soft_packet_limit = XFRM_INF; req.p.lft.hard_byte_limit = XFRM_INF; req.p.lft.hard_packet_limit = XFRM_INF; req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.p))); attr = (struct rtattr *)((char *)&req + req.n.nlmsg_len); if (sa->authkeylen) { struct xfrm_algo algo; const char *name; name = sparse_name(aalg_list, sa->authalg); if (!name) { loglog(RC_LOG_SERIOUS, "unknown authentication algorithm: %u" , sa->authalg); return FALSE; } strcpy(algo.alg_name, name); algo.alg_key_len = sa->authkeylen * BITS_PER_BYTE; attr->rta_type = XFRMA_ALG_AUTH; attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->authkeylen); memcpy(RTA_DATA(attr), &algo, sizeof(algo)); memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->authkey , sa->authkeylen); req.n.nlmsg_len += attr->rta_len; attr = (struct rtattr *)((char *)attr + attr->rta_len); } if (sa->enckeylen) { struct xfrm_algo algo; const char *name; name = sparse_name(ealg_list, sa->encalg); if (!name) { loglog(RC_LOG_SERIOUS, "unknown encryption algorithm: %u" , sa->encalg); return FALSE; } strcpy(algo.alg_name, name); algo.alg_key_len = sa->enckeylen * BITS_PER_BYTE; attr->rta_type = XFRMA_ALG_CRYPT; attr->rta_len = RTA_LENGTH(sizeof(algo) + sa->enckeylen); memcpy(RTA_DATA(attr), &algo, sizeof(algo)); memcpy((char *)RTA_DATA(attr) + sizeof(algo), sa->enckey , sa->enckeylen); req.n.nlmsg_len += attr->rta_len; attr = (struct rtattr *)((char *)attr + attr->rta_len); } if (sa->satype == SADB_X_SATYPE_COMP) { struct xfrm_algo algo; const char *name; name = sparse_name(calg_list, sa->encalg); if (!name) { loglog(RC_LOG_SERIOUS, "unknown compression algorithm: %u" , sa->encalg); return FALSE; } strcpy(algo.alg_name, name); algo.alg_key_len = 0; attr->rta_type = XFRMA_ALG_COMP; attr->rta_len = RTA_LENGTH(sizeof(algo)); memcpy(RTA_DATA(attr), &algo, sizeof(algo)); req.n.nlmsg_len += attr->rta_len; attr = (struct rtattr *)((char *)attr + attr->rta_len); }#ifdef NAT_TRAVERSAL if (sa->natt_type) { struct xfrm_encap_tmpl natt; natt.encap_type = sa->natt_type; natt.encap_sport = ntohs(sa->natt_sport); natt.encap_dport = ntohs(sa->natt_dport); memset (&natt.encap_oa, 0, sizeof (natt.encap_oa)); attr->rta_type = XFRMA_ENCAP; attr->rta_len = RTA_LENGTH(sizeof(natt)); memcpy(RTA_DATA(attr), &natt, sizeof(natt)); req.n.nlmsg_len += attr->rta_len; attr = (struct rtattr *)((char *)attr + attr->rta_len); }#endif return send_netlink_msg(&req.n, NULL, 0, "Add SA", sa->text_said);}/** netlink_del_sa - Delete an SA from the Kernel * * @param sa Kernel SA to be deleted * @return bool True if successfull */static boolnetlink_del_sa(const struct kernel_sa *sa){ struct { struct nlmsghdr n; struct xfrm_usersa_id id; char data[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = XFRM_MSG_DELSA; ip2xfrm(sa->dst, &req.id.daddr); req.id.spi = sa->spi; req.id.family = sa->src->u.v4.sin_family; req.id.proto = sa->proto; req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); return send_netlink_msg(&req.n, NULL, 0, "Del SA", sa->text_said);}static voidlinux_pfkey_register_response(const struct sadb_msg *msg){ switch (msg->sadb_msg_satype) { case SADB_SATYPE_ESP:#ifdef KERNEL_ALG kernel_alg_register_pfkey(msg, msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);#endif break; case SADB_X_SATYPE_IPCOMP: can_do_IPcomp = TRUE; break; default: break; }}/** linux_pfkey_register - Register via PFKEY our capabilities * */static voidlinux_pfkey_register(void){ pfkey_register_proto(SADB_SATYPE_AH, "AH"); pfkey_register_proto(SADB_SATYPE_ESP, "ESP"); pfkey_register_proto(SADB_X_SATYPE_IPCOMP, "IPCOMP"); pfkey_close();}/** Create ip_address out of xfrm_address_t. * * @param family * @param src xfrm formatted IP address * @param dst ip_address formatted destination * @return err_t NULL if okay, otherwise an error */static err_txfrm_to_ip_address(unsigned family, const xfrm_address_t *src, ip_address *dst){ switch (family) { case AF_INET: /* IPv4 */ initaddr((const void *) &src->a4, sizeof(src->a4), family, dst); return NULL; case AF_INET6: /* IPv6 */ initaddr((const void *) &src->a6, sizeof(src->a6), family, dst); return NULL; default: return "unknown address family"; }}static voidnetlink_acquire(struct nlmsghdr *n){ struct xfrm_user_acquire *acquire; const xfrm_address_t *srcx, *dstx; int src_proto, dst_proto; ip_address src, dst; ip_subnet ours, his; unsigned family; unsigned transport_proto; err_t ugh = NULL; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*acquire))) { openswan_log("netlink_acquire got message with length %lu < %lu bytes; ignore message" , (unsigned long) n->nlmsg_len , (unsigned long) sizeof(*acquire)); return; } acquire = NLMSG_DATA(n); srcx = &acquire->sel.saddr; dstx = &acquire->sel.daddr; family = acquire->policy.sel.family; transport_proto = acquire->sel.proto; src_proto = 0; /* XXX-MCR where to get protocol from? */ dst_proto = 0; /* ditto */ /* XXX also the type of src/dst should be checked to make sure * that they aren't v4 to v6 or something goofy */ if (!(ugh = xfrm_to_ip_address(family, srcx, &src)) && !(ugh = xfrm_to_ip_address(family, dstx, &dst)) && !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ") && !(ugh = addrtosubnet(&src, &ours)) && !(ugh = addrtosubnet(&dst, &his))) record_and_initiate_opportunistic(&ours, &his, transport_proto , "%acquire-netlink"); if (ugh != NULL) openswan_log("XFRM_MSG_ACQUIRE message from kernel malformed: %s", ugh);}static voidnetlink_shunt_expire(struct xfrm_userpolicy_info *pol){ const xfrm_address_t *srcx, *dstx; ip_address src, dst; unsigned family; unsigned transport_proto; err_t ugh = NULL; srcx = &pol->sel.saddr; dstx = &pol->sel.daddr; family = pol->sel.family; transport_proto = pol->sel.proto; if ((ugh = xfrm_to_ip_address(family, srcx, &src)) || (ugh = xfrm_to_ip_address(family, dstx, &dst))) { openswan_log("XFRM_MSG_POLEXPIRE message from kernel malformed: %s", ugh); return; } replace_bare_shunt(&src, &dst , BOTTOM_PRIO , SPI_PASS , FALSE , transport_proto , "delete expired bare shunt");}static voidnetlink_policy_expire(struct nlmsghdr *n){ struct xfrm_user_polexpire *upe; struct { struct nlmsghdr n; struct xfrm_userpolicy_id id; } req; struct { struct nlmsghdr n; struct xfrm_userpolicy_info pol; char data[1024]; } rsp; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(*upe))) { openswan_log("netlink_policy_expire got message with length %lu < %lu bytes; ignore message" , (unsigned long) n->nlmsg_len , (unsigned long) sizeof(*upe)); return; } upe = NLMSG_DATA(n); req.id.dir = upe->pol.dir; req.id.index = upe->pol.index; req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = XFRM_MSG_GETPOLICY; req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.id))); rsp.n.nlmsg_type = XFRM_MSG_NEWPOLICY; if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get policy", "?")) { return; } else if (rsp.n.nlmsg_type == NLMSG_ERROR) { DBG(DBG_KLIPS, DBG_log("netlink_policy_expire: policy died on us: " "dir=%d, index=%d" , req.id.dir, req.id.index)); return; } else if (rsp.n.nlmsg_len < NLMSG_LENGTH(sizeof(rsp.pol))) { openswan_log("netlink_policy_expire: XFRM_MSG_GETPOLICY returned message with length %lu < %lu bytes; ignore message" , (unsigned long) rsp.n.nlmsg_len , (unsigned long) sizeof(rsp.pol)); return; } else if (req.id.index != rsp.pol.index) { DBG(DBG_KLIPS, DBG_log("netlink_policy_expire: policy was replaced: " "dir=%d, oldindex=%d, newindex=%d" , req.id.dir, req.id.index, rsp.pol.index)); return; } else if (upe->pol.curlft.add_time != rsp.pol.curlft.add_time) { DBG(DBG_KLIPS, DBG_log("netlink_policy_expire: policy was replaced " " and you have won the lottery: " "dir=%d, index=%d" , req.id.dir, req.id.index)); return; } switch (upe->pol.dir) { case XFRM_POLICY_OUT: netlink_shunt_expire(&rsp.pol); break; }}static boolnetlink_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;}static voidnetlink_process_msg(void){ while (netlink_get()) ;}static ipsec_spi_tnetlink_get_spi(const ip_address *src, const ip_address *dst, int proto, bool tunnel_mode, unsigned reqid, ipsec_spi_t min, ipsec_spi_t max, const char *text_said){ struct { struct nlmsghdr n; struct xfrm_userspi_info spi; } req; struct { struct nlmsghdr n; union { struct nlmsgerr e; struct xfrm_usersa_info sa; } u; char data[1024]; } rsp; memset(&req, 0, sizeof(req)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; ip2xfrm(src, &req.spi.info.saddr); ip2xfrm(dst, &req.spi.info.id.daddr); req.spi.info.mode = tunnel_mode; req.spi.info.reqid = reqid; req.spi.info.id.proto = proto; req.spi.info.family = src->u.v4.sin_family; req.spi.min = min; req.spi.max = max; req.n.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.spi))); rsp.n.nlmsg_type = XFRM_MSG_NEWSA; if (!send_netlink_msg(&req.n, &rsp.n, sizeof(rsp), "Get SPI", text_said)) return 0; else if (rsp.n.nlmsg_type == NLMSG_ERROR) { loglog(RC_LOG_SERIOUS , "ERROR: netlink_get_spi for %s failed with errno %d: %s" , text_said , -rsp.u.e.error , strerror(-rsp.u.e.error)); return 0; } else if (rsp.n.nlmsg_len < NLMSG_LENGTH(sizeof(rsp.u.sa))) { openswan_log("netlink_get_spi: XFRM_MSG_ALLOCSPI returned message with length %lu < %lu bytes; ignore message" , (unsigned long) rsp.n.nlmsg_len , (unsigned long) sizeof(rsp.u.sa)); return 0; } DBG(DBG_KLIPS, DBG_log("netlink_get_spi: allocated 0x%x for %s" , ntohl(rsp.u.sa.id.spi), text_said)); return rsp.u.sa.id.spi;}const struct kernel_ops linux_kernel_ops = { type: KERNEL_TYPE_LINUX, inbound_eroute: 1, policy_lifetime: 1, async_fdp: &netlink_bcast_fd, init: init_netlink, pfkey_register: linux_pfkey_register, pfkey_register_response: linux_pfkey_register_response, process_msg: netlink_process_msg, raw_eroute: netlink_raw_eroute, add_sa: netlink_add_sa, del_sa: netlink_del_sa, process_queue: NULL, grp_sa: NULL, get_spi: netlink_get_spi,};#endif /* linux && KLIPS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -