diff --git a/src/modules/ims_ipsec_pcscf/cmd.c b/src/modules/ims_ipsec_pcscf/cmd.c index 1a87b9df9ce..317948adef5 100644 --- a/src/modules/ims_ipsec_pcscf/cmd.c +++ b/src/modules/ims_ipsec_pcscf/cmd.c @@ -53,6 +53,8 @@ #include #include +#include + extern str ipsec_listen_addr; extern short ipsec_listen_port; @@ -269,24 +271,82 @@ static int update_contact_ipsec_params(ipsec_t* s, const struct sip_msg* m) return 0; } -static int create_ipsec_tunnel(const str remote_addr, unsigned short proto, ipsec_t* s) +static int convert_ip_address(const str ip_addr, const unsigned int af, struct ip_addr* result) { + memset(result, 0, sizeof(struct ip_addr)); + int return_code = -1; + + //Allocate dynamically memory in order to avoid buffer overflows + char* ipaddr_str = NULL; + if((ipaddr_str = pkg_malloc(ip_addr.len + 1)) == NULL) { + LM_CRIT("Error allocating memory for IP address conversion.\n"); + return -1; + } + memset(ipaddr_str, 0, ip_addr.len + 1); + memcpy(ipaddr_str, ip_addr.s, ip_addr.len); + + int err = 0; + + if((err = inet_pton(af, ipaddr_str, &result->u.addr)) != 1) { + if(err == 0) { + LM_ERR("Error converting ipsec listen IP address. Bad format %.*s\n", ip_addr.len, ip_addr.s); + } + else { + LM_ERR("Error converting ipsec listen IP address: %s\n", strerror(errno)); + } + goto cleanup; // return_code = -1 by default + } + + //Set len by address family + if(af == AF_INET6) { + result->len = 16; + } + else { + result->len = 4; + } + + result->af = af; + + //Set success return code + return_code = 0; + +cleanup: + pkg_free(ipaddr_str); + return return_code; +} + +static int create_ipsec_tunnel(const struct ip_addr *remote_addr, unsigned short proto, ipsec_t* s) { struct mnl_socket* sock = init_mnl_socket(); if (sock == NULL) { return -1; } - LM_DBG("Creating security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %.*s; client port %d server port %d\n", + //Convert ipsec address from str to struct ip_addr + struct ip_addr ipsec_addr; + if(convert_ip_address(ipsec_listen_addr, remote_addr->af, &ipsec_addr) != 0) { + //there is an error msg in convert_ip_address() + return -1; + } + + //Convert to char* for logging + char remote_addr_str[128]; + memset(remote_addr_str, 0, sizeof(remote_addr_str)); + if(inet_ntop(remote_addr->af, remote_addr->u.addr, remote_addr_str, sizeof(remote_addr_str)) == NULL) { + LM_CRIT("Error converting remote IP address: %s\n", strerror(errno)); + return -1; + } + + LM_DBG("Creating security associations: Local IP: %.*s client port: %d server port: %d; UE IP: %s; client port %d server port %d\n", ipsec_listen_addr.len, ipsec_listen_addr.s, ipsec_client_port, ipsec_server_port, - remote_addr.len, remote_addr.s, s->port_uc, s->port_us); + remote_addr_str, s->port_uc, s->port_us); // P-CSCF 'client' tunnel to UE 'server' - add_sa (sock, proto, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik); - add_policy(sock, proto, ipsec_listen_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT); + add_sa (sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, s->ck, s->ik); + add_policy(sock, proto, &ipsec_addr, remote_addr, ipsec_client_port, s->port_us, s->spi_us, IPSEC_POLICY_DIRECTION_OUT); // UE 'client' to P-CSCF 'server' tunnel - add_sa (sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik); - add_policy(sock, proto, remote_addr, ipsec_listen_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN); + add_sa (sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, s->ck, s->ik); + add_policy(sock, proto, remote_addr, &ipsec_addr, s->port_uc, ipsec_server_port, s->spi_ps, IPSEC_POLICY_DIRECTION_IN); close_mnl_socket(sock); @@ -451,7 +511,17 @@ int ipsec_create(struct sip_msg* m, udomain_t* d) goto cleanup; } - if(create_ipsec_tunnel(ci.received_host, ci.received_proto, s) != 0) { + // Get request from reply + struct cell *t = tmb.t_gett(); + if (!t || t == (void*) -1) { + LM_ERR("fill_contact(): Reply without transaction\n"); + return -1; + } + + struct sip_msg* req = t->uas.request; + //// + + if(create_ipsec_tunnel(&req->rcv.src_ip, ci.received_proto, s) != 0) { goto cleanup; } diff --git a/src/modules/ims_ipsec_pcscf/ipsec.c b/src/modules/ims_ipsec_pcscf/ipsec.c index 3b0c1499871..05c8dd88d52 100644 --- a/src/modules/ims_ipsec_pcscf/ipsec.c +++ b/src/modules/ims_ipsec_pcscf/ipsec.c @@ -109,7 +109,7 @@ unsigned short kamailio_to_linux_proto(const unsigned short kamailio_proto) }; } -int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik) +int add_sa(struct mnl_socket* nl_sock, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int s_port, int d_port, int long id, str ck, str ik) { char l_msg_buf[MNL_SOCKET_BUFFER_SIZE]; char l_auth_algo_buf[XFRM_TMPLS_BUF_SIZE]; @@ -120,8 +120,6 @@ int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, struct xfrm_algo* l_auth_algo = NULL; struct xfrm_algo* l_enc_algo = NULL; - char* src_addr = NULL; - char* dest_addr = NULL; memset(l_msg_buf, 0, sizeof(l_msg_buf)); memset(l_auth_algo_buf, 0, sizeof(l_auth_algo_buf)); @@ -133,24 +131,6 @@ int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, return -1; } - // convert input IP addresses and keys to char* - if((src_addr = pkg_malloc(src_addr_param.len+1)) == NULL) { - LM_ERR("Error allocating memory for src addr during SA creation\n"); - return -2; - } - - if((dest_addr = pkg_malloc(dest_addr_param.len+1)) == NULL) { - pkg_free(src_addr); - LM_ERR("Error allocating memory for dest addr during SA creation\n"); - return -3; - } - - memset(src_addr, 0, src_addr_param.len+1); - memset(dest_addr, 0, dest_addr_param.len+1); - - memcpy(src_addr, src_addr_param.s, src_addr_param.len); - memcpy(dest_addr, dest_addr_param.s, dest_addr_param.len); - // nlmsghdr initialization l_nlh = mnl_nlmsg_put_header(l_msg_buf); l_nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; @@ -160,20 +140,34 @@ int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, // add Security association l_xsainfo = (struct xfrm_usersa_info*)mnl_nlmsg_put_extra_header(l_nlh, sizeof(struct xfrm_usersa_info)); - l_xsainfo->sel.family = AF_INET; - l_xsainfo->sel.daddr.a4 = inet_addr(dest_addr); - l_xsainfo->sel.saddr.a4 = inet_addr(src_addr); + l_xsainfo->sel.family = dest_addr_param->af; + if(dest_addr_param->af == AF_INET6) { + memcpy(l_xsainfo->sel.daddr.a6, dest_addr_param->u.addr32, sizeof(l_xsainfo->sel.daddr.a6)); + memcpy(l_xsainfo->sel.saddr.a6, src_addr_param->u.addr32, sizeof(l_xsainfo->sel.saddr.a6)); + l_xsainfo->sel.prefixlen_d = 128; + l_xsainfo->sel.prefixlen_s = 128; + } + else { + l_xsainfo->sel.daddr.a4 = dest_addr_param->u.addr32[0]; + l_xsainfo->sel.saddr.a4 = src_addr_param->u.addr32[0]; + l_xsainfo->sel.prefixlen_d = 32; + l_xsainfo->sel.prefixlen_s = 32; + } l_xsainfo->sel.dport = htons(d_port); l_xsainfo->sel.dport_mask = 0xFFFF; - l_xsainfo->sel.prefixlen_d = 32; l_xsainfo->sel.sport = htons(s_port); l_xsainfo->sel.sport_mask = 0xFFFF; - l_xsainfo->sel.prefixlen_s = 32; - l_xsainfo->sel.proto = sel_proto; + //l_xsainfo->sel.proto = sel_proto; l_xsainfo->sel.user = htonl(xfrm_user_selector); - l_xsainfo->saddr.a4 = inet_addr(src_addr); - l_xsainfo->id.daddr.a4 = inet_addr(dest_addr); + if(dest_addr_param->af == AF_INET6) { + memcpy(l_xsainfo->id.daddr.a6, dest_addr_param->u.addr32, sizeof(l_xsainfo->id.daddr.a6)); + memcpy(l_xsainfo->saddr.a6, src_addr_param->u.addr32, sizeof(l_xsainfo->saddr.a6)); + } + else { + l_xsainfo->id.daddr.a4 = dest_addr_param->u.addr32[0]; + l_xsainfo->saddr.a4 = src_addr_param->u.addr32[0]; + } l_xsainfo->id.spi = htonl(id); l_xsainfo->id.proto = IPPROTO_ESP; @@ -182,14 +176,10 @@ int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, l_xsainfo->lft.soft_packet_limit = XFRM_INF; l_xsainfo->lft.hard_packet_limit = XFRM_INF; l_xsainfo->reqid = id; - l_xsainfo->family = AF_INET; + l_xsainfo->family = dest_addr_param->af; l_xsainfo->mode = XFRM_MODE_TRANSPORT; l_xsainfo->replay_window = 32; - l_xsainfo->flags = XFRM_STATE_NOECN; - - // char* ip addresses are no longer needed - free them - pkg_free(src_addr); - pkg_free(dest_addr); + //l_xsainfo->flags = XFRM_STATE_NOECN; // Add authentication algorithm for this SA @@ -281,7 +271,7 @@ int remove_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_para } -int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir) +int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir) { char l_msg_buf[MNL_SOCKET_BUFFER_SIZE]; char l_tmpls_buf[XFRM_TMPLS_BUF_SIZE]; @@ -294,30 +284,9 @@ int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr return -1; } - char* src_addr = NULL; - char* dest_addr = NULL; - memset(l_msg_buf, 0, sizeof(l_msg_buf)); memset(l_tmpls_buf, 0, sizeof(l_tmpls_buf)); - // convert input IP addresses to char* - if((src_addr = pkg_malloc(src_addr_param.len+1)) == NULL) { - LM_ERR("Error allocating memory for src addr during Policy creation\n"); - return -1; - } - - if((dest_addr = pkg_malloc(dest_addr_param.len+1)) == NULL) { - pkg_free(src_addr); - LM_ERR("Error allocating memory for dest addr during Policy creation\n"); - return -2; - } - - memset(src_addr, 0, src_addr_param.len+1); - memset(dest_addr, 0, dest_addr_param.len+1); - - memcpy(src_addr, src_addr_param.s, src_addr_param.len); - memcpy(dest_addr, dest_addr_param.s, dest_addr_param.len); - // nlmsghdr initialization l_nlh = mnl_nlmsg_put_header(l_msg_buf); l_nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; @@ -327,16 +296,24 @@ int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr // add OUT policy l_xpinfo = (struct xfrm_userpolicy_info*)mnl_nlmsg_put_extra_header(l_nlh, sizeof(struct xfrm_userpolicy_info)); - l_xpinfo->sel.family = AF_INET; - l_xpinfo->sel.daddr.a4 = inet_addr(dest_addr); - l_xpinfo->sel.saddr.a4 = inet_addr(src_addr); + l_xpinfo->sel.family = dest_addr_param->af; + if(dest_addr_param->af == AF_INET6) { + memcpy(l_xpinfo->sel.daddr.a6, dest_addr_param->u.addr32, sizeof(l_xpinfo->sel.daddr.a6)); + memcpy(l_xpinfo->sel.saddr.a6, src_addr_param->u.addr32, sizeof(l_xpinfo->sel.saddr.a6)); + l_xpinfo->sel.prefixlen_d = 128; + l_xpinfo->sel.prefixlen_s = 128; + } + else { + l_xpinfo->sel.daddr.a4 = dest_addr_param->u.addr32[0]; + l_xpinfo->sel.saddr.a4 = src_addr_param->u.addr32[0]; + l_xpinfo->sel.prefixlen_d = 32; + l_xpinfo->sel.prefixlen_s = 32; + } l_xpinfo->sel.dport = htons(dst_port); l_xpinfo->sel.dport_mask = 0xFFFF; - l_xpinfo->sel.prefixlen_d = 32; l_xpinfo->sel.sport = htons(src_port); l_xpinfo->sel.sport_mask = 0xFFFF; - l_xpinfo->sel.prefixlen_s = 32; - l_xpinfo->sel.proto = sel_proto; + //l_xpinfo->sel.proto = sel_proto; l_xpinfo->sel.user = htonl(xfrm_user_selector); l_xpinfo->lft.soft_byte_limit = XFRM_INF; @@ -355,38 +332,36 @@ int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr } else { LM_ERR("Invalid direction parameter passed to add_policy: %d\n", dir); - pkg_free(src_addr); - pkg_free(dest_addr); return -3; } - // xfrm_user_tmpl initialization struct xfrm_user_tmpl* l_tmpl = (struct xfrm_user_tmpl*)l_tmpls_buf; l_tmpl->id.proto = IPPROTO_ESP; - l_tmpl->family = AF_INET; + l_tmpl->family = dest_addr_param->af; + if(dest_addr_param->af == AF_INET6) { + memcpy(l_tmpl->id.daddr.a6, dest_addr_param->u.addr32, sizeof(l_tmpl->id.daddr.a6)); + memcpy(l_tmpl->saddr.a6, src_addr_param->u.addr32, sizeof(l_tmpl->saddr.a6)); + } + else { + l_tmpl->id.daddr.a4 = dest_addr_param->u.addr32[0]; + l_tmpl->saddr.a4 = src_addr_param->u.addr32[0]; + } l_tmpl->reqid = p_id; l_tmpl->mode = XFRM_MODE_TRANSPORT; l_tmpl->aalgos = (~(__u32)0); l_tmpl->ealgos = (~(__u32)0); l_tmpl->calgos = (~(__u32)0); - mnl_attr_put(l_nlh, XFRMA_TMPL, sizeof(struct xfrm_user_tmpl), l_tmpl); if(mnl_socket_sendto(mnl_socket, l_nlh, l_nlh->nlmsg_len) < 0) { - pkg_free(src_addr); - pkg_free(dest_addr); LM_ERR("Failed to send Netlink message, error: %s\n", strerror(errno)); return -4; } - // char* ip addresses are no longer needed - free them - pkg_free(src_addr); - pkg_free(dest_addr); - return 0; } @@ -449,8 +424,8 @@ int remove_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_a .xpid.sel.prefixlen_d = 32, .xpid.sel.sport = htons(src_port), .xpid.sel.sport_mask = 0xFFFF, - .xpid.sel.prefixlen_s = 32, - .xpid.sel.proto = sel_proto + .xpid.sel.prefixlen_s = 32//, + //.xpid.sel.proto = sel_proto }; if(mnl_socket_sendto(mnl_socket, &req.n, req.n.nlmsg_len) < 0) diff --git a/src/modules/ims_ipsec_pcscf/ipsec.h b/src/modules/ims_ipsec_pcscf/ipsec.h index 71390f1d8b1..06e98c50df8 100644 --- a/src/modules/ims_ipsec_pcscf/ipsec.h +++ b/src/modules/ims_ipsec_pcscf/ipsec.h @@ -26,6 +26,7 @@ #define IMS_IPSEC_PCSCF_IPSEC #include "../../core/str.h" +#include "../../core/ip_addr.h" struct mnl_socket; @@ -41,10 +42,10 @@ void close_mnl_socket(struct mnl_socket* sock); unsigned short kamailio_to_linux_proto(const unsigned short kamailio_proto); -int add_sa(struct mnl_socket* nl_sock, unsigned short proto, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id, str ck, str ik); +int add_sa(struct mnl_socket* nl_sock, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int s_port, int d_port, int long id, str ck, str ik); int remove_sa(struct mnl_socket* nl_sock, str src_addr_param, str dest_addr_param, int s_port, int d_port, int long id); -int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir); +int add_policy(struct mnl_socket* mnl_socket, unsigned short proto, const struct ip_addr *src_addr_param, const struct ip_addr *dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir); int remove_policy(struct mnl_socket* mnl_socket, unsigned short proto, str src_addr_param, str dest_addr_param, int src_port, int dst_port, int long p_id, enum ipsec_policy_direction dir); int clean_sa(struct mnl_socket* mnl_socket);