asterisk/res/res_pjsip_volte.c

692 lines
22 KiB
C

/*** MODULEINFO
<depend>libmnl</depend>
<depend>pjproject</depend>
<depend>res_pjsip</depend>
<depend>res_pjsip_session</depend>
<depend>res_pjsip_outbound_authenticator_digest</depend>
<support_level>core</support_level>
***/
#include "asterisk.h"
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjlib.h>
#include <pjmedia.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_session.h"
#include "asterisk/utils.h"
#include "asterisk/module.h"
#include "asterisk/causes.h"
#include "asterisk/threadpool.h"
#include "res_pjsip_volte/netlink_xfrm.h"
#include "res_pjsip_volte/milenage.h"
#define PJ_CONSUME PJ_TRUE
#define fmt_str(str) (int)(str).slen, (str).ptr
const pj_str_t STR_SUPPORTED = { "Supported", 9 };
const pj_str_t STR_REQUIRE = { "Require", 7 };
const pj_str_t STR_PROXY_REQUIRE = { "Proxy-Require", 13 };
const pj_str_t STR_PATH = { "path", 4 };
const pj_str_t STR_SEC_AGREE = { "sec-agree", 9 };
const pj_str_t STR_AUTHORIZATION = { "Authorization", 13 };
const pj_str_t STR_SECURITY_CLIENT = { "Security-Client", 15 };
const pj_str_t STR_SECURITY_SERVER = { "Security-Server", 15 };
const pj_str_t STR_Q = { "q", 1 };
const pj_str_t STR_PROT = { "prot", 4 };
const pj_str_t STR_MOD = { "mod", 3 };
const pj_str_t STR_SPI_C = { "spi-c", 5 };
const pj_str_t STR_SPI_S = { "spi-s", 5 };
const pj_str_t STR_PORT_C = { "port-c", 6 };
const pj_str_t STR_PORT_S = { "port-s", 6 };
const pj_str_t STR_ALG = { "alg", 3 };
const pj_str_t STR_EALG = { "ealg", 4 };
struct ipsec_alg {
const char *sip_name;
const char *kernel_name;
};
const struct ipsec_alg ipsec_alg[] = {
{ "hmac-md5-96", "md5" },
{ "hmac-sha-1-96", "sha1" },
{ NULL, NULL }
};
const struct ipsec_alg ipsec_ealg[] = {
{ "null", "cipher_null" },
{ NULL, NULL }
};
static unsigned char aka_res[8];
static struct mnl_socket *g_mnl_socket = NULL;
struct sockaddr_storage g_local_addr_c, g_local_addr_s;
struct sockaddr_storage g_remote_addr_c, g_remote_addr_s;
static uint32_t g_local_spi_c, g_local_spi_s;
static uint32_t g_remote_spi_c, g_remote_spi_s;
static pj_bool_t g_local_sa_c_set = PJ_FALSE, g_local_sa_s_set = PJ_FALSE;
static pj_bool_t g_remote_sa_c_set = PJ_FALSE, g_remote_sa_s_set = PJ_FALSE;
static pj_bool_t g_local_sp_c_set = PJ_FALSE, g_local_sp_s_set = PJ_FALSE;
static pj_bool_t g_remote_sp_c_set = PJ_FALSE, g_remote_sp_s_set = PJ_FALSE;
static void copy_pj_sockaddr_to_sockaddr_storage(const pj_sockaddr *src, struct sockaddr_storage *dst)
{
memset(dst, 0, sizeof(struct sockaddr_storage));
dst->ss_family = (src->addr.sa_family == PJ_AF_INET) ? AF_INET : AF_INET6;
if (dst->ss_family == AF_INET) {
struct sockaddr_in *dst_in = (struct sockaddr_in *)dst;
const pj_sockaddr_in *src_in = (const pj_sockaddr_in *)src;
dst_in->sin_port = htons(src_in->sin_port);
memcpy(&dst_in->sin_addr, &src_in->sin_addr, sizeof(struct in_addr));
} else if (dst->ss_family == AF_INET6) {
struct sockaddr_in6 *dst_in6 = (struct sockaddr_in6 *)dst;
const pj_sockaddr_in6 *src_in6 = (const pj_sockaddr_in6 *)src;
dst_in6->sin6_port = htons(src_in6->sin6_port);
memcpy(&dst_in6->sin6_addr, &src_in6->sin6_addr, sizeof(struct in6_addr));
}
}
static char *sockaddr_storage_to_string(const struct sockaddr_storage *addr, char *ip_string, size_t ip_string_len)
{
if (addr->ss_family == AF_INET) {
const struct sockaddr_in *addr_in = (const struct sockaddr_in *)addr;
inet_ntop(AF_INET, &addr_in->sin_addr, ip_string, ip_string_len);
} else if (addr->ss_family == AF_INET6) {
const struct sockaddr_in6 *addr_in6 = (const struct sockaddr_in6 *)addr;
inet_ntop(AF_INET6, &addr_in6->sin6_addr, ip_string, ip_string_len);
} else {
snprintf(ip_string, ip_string_len, "<Unknown AF>");
}
return ip_string;
}
static void sockaddr_storage_port(struct sockaddr_storage *addr, uint16_t port)
{
switch (((struct sockaddr *)addr)->sa_family) {
case AF_INET:
((struct sockaddr_in *)addr)->sin_port = htons(port);
break;
case AF_INET6:
((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
break;
}
}
/* Delete old SA and SP entries upon new registration or module exit. */
static void cleanup_xfrm(void)
{
if (g_local_sa_c_set) {
xfrm_sa_del(g_mnl_socket, (const struct sockaddr *)&g_local_addr_c, (const struct sockaddr *)&g_remote_addr_c, g_local_spi_c);
g_local_sa_c_set = PJ_FALSE;
}
if (g_local_sa_s_set) {
xfrm_sa_del(g_mnl_socket, (const struct sockaddr *)&g_local_addr_s, (const struct sockaddr *)&g_remote_addr_s, g_local_spi_s);
g_local_sa_s_set = PJ_FALSE;
}
if (g_remote_sa_c_set) {
xfrm_sa_del(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_c, (const struct sockaddr *)&g_local_addr_c, g_remote_spi_c);
g_remote_sa_c_set = PJ_FALSE;
}
if (g_remote_sa_s_set) {
xfrm_sa_del(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_s, (const struct sockaddr *)&g_local_addr_s, g_remote_spi_s);
g_remote_sa_s_set = PJ_FALSE;
}
if (g_local_sp_c_set) {
xfrm_policy_del(g_mnl_socket, (const struct sockaddr *)&g_local_addr_c, (const struct sockaddr *)&g_remote_addr_c, false);
g_local_sp_c_set = PJ_FALSE;
}
if (g_local_sp_s_set) {
xfrm_policy_del(g_mnl_socket, (const struct sockaddr *)&g_local_addr_s, (const struct sockaddr *)&g_remote_addr_s, false);
g_local_sp_s_set = PJ_FALSE;
}
if (g_remote_sp_c_set) {
xfrm_policy_del(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_c, (const struct sockaddr *)&g_local_addr_c, true);
g_remote_sp_c_set = PJ_FALSE;
}
if (g_remote_sp_s_set) {
xfrm_policy_del(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_s, (const struct sockaddr *)&g_local_addr_s, true);
g_remote_sp_s_set = PJ_FALSE;
}
}
struct security_server {
pj_str_t q;
pj_str_t prot;
pj_str_t mod;
pj_str_t spi_c;
pj_str_t spi_s;
pj_str_t port_c;
pj_str_t port_s;
pj_str_t alg;
pj_str_t ealg;
};
static void on_syntax_error(pj_scanner *scanner)
{
PJ_UNUSED_ARG(scanner);
}
static void parse_security_server(pj_pool_t *pool, char *buf, pj_size_t size, struct security_server *sec)
{
pj_scanner scanner;
memset(sec, 0, sizeof(*sec));
pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);
for (;;) {
pj_str_t name, value;
pjsip_parse_param_imp(&scanner, pool, &name, &value, 0);
if (!pj_stricmp(&name, &STR_Q)) {
sec->q = value;
} else
if (!pj_stricmp(&name, &STR_PROT)) {
sec->prot = value;
} else
if (!pj_stricmp(&name, &STR_MOD)) {
sec->mod = value;
} else
if (!pj_stricmp(&name, &STR_SPI_C)) {
sec->spi_c = value;
} else
if (!pj_stricmp(&name, &STR_SPI_S)) {
sec->spi_s = value;
} else
if (!pj_stricmp(&name, &STR_PORT_C)) {
sec->port_c = value;
} else
if (!pj_stricmp(&name, &STR_PORT_S)) {
sec->port_s = value;
} else
if (!pj_stricmp(&name, &STR_ALG)) {
sec->alg = value;
} else
if (!pj_stricmp(&name, &STR_EALG)) {
sec->ealg = value;
}
if (pj_scan_is_eof(&scanner))
break;
/* Eat semicolon */
if (*scanner.curptr == ';')
pj_scan_get_char(&scanner);
}
pj_scan_fini(&scanner);
}
static pj_status_t on_load(pjsip_endpoint *endpt)
{
printf("endpoint!\n");
return PJ_SUCCESS;
}
/* Check if message is exchanged with IMS.
* This approach uses the host name of the URI. */
static pj_bool_t is_ims(const pjsip_msg *msg)
{
pjsip_fromto_hdr *hdr;
pjsip_sip_uri *uri;
size_t host_len;
/* Get URI. */
hdr = pjsip_msg_find_hdr(msg, PJSIP_H_TO, NULL);
if (!hdr)
return PJ_FALSE;
uri = pjsip_uri_get_uri(hdr->uri);
host_len = uri->host.slen;
if (host_len < 20) {
ast_log(LOG_DEBUG, "SIP message is not IMS message, ignoring.");
return PJ_FALSE;
}
if (!!strncmp(uri->host.ptr, "ims.", 4)) {
ast_log(LOG_DEBUG, "SIP message is not IMS message, ignoring.");
return PJ_FALSE;
}
if (!!strncmp(uri->host.ptr + host_len - 16, ".3gppnetwork.org", 16)) {
ast_log(LOG_DEBUG, "SIP message is not IMS message, ignoring.");
return PJ_FALSE;
}
return PJ_TRUE;
}
static void add_securety_client_hdr(pjsip_tx_data *tdata, const struct ipsec_alg alg[], const struct ipsec_alg ealg[], uint32_t spi_c, uint32_t spi_s, uint16_t port_c, uint16_t port_s)
{
pjsip_generic_array_hdr *hdr;
char str[256];
int i, j;
/* Add Security-Client header. */
hdr = pjsip_generic_array_hdr_create(tdata->pool, &STR_SECURITY_CLIENT);
if (!hdr) {
ast_log(LOG_ERROR, "Failed to create header.");
return;
}
/* Create tupple for given algorithms. */
for (i = 0; alg[i].sip_name; i++) {
for (j = 0; ealg[j].sip_name; j++) {
snprintf(str, sizeof(str), "ipsec-3gpp; alg=%s; ealg=%s; spi-c=%u; spi-s=%u; port-c=%u; port-s=%u", alg[i].sip_name, ealg[j].sip_name, spi_c, spi_s, port_c, port_s);
if (hdr->count == PJSIP_GENERIC_ARRAY_MAX_COUNT) {
ast_log(LOG_ERROR, "Too many evalue in array, skipping '%s'.", str);
continue;
}
pj_strdup2(tdata->pool, &hdr->values[hdr->count++], str);
}
}
/* Append header */
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
}
static void add_value_string_hdr(pjsip_tx_data *tdata, const pj_str_t *name, const pj_str_t *value)
{
pjsip_generic_string_hdr *hdr;
/* Add Proxy-Require header. */
hdr = pjsip_generic_string_hdr_create(tdata->pool, name, value);
if (!hdr) {
ast_log(LOG_ERROR, "Failed to create header.");
return;
}
/* Append header */
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
}
static void add_value_array_hdr(pjsip_tx_data *tdata, const pj_str_t *name, const pj_str_t *value)
{
pjsip_generic_array_hdr *hdr;
pj_bool_t created = PJ_FALSE;
/* Create header, if not yet created. */
hdr = pjsip_msg_find_hdr_by_name(tdata->msg, name, NULL);
if (!hdr) {
hdr = pjsip_generic_array_hdr_create(tdata->pool, name);
created = PJ_TRUE;
}
if (!hdr) {
ast_log(LOG_ERROR, "Failed to create header.");
return;
}
if (hdr->count == PJSIP_GENERIC_ARRAY_MAX_COUNT) {
ast_log(LOG_ERROR, "Too many evalue in array, skipping %s.", value->ptr);
return;
}
pj_strdup(tdata->pool, &hdr->values[hdr->count++], value);
/* Append header, if created. */
if (created)
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
}
static pj_status_t on_tx_register_request(pjsip_tx_data *tdata)
{
char src_str[64], dst_str[64];
pjsip_generic_array_hdr *hdr;
int rc;
volte_auth = NULL;
if (!is_ims(tdata->msg))
return PJ_SUCCESS;
pj_bool_t created = PJ_FALSE;
/* Create header, if not yet created. */
hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &STR_SECURITY_CLIENT, NULL);
if (!hdr) {
puts("first register\n");
cleanup_xfrm();
/* Get local and remote peer address. */
copy_pj_sockaddr_to_sockaddr_storage(&tdata->tp_info.transport->local_addr, &g_local_addr_c);
copy_pj_sockaddr_to_sockaddr_storage(&tdata->tp_info.transport->local_addr, &g_local_addr_s);
copy_pj_sockaddr_to_sockaddr_storage(&tdata->tp_info.dst_addr, &g_remote_addr_c);
copy_pj_sockaddr_to_sockaddr_storage(&tdata->tp_info.dst_addr, &g_remote_addr_s);
sockaddr_storage_port(&g_remote_addr_c, 0x0001);
sockaddr_storage_port(&g_remote_addr_s, 0x0001);
ast_log(LOG_DEBUG, "peers %s->%s\n", sockaddr_storage_to_string(&g_local_addr_c, src_str, sizeof(src_str)), sockaddr_storage_to_string(&g_remote_addr_c, dst_str, sizeof(dst_str)));
/* Allocate SPI-C and SPI-S towards remote peer. */
rc = xfrm_spi_alloc(g_mnl_socket, 2342, &g_local_spi_c, (const struct sockaddr *)&g_local_addr_c, (const struct sockaddr *)&g_remote_addr_c);
if (rc < 0) {
spi_alloc_failed:
ast_log(LOG_ERROR, "Failed to request SPI.\n");
return PJ_CONSUME;
}
g_local_sa_s_set = PJ_TRUE;
rc = xfrm_spi_alloc(g_mnl_socket, 2342, &g_local_spi_s, (const struct sockaddr *)&g_local_addr_s, (const struct sockaddr *)&g_remote_addr_s);
if (rc < 0)
goto spi_alloc_failed;
g_local_sa_c_set = PJ_TRUE;
ast_log(LOG_DEBUG, "local SPI-C=0x%08x SPI-S=0x%08x\n", g_local_spi_s, g_local_spi_c);
/* "Require: sec-agree" */
add_value_array_hdr(tdata, &STR_REQUIRE, &STR_SEC_AGREE);
/* "Proxy-Require: sec-agree" */
add_value_string_hdr(tdata, &STR_PROXY_REQUIRE, &STR_SEC_AGREE);
/* "Supported: path,sec-agree" */
add_value_array_hdr(tdata, &STR_SUPPORTED, &STR_PATH);
/* "Security-Client: ..." */
add_value_array_hdr(tdata, &STR_SUPPORTED, &STR_SEC_AGREE);
#warning fix port numbers
add_securety_client_hdr(tdata, ipsec_alg, ipsec_ealg, g_local_spi_c, g_local_spi_s, 43419, 42318);
#warning HACKING: Asterisk must do this on first register! Or we must do it!
char xxx[] = "Digest uri=\"sip:ims.mnc001.mcc238.3gppnetwork.org\",username=\"238010000090828@ims.mnc001.mcc238.3gppnetwork.org\",response=\"\",realm=\"ims.mnc001.mcc238.3gppnetwork.org\",nonce=\"\"";
const pj_str_t STR_XXX = { xxx, strlen(xxx)};
add_value_string_hdr(tdata, &STR_AUTHORIZATION, &STR_XXX);
} else {
puts("second register\n");
hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &STR_AUTHORIZATION, NULL);
if (hdr)
pj_list_erase(hdr);
}
return PJ_SUCCESS;
}
/* What PJSIP will requests */
static pj_status_t on_tx_request(pjsip_tx_data *tdata)
{
const pjsip_msg *msg = tdata->msg;
puts("tx request");
if (!msg) {
ast_log(LOG_ERROR, "No message in request.");
return PJ_CONSUME;
}
const pj_str_t REFER_TO = { "User-Agent", 10 };
pjsip_generic_string_hdr *refer_to_hdr;
switch (msg->line.req.method.id) {
case PJSIP_REGISTER_METHOD:
puts("register");
return on_tx_register_request(tdata);
case PJSIP_INVITE_METHOD:
break;
default:
break;
}
return PJ_SUCCESS;
}
static pj_bool_t on_rx_401_407_response(pjsip_rx_data *rdata, pjsip_hdr_e auth_type)
{
if (!is_ims(rdata->msg_info.msg))
return PJ_FALSE;
/* Get Security-Server from header. */
struct security_server sec;
pjsip_generic_string_hdr *sec_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_SECURITY_SERVER, NULL);
if (!sec_hdr || !sec_hdr->hvalue.ptr) {
ast_log(LOG_ERROR, "Missing 'Security-Server' in REGISTER response.");
return PJ_FALSE;
}
parse_security_server(rdata->tp_info.pool, sec_hdr->hvalue.ptr, sec_hdr->hvalue.slen, &sec);
if (!sec.prot.ptr || !sec.spi_c.ptr || !sec.spi_s.ptr || !sec.port_c.ptr || !sec.port_s.ptr || !sec.alg.ptr || !sec.ealg.ptr) {
ast_log(LOG_ERROR, "Missing 'Security-Server' elements in REGISTER response. header=\"%.*s\", prot=%.*s, spi-c=%.*s, spi-s=%.*s, port-c=%.*s, port-s=%.*s, alg=%.*s, ealg=%.*s", fmt_str(sec_hdr->hvalue), fmt_str(sec.prot), fmt_str(sec.spi_c), fmt_str(sec.spi_s), fmt_str(sec.port_c), fmt_str(sec.port_s), fmt_str(sec.alg), fmt_str(sec.ealg));
return PJ_FALSE;
}
pjsip_www_authenticate_hdr *auth_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, auth_type, NULL);
if (!auth_hdr || !auth_hdr->challenge.digest.nonce.ptr || !auth_hdr->challenge.digest.algorithm.ptr) {
ast_log(LOG_ERROR, "Authentication header missing or incomplete in REGISTER response.\n");
return PJ_FALSE;
}
if (!pj_strncmp2(&auth_hdr->challenge.digest.algorithm, "AKAv2-MD5", 9)) {
ast_log(LOG_ERROR, "Authentication algorithm not supported. See third-party/pjproject/source/pjsip/src/pjsip/sip_auth_aka.c for implementation.\n");
return PJ_FALSE;
}
if (!!pj_strncmp2(&auth_hdr->challenge.digest.algorithm, "AKAv1-MD5", 9)) {
ast_log(LOG_ERROR, "Authentication algorithm not supported.\n");
return PJ_FALSE;
}
#warning hacking
const uint8_t opc[16] = { 0x77, 0x5A, 0x1F, 0x88, 0x7D, 0x2A, 0xD6, 0x6F, 0x97, 0x19, 0xC2, 0xC7, 0x9F, 0x84, 0x7B, 0x50 };
const uint8_t ki[16] = { 0xD5, 0x34, 0xE0, 0x78, 0x54, 0xB7, 0x5E, 0x47, 0x5C, 0x66, 0x7A, 0x85, 0x6A, 0xA3, 0x1F, 0x9C };
const uint8_t amf[2] = { 0x80, 0x00 };
const uint8_t sqn[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t rand_auth[32], *rand = rand_auth, *auth = rand_auth + 16;
uint8_t out_autn[16], out_ik[16], out_ck[16];
size_t out_res_len = 8;
ast_base64decode(rand_auth, auth_hdr->challenge.digest.nonce.ptr, sizeof(rand_auth));
hexdump(LOG_DEBUG, "nonce", rand_auth, 32);
milenage_generate(opc, amf, ki, sqn, rand, out_autn, out_ik, out_ck, aka_res, &out_res_len);
if (out_res_len != 8) {
ast_log(LOG_ERROR, "Milenage computation failed.\n");
return PJ_FALSE;
}
hexdump(LOG_DEBUG, "IK", out_ik, 16);
hexdump(LOG_DEBUG, "CK", out_ck, 16);
volte_auth = aka_res;
struct xfrm_algobuf auth_algo, ciph_algo;
int i, j;
int rc;
for (i = 0; ipsec_alg[i].sip_name; i++) {
if (!pj_strncmp2(&sec.alg, ipsec_alg[i].sip_name, strlen(ipsec_alg[i].sip_name)))
break;
}
if (!ipsec_alg[i].kernel_name) {
ast_log(LOG_ERROR, "Given 'alg' in Security-Server header not found.\n");
return PJ_FALSE;
}
for (j = 0; ipsec_ealg[j].sip_name; j++) {
if (!pj_strncmp2(&sec.ealg, ipsec_ealg[j].sip_name, strlen(ipsec_ealg[j].sip_name)))
break;
}
g_remote_spi_c = atoi(sec.spi_c.ptr);
g_remote_spi_s = atoi(sec.spi_s.ptr);
ast_log(LOG_DEBUG, "remote SPI-C=0x%08x SPI-S=0x%08x\n", g_remote_spi_s, g_remote_spi_c);
sockaddr_storage_port(&g_remote_addr_c, atoi(sec.port_c.ptr));
sockaddr_storage_port(&g_remote_addr_s, atoi(sec.port_s.ptr));
strcpy(auth_algo.algo.alg_name, ipsec_alg[i].kernel_name);
switch (i) {
case 0:
memcpy(auth_algo.algo.alg_key, out_ik, 16);
auth_algo.algo.alg_key_len = 16;
break;
case 1:
memcpy(auth_algo.algo.alg_key, out_ik, 16);
memset(auth_algo.algo.alg_key + 16, 0x00, 4);
auth_algo.algo.alg_key_len = 20;
break;
}
strcpy(ciph_algo.algo.alg_name, ipsec_ealg[j].kernel_name);
switch (j) {
case 0:
ciph_algo.algo.alg_key_len = 0;
break;
}
cleanup_xfrm();
rc = xfrm_sa_add(g_mnl_socket, g_local_spi_c, (const struct sockaddr *)&g_local_addr_c, (const struct sockaddr *)&g_remote_addr_c, g_local_spi_c, &auth_algo.algo, &ciph_algo.algo);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SA.\n");
else
g_local_sa_c_set = PJ_TRUE;
rc = xfrm_sa_add(g_mnl_socket, g_local_spi_s, (const struct sockaddr *)&g_local_addr_s, (const struct sockaddr *)&g_remote_addr_s, g_local_spi_s, &auth_algo.algo, &ciph_algo.algo);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SA.\n");
else
g_local_sa_s_set = PJ_TRUE;
rc = xfrm_sa_add(g_mnl_socket, g_remote_spi_c, (const struct sockaddr *)&g_remote_addr_c, (const struct sockaddr *)&g_local_addr_c, g_remote_spi_c, &auth_algo.algo, &ciph_algo.algo);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SA.\n");
else
g_remote_sa_c_set = PJ_TRUE;
rc = xfrm_sa_add(g_mnl_socket, g_remote_spi_s, (const struct sockaddr *)&g_remote_addr_s, (const struct sockaddr *)&g_local_addr_s, g_remote_spi_s, &auth_algo.algo, &ciph_algo.algo);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SA.\n");
else
g_remote_sa_s_set = PJ_TRUE;
rc = xfrm_policy_add(g_mnl_socket, (const struct sockaddr *)&g_local_addr_c, (const struct sockaddr *)&g_remote_addr_c, g_local_spi_c, false);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SP.\n");
else
g_local_sp_c_set = PJ_TRUE;
rc = xfrm_policy_add(g_mnl_socket, (const struct sockaddr *)&g_local_addr_s, (const struct sockaddr *)&g_remote_addr_s, g_local_spi_s, false);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SP.\n");
else
g_local_sp_s_set = PJ_TRUE;
rc = xfrm_policy_add(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_c, (const struct sockaddr *)&g_local_addr_c, g_remote_spi_c, true);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SP.\n");
else
g_remote_sp_c_set = PJ_TRUE;
rc = xfrm_policy_add(g_mnl_socket, (const struct sockaddr *)&g_remote_addr_s, (const struct sockaddr *)&g_local_addr_s, g_remote_spi_s, true);
if (rc < 0)
ast_log(LOG_ERROR, "Failed to add IPSec SP.\n");
else
g_remote_sp_s_set = PJ_TRUE;
return PJ_FALSE;
}
/* What response PJSIP receives */
static pj_bool_t on_rx_response(pjsip_rx_data *rdata)
{
const pjsip_msg *msg = rdata->msg_info.msg;
puts("rx response");
if (!msg) {
ast_log(LOG_ERROR, "No message in request.");
return PJ_CONSUME;
}
switch ((int)msg->line.req.method.id) {
case 401:
return on_rx_401_407_response(rdata, PJSIP_H_WWW_AUTHENTICATE);
case 407:
return on_rx_401_407_response(rdata, PJSIP_H_PROXY_AUTHENTICATE);
default:
break;
}
return PJ_FALSE;
}
/* What request PJSIP receives */
static pj_bool_t on_rx_request(pjsip_rx_data *rdata)
{
puts("rx request");
return PJ_TRUE;
}
/* What PJSIP will response */
static pj_status_t on_tx_response(pjsip_tx_data *tdata)
{
puts("tx response");
return PJ_SUCCESS;
}
static pjsip_module volte_module = {
.name = {"VoLTE Support Module", 18},
.priority = PJSIP_MOD_PRIORITY_TRANSPORT_LAYER,
.load = on_load,
.on_tx_request = on_tx_request,
.on_rx_response = on_rx_response,
.on_tx_response = on_tx_response,
.on_rx_request = on_rx_request,
};
static int gai_helper(struct sockaddr_storage *out, const char *node, const char *port)
{
struct addrinfo hints = {
.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST,
};
struct addrinfo *res;
int rc;
rc = getaddrinfo(node, port, &hints, &res);
if (rc != 0) {
fprintf(stderr, "getaddrinfo(%s): %s\n", node, gai_strerror(rc));
return -1;
}
memcpy(out, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
return 0;
}
static int load_module(void)
{
if (ast_sip_register_service(&volte_module) != PJ_SUCCESS) {
ast_log(LOG_ERROR, "Failed to load VoLTE support module.\n");
return AST_MODULE_LOAD_DECLINE;
}
g_mnl_socket = xfrm_init_mnl_socket();
if (!g_mnl_socket) {
ast_log(LOG_ERROR, "Failed to init mnl socket to admin xfrm rules.\n");
ast_sip_unregister_service(&volte_module);
return AST_MODULE_LOAD_DECLINE;
}
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
ast_sip_unregister_service(&volte_module);
cleanup_xfrm();
xfrm_exit_mnl_socket(g_mnl_socket);
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "VoLTE support",
.support_level = AST_MODULE_SUPPORT_CORE,
.load = load_module,
.unload = unload_module,
.load_pri = AST_MODPRI_APP_DEPEND,
.requires = "res_pjsip,res_pjsip_session", );