DEBUG_NO_STATIC int pfkey_x_satype_parse(struct sadb_ext *pfkey_ext) { int error = 0; int i; struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext; DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW, "pfkey_x_satype_parse: enter\n"); /* sanity checks... */ if(pfkey_x_satype->sadb_x_satype_len != sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_satype_parse: " "size wrong ext_len=%d, key_ext_len=%ld.\n", pfkey_x_satype->sadb_x_satype_len, sizeof(struct sadb_x_satype)); SENDERR(EINVAL); } if(!pfkey_x_satype->sadb_x_satype_satype) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_satype_parse: " "satype is zero, must be non-zero.\n"); SENDERR(EINVAL); } if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_satype_parse: " "satype %d > max %d, invalid.\n", pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX); SENDERR(EINVAL); } if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_satype_parse: " "proto lookup from satype=%d failed.\n", pfkey_x_satype->sadb_x_satype_satype); SENDERR(EINVAL); } for(i = 0; i < 3; i++) { if(pfkey_x_satype->sadb_x_satype_reserved[i]) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_satype_parse: " "reserved[%d]=%d must be set to zero.\n", i, pfkey_x_satype->sadb_x_satype_reserved[i]); SENDERR(EINVAL); } } errlab: return error; }
int pfkey_x_satype_process(struct sadb_ext *pfkey_ext, struct pfkey_extracted_data* extr) { int error = 0; struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext; KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_satype_process: .\n"); if(!extr || !extr->ips) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_satype_process: " "extr or extr->ips is NULL, fatal\n"); SENDERR(EINVAL); } if(extr->ips2 == NULL) { extr->ips2 = ipsec_sa_alloc(&error); /* pass error var by pointer */ } if(extr->ips2 == NULL) { SENDERR(-error); } if(!(extr->ips2->ips_said.proto = satype2proto(pfkey_x_satype->sadb_x_satype_satype))) { KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_satype_process: " "proto lookup from satype=%d failed.\n", pfkey_x_satype->sadb_x_satype_satype); SENDERR(EINVAL); } KLIPS_PRINT(debug_pfkey, "klips_debug:pfkey_x_satype_process: " "protocol==%d decoded from satype==%d(%s).\n", extr->ips2->ips_said.proto, pfkey_x_satype->sadb_x_satype_satype, satype2name(pfkey_x_satype->sadb_x_satype_satype)); errlab: return error; }
int pfkey_msg_parse(struct sadb_msg *pfkey_msg, struct pf_key_ext_parsers_def *ext_parsers[], struct sadb_ext *extensions[], int dir) { int error = 0; int remain; struct sadb_ext *pfkey_ext; int extensions_seen = 0; DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n", pfkey_msg->sadb_msg_version, pfkey_msg->sadb_msg_type, pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type), pfkey_msg->sadb_msg_errno, pfkey_msg->sadb_msg_satype, satype2name(pfkey_msg->sadb_msg_satype), pfkey_msg->sadb_msg_len, pfkey_msg->sadb_msg_reserved, pfkey_msg->sadb_msg_seq, pfkey_msg->sadb_msg_pid); if(ext_parsers == NULL) ext_parsers = ext_default_parsers; pfkey_extensions_init(extensions); remain = pfkey_msg->sadb_msg_len; remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN; pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg + sizeof(struct sadb_msg)); extensions[0] = (struct sadb_ext *) pfkey_msg; if(pfkey_msg->sadb_msg_version != PF_KEY_V2) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "not PF_KEY_V2 msg, found %d, should be %d.\n", pfkey_msg->sadb_msg_version, PF_KEY_V2); SENDERR(EINVAL); } if(!pfkey_msg->sadb_msg_type) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "msg type not set, must be non-zero..\n"); SENDERR(EINVAL); } if(pfkey_msg->sadb_msg_type > SADB_MAX) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "msg type=%d > max=%d.\n", pfkey_msg->sadb_msg_type, SADB_MAX); SENDERR(EINVAL); } switch(pfkey_msg->sadb_msg_type) { case SADB_GETSPI: case SADB_UPDATE: case SADB_ADD: case SADB_DELETE: case SADB_GET: case SADB_X_GRPSA: case SADB_X_ADDFLOW: if(!satype2proto(pfkey_msg->sadb_msg_satype)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "satype %d conversion to proto failed for msg_type %d (%s).\n", pfkey_msg->sadb_msg_satype, pfkey_msg->sadb_msg_type, pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); SENDERR(EINVAL); } else { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n", pfkey_msg->sadb_msg_satype, satype2name(pfkey_msg->sadb_msg_satype), satype2proto(pfkey_msg->sadb_msg_satype), pfkey_msg->sadb_msg_type, pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); } case SADB_ACQUIRE: case SADB_REGISTER: case SADB_EXPIRE: if(!pfkey_msg->sadb_msg_satype) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "satype is zero, must be non-zero for msg_type %d(%s).\n", pfkey_msg->sadb_msg_type, pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); SENDERR(EINVAL); } default: } /* errno must not be set in downward messages */ /* this is not entirely true... a response to an ACQUIRE could return an error */ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "errno set to %d.\n", pfkey_msg->sadb_msg_errno); SENDERR(EINVAL); } DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "remain=%d, ext_type=%d(%s), ext_len=%d.\n", remain, pfkey_ext->sadb_ext_type, pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type), pfkey_ext->sadb_ext_len); DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "extensions permitted=%08x, required=%08x.\n", extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); extensions_seen = 1; while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) { /* Is there enough message left to support another extension header? */ if(remain < pfkey_ext->sadb_ext_len) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "remain %d less than ext len %d.\n", remain, pfkey_ext->sadb_ext_len); SENDERR(EINVAL); } DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "parsing ext type=%d remain=%d.\n", pfkey_ext->sadb_ext_type, remain); /* Is the extension header type valid? */ if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "ext type %d invalid, SADB_EXT_MAX=%d.\n", pfkey_ext->sadb_ext_type, SADB_EXT_MAX); SENDERR(EINVAL); } /* Have we already seen this type of extension? */ if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "ext type %d already seen.\n", pfkey_ext->sadb_ext_type); SENDERR(EINVAL); } /* Do I even know about this type of extension? */ if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "ext type %d unknown, ignoring.\n", pfkey_ext->sadb_ext_type); goto next_ext; } /* Is this type of extension permitted for this type of message? */ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] & 1<<pfkey_ext->sadb_ext_type)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "ext type %d not permitted, exts_perm_in=%08x, 1<<type=%08x\n", pfkey_ext->sadb_ext_type, extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], 1<<pfkey_ext->sadb_ext_type); SENDERR(EINVAL); } DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "About to parse extension %d %p with parser %s.\n", pfkey_ext->sadb_ext_type, pfkey_ext, ext_parsers[pfkey_ext->sadb_ext_type]->parser_name); /* Parse the extension */ if((error = (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "extension parsing for type %d failed with error %d.\n", pfkey_ext->sadb_ext_type, error); SENDERR(-error); } DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "Extension %d parsed.\n", pfkey_ext->sadb_ext_type); /* Mark that we have seen this extension and remember the header location */ extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type ); extensions[pfkey_ext->sadb_ext_type] = pfkey_ext; next_ext: /* Calculate how much message remains */ remain -= pfkey_ext->sadb_ext_len; if(!remain) { break; } /* Find the next extension header */ pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext + pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN); } if(remain) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "unexpected remainder of %d.\n", remain); /* why is there still something remaining? */ SENDERR(EINVAL); } /* check required extensions */ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT, "pfkey_msg_parse: " "extensions permitted=%08x, seen=%08x, required=%08x.\n", extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type], extensions_seen, extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]); /* don't check further if it is an error return message since it may not have a body */ if(pfkey_msg->sadb_msg_errno) { SENDERR(-error); } if((extensions_seen & extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) != extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "required extensions missing:%08x.\n", extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] - (extensions_seen & extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type])); SENDERR(EINVAL); } if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW) && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW) != SADB_X_EXT_ADDRESS_DELFLOW) && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA)) || ((((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags & SADB_X_SAFLAGS_CLEARFLOW) != SADB_X_SAFLAGS_CLEARFLOW))) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n", SADB_X_EXT_ADDRESS_DELFLOW - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW), (1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA))); SENDERR(EINVAL); } switch(pfkey_msg->sadb_msg_type) { case SADB_ADD: case SADB_UPDATE: /* check maturity */ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state != SADB_SASTATE_MATURE) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "state=%d for add or update should be MATURE=%d.\n", ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state, SADB_SASTATE_MATURE); SENDERR(EINVAL); } /* check AH and ESP */ switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) { case SADB_SATYPE_AH: if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth != SADB_AALG_NONE)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "auth alg is zero, must be non-zero for AH SAs.\n"); SENDERR(EINVAL); } if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt != SADB_EALG_NONE) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "AH handed encalg=%d, must be zero.\n", ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt); SENDERR(EINVAL); } break; case SADB_SATYPE_ESP: if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != SADB_EALG_NONE)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n", ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); SENDERR(EINVAL); } if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt == SADB_EALG_NULL) && (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth == SADB_AALG_NONE) ) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "ESP handed encNULL+authNONE, illegal combination.\n"); SENDERR(EINVAL); } break; case SADB_X_SATYPE_COMP: if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) && ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt != SADB_EALG_NONE)) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n", ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt, ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype); SENDERR(EINVAL); } if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth != SADB_AALG_NONE) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "COMP handed auth=%d, must be zero.\n", ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth); SENDERR(EINVAL); } break; default: } if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_msg_parse: " "spi=%08lx must be > 255.\n", ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi)); SENDERR(EINVAL); } default: } errlab: return error; }
/** 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); }