/* find or construct a string to describe an sparse value * Result may be in STATIC buffer -- NOT RE-ENTRANT! */ const char *sparse_val_show(sparse_names sd, unsigned long val) { const char *p = sparse_name(sd, val); if (p == NULL) { static char buf[12]; /* only one! I hope that it is big enough */ snprintf(buf, sizeof(buf), "%lu??", val); p = buf; } return p; }
/* Finish (building, sending, accepting response for) PF_KEY message. * If response isn't NULL, the response from the kernel will be * placed there (and its errno field will not be examined). * Returns TRUE iff all appears well. */ static bool finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1] , const char *description , const char *text_said , pfkey_buf *response) { struct sadb_msg *pfkey_msg; bool success = TRUE; int error; error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); if (error != 0) { loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d" , description, text_said, error); success = FALSE; } else { size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; DBG(DBG_KLIPS, DBG_log("finish_pfkey_msg: %s message %u for %s %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said); DBG_dump(NULL, (void *) pfkey_msg, len)); if (!no_klips) { ssize_t r = write(pfkeyfd, pfkey_msg, len); if (r != (ssize_t)len) { if (r < 0) { log_errno((e , "pfkey write() of %s message %u" " for %s %s failed" , sparse_val_show(pfkey_type_names , pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said)); } else { loglog(RC_LOG_SERIOUS , "ERROR: pfkey write() of %s message %u" " for %s %s truncated: %ld instead of %ld" , sparse_val_show(pfkey_type_names , pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said , (long)r, (long)len); } success = FALSE; /* if we were compiled with debugging, but we haven't already * dumped the KLIPS command, do so. */ #ifdef DEBUG if ((cur_debugging & DBG_KLIPS) == 0) DBG_dump(NULL, (void *) pfkey_msg, len); #endif } else { /* Check response from KLIPS. * It ought to be an echo, perhaps with additional info. * If the caller wants it, response will point to space. */ pfkey_buf b; pfkey_buf *bp = response != NULL? response : &b; if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq)) { loglog(RC_LOG_SERIOUS , "ERROR: no response to our PF_KEY %s message for %s %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said); success = FALSE; } else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) { loglog(RC_LOG_SERIOUS , "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)" , sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said , sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type)); success = FALSE; } else if (response == NULL && bp->msg.sadb_msg_errno != 0) { /* KLIPS is signalling a problem */ loglog(RC_LOG_SERIOUS , "ERROR: PF_KEY %s response for %s %s included errno %u: %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said , (unsigned) bp->msg.sadb_msg_errno , strerror(bp->msg.sadb_msg_errno)); success = FALSE; } } } } /* all paths must exit this way to free resources */ pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); return success; }
/** 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 bool netlink_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); }