/* wrnad_pfkey.c - Wind River network acceleration daemon (NAD) */ /* * Copyright (c) 2010 Wind River Systems, Inc. * * The right to copy, distribute or otherwise make use of this software * may be licensed only pursuant to the terms of an applicable Wind River * license agreement. */ /* includes */ #if !defined(IPWRNAD) || defined(IPIPSEC2) #include #include #include #include #include #include #include #include "wrnad.h" /* defines */ /* typedefs */ /* imports */ /* globals */ /* locals */ static char recvbuf[WRNAD_RECVBUF_SIZE]; /******************************************************************************* * * wrnad_pfkey_typestr - find pfkey type in string format * * This routine returns the pfkey message type as a string * * RETURNS: string representation of pfkey message type. * * ERRNO: N/A */ const char * wrnad_pfkey_typestr(int type) { switch (type) { case SADB_RESERVED: return "SADB_RESERVED"; case SADB_GETSPI: return "SADB_GETSPI"; case SADB_UPDATE: return "SADB_UPDATE"; case SADB_ADD: return "SADB_ADD"; case SADB_DELETE: return "SADB_DELETE"; case SADB_GET: return "SADB_GET"; case SADB_ACQUIRE: return "SADB_ACQUIRE"; case SADB_REGISTER: return "SADB_REGISTER"; case SADB_EXPIRE: return "SADB_EXPIRE"; case SADB_FLUSH: return "SADB_FLUSH"; case SADB_DUMP: return "SADB_DUMP"; case SADB_X_PROMISC: return "SADB_X_PROMISC"; case SADB_X_SPDADD: return "SADB_X_SPDADD"; case SADB_X_SPDDELETE: return "SADB_X_SPDDELETE"; case SADB_X_SPDFLUSH: return "SADB_X_SPDFLUSH"; /* Linux native */ #ifndef IPWRNAD case SADB_X_PCHANGE: return "SADB_X_PCHANGE"; case SADB_X_SPDUPDATE: return "SADB_X_SPDUPDATE"; case SADB_X_SPDGET: return "SADB_X_SPDGET"; case SADB_X_SPDACQUIRE: return "SADB_X_SPDACQUIRE"; case SADB_X_SPDDUMP: return "SADB_X_SPDDUMP"; case SADB_X_SPDSETIDX: return "SADB_X_SPDSETIDX"; case SADB_X_SPDEXPIRE: return "SADB_X_SPDEXPIRE"; case SADB_X_SPDDELETE2: return "SADB_X_SPDDELETE2"; case SADB_X_NAT_T_NEW_MAPPING: return "SADB_X_NAT_T_NEW_MAPPING"; #endif /* ifndef IPWRNAD */ /* Interpeak BSD-versions */ #ifdef SADB_X_ADDFLOW case SADB_X_ADDFLOW: return "SADB_X_ADDFLOW"; #endif #ifdef SADB_X_DELFLOW case SADB_X_DELFLOW: return "SADB_X_DELFLOW"; #endif #ifdef SADB_X_GRPSPIS case SADB_X_GRPSPIS: return "SADB_X_GRPSPIS"; #endif #ifdef SADB_X_BINDSA case SADB_X_BINDSA: return "SADB_X_BINDSA"; #endif #ifdef SADB_X_FINDFLOW case SADB_X_FINDFLOW: return "SADB_X_FINDFLOW"; #endif #ifdef SADB_X_DUMPFLOW case SADB_X_DUMPFLOW: return "SADB_X_DUMPFLOW"; #endif #ifdef SADB_X_MIGRATE case SADB_X_MIGRATE: return "SADB_X_MIGRATE"; #endif /* Unknown */ default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_satypestr - find pfkey sa type in string format * * This routine returns the pfkey message sa type as a string * * RETURNS: string representation of pfkey message sa type. * * ERRNO: N/A */ static const char * wrnad_pfkey_satypestr(int type) { switch (type) { case SADB_SATYPE_UNSPEC: return "UNSPEC"; case SADB_SATYPE_AH: return "AH"; case SADB_SATYPE_ESP: return "ESP"; case SADB_SATYPE_RSVP: return "RSVP"; case SADB_SATYPE_OSPFV2: return "OSPFV2"; case SADB_SATYPE_RIPV2: return "RIPV2"; case SADB_SATYPE_MIP: return "MIP"; #ifdef SADB_X_SATYPE_IPCOMP case SADB_X_SATYPE_IPCOMP: return "IPCOMP"; #endif default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_sastatestr - find pfkey sa state in string format * * This routine returns the pfkey message sa state as a string * * RETURNS: string representation of pfkey message sa state. * * ERRNO: N/A */ static const char * wrnad_pfkey_sastatestr(int state) { switch (state) { case SADB_SASTATE_LARVAL: return "LARVAL"; case SADB_SASTATE_MATURE: return "MATURE"; case SADB_SASTATE_DYING: return "DYING"; case SADB_SASTATE_DEAD: return "DEAD"; default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_saaalgstr - find pfkey sa aalg in string format * * This routine returns the pfkey message sa aalg as a string * * RETURNS: string representation of pfkey message sa aalg. * * ERRNO: N/A */ static const char * wrnad_pfkey_saaalgstr(int aalg) { switch (aalg) { case SADB_AALG_NONE: return "NONE"; case SADB_AALG_MD5HMAC: return "MD5HMAC"; case SADB_AALG_SHA1HMAC: return "SHA1HMAC"; #ifdef SADB_X_AALG_SHA2_256HMAC case SADB_X_AALG_SHA2_256HMAC: return "SHA2_256HMAC"; #endif #ifdef SADB_X_AALG_SHA2_384HMAC case SADB_X_AALG_SHA2_384HMAC: return "SHA2_384HMAC"; #endif #ifdef SADB_X_AALG_SHA2_512HMAC case SADB_X_AALG_SHA2_512HMAC: return "SHA2_512HMAC"; #endif #ifdef SADB_X_AALG_RIPEMD160HMAC case SADB_X_AALG_RIPEMD160HMAC: return "RIPEMD160HMAC"; #endif #ifdef SADB_X_AALG_AES_XCBC_MAC case SADB_X_AALG_AES_XCBC_MAC: return "AES_XCBC_MAC"; #endif #ifdef SADB_X_AALG_NULL case SADB_X_AALG_NULL: return "NULL"; #endif default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_saealgstr - find pfkey sa ealg in string format * * This routine returns the pfkey message sa ealg as a string * * RETURNS: string representation of pfkey message sa ealg. * * ERRNO: N/A */ static const char * wrnad_pfkey_saealgstr(int ealg) { switch (ealg) { case SADB_EALG_NONE: return "NONE"; case SADB_EALG_DESCBC: return "DESCBC"; case SADB_EALG_3DESCBC: return "3DESCBC"; #ifndef IPWRNAD case SADB_X_EALG_CASTCBC: return "CASTCBC"; case SADB_X_EALG_BLOWFISHCBC: return "BLOWFISHCBC"; case SADB_EALG_NULL: return "NULL"; #endif case SADB_X_EALG_AESCBC: return "AESCBC"; #ifdef SADB_X_EALG_AESCTR case SADB_X_EALG_AESCTR: return "AESCTR"; #ifndef IPWRNAD case SADB_X_EALG_AES_CCM_ICV8: return "AES_CCM_ICV8"; case SADB_X_EALG_AES_CCM_ICV12: return "AES_CCM_ICV12"; case SADB_X_EALG_AES_CCM_ICV16: return "AES_CCM_ICV16"; case SADB_X_EALG_AES_GCM_ICV8: return "AES_GCM_ICV8"; case SADB_X_EALG_AES_GCM_ICV12: return "AES_GCM_ICV12"; case SADB_X_EALG_AES_GCM_ICV16: return "AES_GCM_ICV16"; case SADB_X_EALG_CAMELLIACBC: return "CAMELLIACBC"; #endif #endif /* SADB_X_EALG_AESCTR */ default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_exttypestr - find pfkey extension header type in string format * * This routine returns the pfkey extension header type as a string * * RETURNS: string representation of pfkey extension header type. * * ERRNO: N/A */ static const char * wrnad_pfkey_exttypestr(int type) { switch (type) { case SADB_EXT_RESERVED: return "SADB_EXT_RESERVED"; case SADB_EXT_SA: return "SADB_EXT_SA"; case SADB_EXT_LIFETIME_CURRENT: return "SADB_EXT_LIFETIME_CURRENT"; case SADB_EXT_LIFETIME_HARD: return "SADB_EXT_LIFETIME_HARD"; case SADB_EXT_LIFETIME_SOFT: return "SADB_EXT_LIFETIME_SOFT"; case SADB_EXT_ADDRESS_SRC: return "SADB_EXT_ADDRESS_SRC"; case SADB_EXT_ADDRESS_DST: return "SADB_EXT_ADDRESS_DST"; case SADB_EXT_ADDRESS_PROXY: return "SADB_EXT_ADDRESS_PROXY"; case SADB_EXT_KEY_AUTH: return "SADB_EXT_KEY_AUTH"; case SADB_EXT_KEY_ENCRYPT: return "SADB_EXT_KEY_ENCRYPT"; case SADB_EXT_IDENTITY_SRC: return "SADB_EXT_IDENTITY_SRC"; case SADB_EXT_IDENTITY_DST: return "SADB_EXT_IDENTITY_DST"; case SADB_EXT_SENSITIVITY: return "SADB_EXT_SENSITIVITY"; case SADB_EXT_PROPOSAL: return "SADB_EXT_PROPOSAL"; case SADB_EXT_SPIRANGE: return "SADB_EXT_SPIRANGE"; case SADB_X_EXT_POLICY: return "SADB_X_EXT_POLICY"; /* Linux */ #ifndef IPWRNAD case SADB_EXT_SUPPORTED_AUTH: return "SADB_EXT_SUPPORTED_AUTH"; case SADB_EXT_SUPPORTED_ENCRYPT: return "SADB_EXT_SUPPORTED_ENCRYPT"; case SADB_X_EXT_KMPRIVATE: return "SADB_X_EXT_KMPRIVATE"; case SADB_X_EXT_NAT_T_TYPE: return "SADB_X_EXT_NAT_T_TYPE"; case SADB_X_EXT_NAT_T_SPORT: return "SADB_X_EXT_NAT_T_SPORT"; case SADB_X_EXT_NAT_T_DPORT: return "SADB_X_EXT_NAT_T_DPORT"; case SADB_X_EXT_NAT_T_OA: return "SADB_X_EXT_NAT_T_OA"; #endif /* ifndef IPWRNAD */ /* Optional */ #ifdef SADB_X_EXT_SEC_CTX case SADB_X_EXT_SEC_CTX: return "SADB_X_EXT_SEC_CTX"; #endif #ifdef SADB_X_EXT_KMADDRESS case SADB_X_EXT_KMADDRESS: return "SADB_X_EXT_KMADDRES"; #endif /* Interpeak/BSD */ #ifdef SADB_X_EXT_SRC_MASK case SADB_X_EXT_SRC_MASK: return "SADB_X_EXT_SRC_MASK"; #endif #ifdef SADB_X_EXT_DST_MASK case SADB_X_EXT_DST_MASK: return "SADB_X_EXT_DST_MASK"; #endif #ifdef SADB_X_EXT_PROTOCOL case SADB_X_EXT_PROTOCOL: return "SADB_X_EXT_PROTOCOL"; #endif #ifdef SADB_X_EXT_SA2 case SADB_X_EXT_SA2: return "SADB_X_EXT_SA2"; #endif #ifdef SADB_X_EXT_SRC_FLOW case SADB_X_EXT_SRC_FLOW: return "SADB_X_EXT_SRC_FLOW"; #endif #ifdef SADB_X_EXT_DST_FLOW case SADB_X_EXT_DST_FLOW: return "SADB_X_EXT_DST_FLOW"; #endif #ifdef SADB_X_EXT_DST2 case SADB_X_EXT_DST2: return "SADB_X_EXT_DST2"; #endif #ifdef SADB_X_EXT_FLOW_OPTIONS case SADB_X_EXT_FLOW_OPTIONS: return "SADB_X_EXT_FLOW_OPTIONS"; #endif #ifdef SADB_X_EXT_UDPENCAP case SADB_X_EXT_UDPENCAP: return "SADB_X_EXT_UDPENCAP"; #endif #ifdef SADB_X_EXT_SRCMAX_FLOW case SADB_X_EXT_SRCMAX_FLOW: return "SADB_X_EXT_SRCMAX_FLOW"; #endif #ifdef SADB_X_EXT_DSTMAX_FLOW case SADB_X_EXT_DSTMAX_FLOW: return "SADB_X_EXT_DSTMAX_FLOW"; #endif #ifdef SADB_X_EXT_SA_OPTIONS case SADB_X_EXT_SA_OPTIONS: return "SADB_X_EXT_SA_OPTIONS"; #endif default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_policy_typestr - find pfkey policy type in string format * * This routine returns the pfkey policy type as a string * * RETURNS: string representation of pfkey policy type message. * * ERRNO: N/A */ static const char * wrnad_pfkey_policy_typestr(int type) { switch (type) { case IPSEC_POLICY_DISCARD: return "DISCARD"; case IPSEC_POLICY_NONE: return "NONE"; case IPSEC_POLICY_IPSEC: return "IPSEC"; case IPSEC_POLICY_ENTRUST: return "ENTRUST"; case IPSEC_POLICY_BYPASS: return "BYPASS"; default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_policy_dirstr - find pfkey policy dir in string format * * This routine returns the pfkey policy dir as a string * * RETURNS: string representation of pfkey policy dir message. * * ERRNO: N/A */ static const char * wrnad_pfkey_policy_dirstr(int dir) { switch (dir) { case IPSEC_DIR_ANY: return "ANY"; case IPSEC_DIR_INBOUND: return "INBOUND"; case IPSEC_DIR_OUTBOUND: return "OUTBOUND"; case IPSEC_DIR_FWD: return "FWD"; case IPSEC_DIR_MAX: return "MAX"; case IPSEC_DIR_INVALID: return "INVALID"; default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_ipsecrequest_modestr - find pfkey ipsecrequest mode in string format * * This routine returns the pfkey ipsecrequest mode as a string * * RETURNS: string representation of pfkey ipsecrequest mode message. * * ERRNO: N/A */ static const char * wrnad_pfkey_ipsecrequest_modestr(int mode) { switch (mode) { case IPSEC_MODE_ANY: return "ANY"; case IPSEC_MODE_TRANSPORT: return "TRANSPORT"; case IPSEC_MODE_TUNNEL: return "TUNNEL"; case IPSEC_MODE_BEET: return "BEET"; default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_ipsecrequest_levelstr - find pfkey ipsecrequest level in string format * * This routine returns the pfkey ipsecrequest level as a string * * RETURNS: string representation of pfkey ipsecrequest level message. * * ERRNO: N/A */ static const char * wrnad_pfkey_ipsecrequest_levelstr(int level) { switch (level) { case IPSEC_LEVEL_DEFAULT: return "DEFAULT"; case IPSEC_LEVEL_USE: return "USE"; case IPSEC_LEVEL_REQUIRE: return "TUNNEL"; case IPSEC_LEVEL_UNIQUE: return "UNIQUE"; default: return "UNKNOWN"; } } /******************************************************************************* * * wrnad_pfkey_parse_extensions - parse PF_KEY extension headers * * This routine parses PF_KEY extension headers * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ static int wrnad_pfkey_parse_extensions(struct sadb_msg *msg) { struct sadb_ext *ext; struct sadb_sa *sa; struct sadb_lifetime *lifetime; struct sadb_address *address; struct sockaddr *sockaddr; struct sadb_key *key; struct sadb_x_policy *policy; struct sadb_x_ipsecrequest *request; int extlen, i; char buf[64]; unsigned char *p; extlen = (msg->sadb_msg_len << 3) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((char *)msg + sizeof(struct sadb_msg)); while (extlen > 0) { if (!ext->sadb_ext_len || extlen < (ext->sadb_ext_len << 3)) { wrnad_log(LOG_WARNING, "pfkey extension header length is invalid. sadb_ext_len=%d total=%d", ext->sadb_ext_len, extlen); return -1; } switch (ext->sadb_ext_type) { case SADB_EXT_SA: case SADB_X_EXT_SA2: sa = (struct sadb_sa *)ext; if ((sa->sadb_sa_len << 3) != sizeof(struct sadb_sa)) { wrnad_log(LOG_WARNING, "pfkey association extension length %d is invalid", sa->sadb_sa_len); return -1; } wrnad_log(LOG_DEBUG, "Pfkey association extension: len=%u, type=%s, spi=0x%x, replay=%u, state=%s, auth=%s, encrypt=%s, flags=0x%x", sa->sadb_sa_len, wrnad_pfkey_exttypestr(sa->sadb_sa_exttype), ntohl(sa->sadb_sa_spi), sa->sadb_sa_replay, wrnad_pfkey_sastatestr(sa->sadb_sa_state), wrnad_pfkey_saaalgstr(sa->sadb_sa_auth), wrnad_pfkey_saealgstr(sa->sadb_sa_encrypt), sa->sadb_sa_flags); break; case SADB_EXT_LIFETIME_HARD: case SADB_EXT_LIFETIME_SOFT: case SADB_EXT_LIFETIME_CURRENT: lifetime = (struct sadb_lifetime *)ext; if ((lifetime->sadb_lifetime_len << 3) != sizeof(struct sadb_lifetime)) { wrnad_log(LOG_WARNING, "pfkey lifetime extension length %d is invalid", lifetime->sadb_lifetime_len); return -1; } wrnad_log(LOG_DEBUG, "Pfkey lifetime extension: len=%u, type=%s allocations=%u bytes=%u addtime=%u usetime=%u", lifetime->sadb_lifetime_len, wrnad_pfkey_exttypestr(lifetime->sadb_lifetime_exttype), lifetime->sadb_lifetime_allocations, lifetime->sadb_lifetime_bytes, lifetime->sadb_lifetime_addtime, lifetime->sadb_lifetime_usetime); break; case SADB_EXT_ADDRESS_SRC: case SADB_EXT_ADDRESS_DST: case SADB_EXT_ADDRESS_PROXY: #ifdef SADB_X_EXT_SRC_MASK case SADB_X_EXT_SRC_MASK: #endif #ifdef SADB_X_EXT_DST_MASK case SADB_X_EXT_DST_MASK: #endif #ifdef SADB_X_EXT_SRC_FLOW case SADB_X_EXT_SRC_FLOW: #endif #ifdef SADB_X_EXT_DST_FLOW case SADB_X_EXT_DST_FLOW: #endif #ifdef SADB_X_EXT_DST2 case SADB_X_EXT_DST2: #endif #ifdef SADB_X_EXT_SRCMAX_FLOW case SADB_X_EXT_SRCMAX_FLOW: #endif #ifdef SADB_X_EXT_DSTMAX_FLOW case SADB_X_EXT_DSTMAX_FLOW: #endif address = (struct sadb_address *)ext; if ((address->sadb_address_len << 3) < (unsigned short)sizeof(struct sadb_address) + (unsigned short)sizeof(struct sockaddr_in)) { wrnad_log(LOG_WARNING, "Pfkey address extension length %d is invalid", address->sadb_address_len); return -1; } wrnad_log(LOG_DEBUG, "Pfkey address extension: len=%u, type=%s proto=%u prefixlen=%u reserved=%u", address->sadb_address_len, wrnad_pfkey_exttypestr(address->sadb_address_exttype), address->sadb_address_proto, address->sadb_address_prefixlen, address->sadb_address_reserved); sockaddr = (struct sockaddr *)(address + 1); if (sockaddr->sa_family == AF_INET) { struct sockaddr_in *sockaddr_in; sockaddr_in = (struct sockaddr_in *)sockaddr; if (inet_ntop(sockaddr_in->sin_family, &sockaddr_in->sin_addr, buf, sizeof(buf)) != NULL) { wrnad_log(LOG_DEBUG, "Socket address: family=%u, port=%u address=%s", sockaddr_in->sin_family, ntohs(sockaddr_in->sin_port), buf); } } break; case SADB_EXT_KEY_AUTH: case SADB_EXT_KEY_ENCRYPT: key = (struct sadb_key *)ext; if ((key->sadb_key_len << 3) < (unsigned short)sizeof(struct sadb_key)) { wrnad_log(LOG_WARNING, "Pfkey key extension length %d is invalid", key->sadb_key_len); return -1; } wrnad_log(LOG_DEBUG, "Pfkey key extension: len=%u, type=%s bits=%u reserved=%u", key->sadb_key_len, wrnad_pfkey_exttypestr(key->sadb_key_exttype), key->sadb_key_bits, key->sadb_key_reserved); if ((key->sadb_key_len << 3) < (unsigned short)sizeof(struct sadb_key) + (key->sadb_key_bits >> 3)) { wrnad_log(LOG_WARNING, "Pfkey key extension length %d is invalid", key->sadb_key_len); return -1; } p = (unsigned char *)(key + 1); for (i=0; i<(key->sadb_key_bits >> 3); i++) { if (i < (int)sizeof(buf)) sprintf(&buf[i<<1], "%02x", p[i]); } wrnad_log(LOG_DEBUG, "Key: %s", buf); break; case SADB_X_EXT_POLICY: policy = (struct sadb_x_policy *)ext; if ((policy->sadb_x_policy_len << 3) < (unsigned short)sizeof(struct sadb_x_policy) + (unsigned short)sizeof(struct sadb_x_ipsecrequest)) { wrnad_log(LOG_WARNING, "Pfkey policy extension length %d is invalid", policy->sadb_x_policy_len); return -1; } wrnad_log(LOG_DEBUG, "Pfkey policy extension: len=%u type=%s policytype=%s dir=%s reserved=%u id=%u prio=%u", policy->sadb_x_policy_len, wrnad_pfkey_exttypestr(policy->sadb_x_policy_exttype), wrnad_pfkey_policy_typestr(policy->sadb_x_policy_type), wrnad_pfkey_policy_dirstr(policy->sadb_x_policy_dir), policy->sadb_x_policy_reserved, policy->sadb_x_policy_id, policy->sadb_x_policy_priority); request = (struct sadb_x_ipsecrequest *)(policy + 1); wrnad_log(LOG_DEBUG, "Pfkey ipsec request extension: len=%u proto=%s mode=%s level=%s", request->sadb_x_ipsecrequest_len, request->sadb_x_ipsecrequest_proto == IPPROTO_AH ? "AH" : "ESP", wrnad_pfkey_ipsecrequest_modestr(request->sadb_x_ipsecrequest_mode), wrnad_pfkey_ipsecrequest_levelstr(request->sadb_x_ipsecrequest_level)); break; default: wrnad_log(LOG_DEBUG, "Pfkey extension header: len=%u, type=%s(%d)", ext->sadb_ext_len, wrnad_pfkey_exttypestr(ext->sadb_ext_type), ext->sadb_ext_type); break; } extlen -= ext->sadb_ext_len << 3; ext = (struct sadb_ext *)((char *)ext + (ext->sadb_ext_len << 3)); } return 0; } /******************************************************************************* * * wrnad_pfkey_sa_handler - pfkey handler for SA messages * * This routine handles pfkey SA messages. * * RETURNS: -1 = failed * 0 = skip * 1 = action * * ERRNO: N/A */ static int wrnad_pfkey_sa_handler(struct sadb_msg *msg) { int ret; ret = wrnad_pfkey_parse_extensions(msg); if (ret == 0) ret = 1; return ret; } /******************************************************************************* * * wrnad_pfkey_spd_handler - pfkey handler for SPD messages * * This routine handles pfkey SA messages. * * RETURNS: -1 = failed * 0 = skip * 1 = action * * ERRNO: N/A */ static int wrnad_pfkey_spd_handler(struct sadb_msg *msg) { int ret; ret = wrnad_pfkey_parse_extensions(msg); if (ret == 0) ret = 1; return ret; } /******************************************************************************* * * wrnad_pfkey_find_handler - find pfkey handler * * This routine returns a handler form the pfkey message type. * * RETURNS: handler or NULL if not found * * ERRNO: N/A */ static wrnad_pfkey_handler wrnad_pfkey_find_handler(struct sadb_msg *msg) { switch (msg->sadb_msg_type) { /* SA's */ case SADB_ADD: case SADB_DELETE: case SADB_FLUSH: #ifdef SADB_X_GRPSPIS case SADB_X_GRPSPIS: #endif return wrnad_pfkey_sa_handler; /* Flows */ case SADB_X_SPDADD: case SADB_X_SPDDELETE: case SADB_X_SPDFLUSH: #ifdef SADB_X_ADDFLOW case SADB_X_ADDFLOW: #endif #ifdef SADB_X_DELFLOW case SADB_X_DELFLOW: #endif return wrnad_pfkey_spd_handler; default: return NULL; } } /******************************************************************************* * * wrnad_pfkey_parse - parse message received on pfkey socket * * This routine parses indivudual messages received on a pfkey socket * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ static int wrnad_pfkey_parse(int fd, struct sadb_msg *msg) { wrnad_pfkey_handler f; int ret; /* Find handler */ if ((f = wrnad_pfkey_find_handler(msg))) { ret = f(msg); if (ret == 1) { /* Send pfkey message over MIPC */ msg->sadb_msg_seq = 0x80000000; /* Linux does not always seem to clear the reserved field */ msg->sadb_msg_reserved = 0; ret = wrnad_mipc_send_pfkey(fd, msg); } return ret; } else { wrnad_log(LOG_DEBUG, "No handler found for pfkey message type %d (%s)", msg->sadb_msg_type, wrnad_pfkey_typestr(msg->sadb_msg_type)); return -1; } } /******************************************************************************* * * wrnad_pfkey_scan - scan message received on pfkey socket * * This routine scans messages received on a pfkey socket * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ static int wrnad_pfkey_scan(char *buf, int buflen, int fd) { struct sadb_msg *msg; msg = (struct sadb_msg *)buf; if (buflen >= (int)sizeof(*msg) && buflen == (msg->sadb_msg_len << 3)) { wrnad_log(LOG_DEBUG, "Pfkey base header: version=%u, type=%s, errno=%u, satype=%s, len=%u, reserved=%u, seq=%u, pid=%u", msg->sadb_msg_version, wrnad_pfkey_typestr(msg->sadb_msg_type), msg->sadb_msg_errno, wrnad_pfkey_satypestr(msg->sadb_msg_satype), msg->sadb_msg_len, msg->sadb_msg_reserved, msg->sadb_msg_seq, msg->sadb_msg_pid); if (msg->sadb_msg_version == PF_KEY_V2) { if (wrnad_pfkey_parse(fd, msg) >= 0) { wrnad_log(LOG_DEBUG, "Pfkey message type %s handled ok.", wrnad_pfkey_typestr(msg->sadb_msg_type)); } } } else { wrnad_log(LOG_WARNING, "Pfkey message broken! Length was %d.", buflen); return -1; } return 0; } /******************************************************************************* * * wrnad_pfkey_close - close pfkey socket * * This routine closes a pfkey socket * * RETURNS: N/A * * ERRNO: N/A */ void wrnad_pfkey_close(int fd) { if (fd >= 0) close(fd); } /******************************************************************************* * * wrnad_pfkey_open - open and register pfkey socket * * This routine opens a rtnetlink socket and binds it. * * RETURNS: socket descriptor if exited normally, else -1. * * ERRNO: N/A */ int wrnad_pfkey_open(void) { int fd, ret; struct sadb_msg msg; fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2); if (fd < 0) { wrnad_log(LOG_ERR, "Failed to open pfkey socket!"); return -1; } wrnad_log(LOG_DEBUG, "Pfkey socket %d created.", fd); msg.sadb_msg_version = PF_KEY_V2; msg.sadb_msg_type = SADB_REGISTER; msg.sadb_msg_errno = 0; msg.sadb_msg_satype = SADB_SATYPE_ESP; msg.sadb_msg_len = sizeof(msg) >> 3; msg.sadb_msg_reserved = 0; msg.sadb_msg_seq = 0; msg.sadb_msg_pid = getpid(); ret = send(fd, &msg, sizeof(msg), 0); if (ret < 0) { wrnad_log(LOG_ERR, "Failed to register for SATYPE ESP!"); return -1; } msg.sadb_msg_version = PF_KEY_V2; msg.sadb_msg_type = SADB_REGISTER; msg.sadb_msg_errno = 0; msg.sadb_msg_satype = SADB_SATYPE_AH; msg.sadb_msg_len = sizeof(msg) >> 3; msg.sadb_msg_reserved = 0; msg.sadb_msg_seq = 0; msg.sadb_msg_pid = getpid(); ret = send(fd, &msg, sizeof(msg), 0); if (ret < 0) { wrnad_log(LOG_ERR, "Failed to register for SATYPE AH!"); return -1; } return fd; } /******************************************************************************* * * wrnad_pfkey_recv - recv on a pfkey socket * * This routine receives messages on a pfkey socket * * RETURNS: 0 if exited normally, else -1. * * ERRNO: N/A */ int wrnad_pfkey_recv(int pfkeyfd, int mipcfd) { int len; len = recv(pfkeyfd, recvbuf, sizeof(recvbuf), 0); if (len < 0) { wrnad_log(LOG_ERR, "Recv on pfkey socket %d interrupted by error %s -> exit.", pfkeyfd, strerror(errno)); return -1; } else if (len == 0) { wrnad_log(LOG_ERR, "Recv on pfkey socket %d interrupted by EOF.", pfkeyfd); return -1; } wrnad_log(LOG_DEBUG, "Recv on pfkey socket %d returned %d bytes of data.", pfkeyfd, len); /* Scan receive message */ if (wrnad_pfkey_scan(recvbuf, len, mipcfd) < 0) wrnad_log(LOG_WARNING, "Pfkey message failed scan!\n"); else wrnad_log(LOG_DEBUG, "Pfkey message scanned ok.\n"); return 0; } #endif /* !IPWRNAD || IPIPSEC2 */