From 861bd2093e39a0ae4fba7fd7add9704673db6937 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 20 May 2009 23:04:05 +0000 Subject: [PATCH] ZRTP Support please download your SDK from http://www.zfone.com and use build/buildzrtp.sh to build the lib. git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13406 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- Makefile.am | 4 + build/buildzrtp.sh | 8 ++ configure.in | 15 +++ patches/zrtp_bnlib_pic.diff | 5 + src/include/switch_types.h | 4 +- src/switch_core.c | 51 +++++++- src/switch_rtp.c | 239 +++++++++++++++++++++++++++++++++++- 7 files changed, 318 insertions(+), 8 deletions(-) create mode 100644 build/buildzrtp.sh create mode 100644 patches/zrtp_bnlib_pic.diff diff --git a/Makefile.am b/Makefile.am index 59846b5624..61e4120b0a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -198,6 +198,10 @@ libfreeswitch_la_SOURCES += src/switch_odbc.c libfreeswitch_la_LDFLAGS += $(ODBC_LIB_FLAGS) endif +if ENABLE_ZRTP +libfreeswitch_la_LDFLAGS += -lzrtp -lbn +endif + bin_SCRIPTS = scripts/gentls_cert scripts/fsxs src/include/switch_swigable_cpp.h: src/include/switch_cpp.h diff --git a/build/buildzrtp.sh b/build/buildzrtp.sh new file mode 100644 index 0000000000..9df8fff6f6 --- /dev/null +++ b/build/buildzrtp.sh @@ -0,0 +1,8 @@ +#!/bin/sh +tar zxf libzrtp-0.81.514.tar.gz +cd libzrtp-0.81.514 +patch -p1 < ../patches/zrtp_bnlib_pic.diff +cd projects/gnu/ +./configure CFLAGS="-fPIC" +make +make install diff --git a/configure.in b/configure.in index 834603f4e9..f6afd157d5 100644 --- a/configure.in +++ b/configure.in @@ -264,6 +264,21 @@ if test "${enable_debug}" = "yes"; then fi +AC_ARG_ENABLE(zrtp, + [AS_HELP_STRING([--enable-zrtp], [Compile with zrtp Support])],,[enable_zrtp="no"]) +if test "x$enable_zrtp" = "xyes" ; then + saved_LIBS=$LIBS + LIBS="$saved_LIBS -L/usr/local/lib -lbn -lpthread" + AC_CHECK_LIB(zrtp, zrtp_init, [has_zrtp="yes"], [has_zrtp="no"]) + LIBS=$saved_LIBS + if test "x$has_zrtp" = "xno"; then + AC_ERROR([Cannot locate zrtp libraries]) + fi + APR_ADDTO(SWITCH_AM_CFLAGS, -DENABLE_ZRTP) +fi +AM_CONDITIONAL([ENABLE_ZRTP],[test "x$enable_zrtp" != "xno"]) + + AM_CONDITIONAL([WANT_DEBUG],[test "${enable_debug}" = "yes"]) AC_ARG_ENABLE(core-odbc-support, diff --git a/patches/zrtp_bnlib_pic.diff b/patches/zrtp_bnlib_pic.diff new file mode 100644 index 0000000000..d9b98f408b --- /dev/null +++ b/patches/zrtp_bnlib_pic.diff @@ -0,0 +1,5 @@ +--- libzrtp-0.81.514.orig/third_party/bnlib/cfg.debug 2009-03-22 08:26:34.000000000 -0500 ++++ libzrtp-0.81.514.patched/third_party/bnlib/cfg.debug 2009-05-20 11:42:52.000000000 -0500 +@@ -1 +1 @@ +-./configure CFLAGS="-O0 -g3" ++./configure CFLAGS="-O0 -g3 -fPIC" diff --git a/src/include/switch_types.h b/src/include/switch_types.h index ae9b2a49b3..f4d92e83df 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -496,7 +496,9 @@ typedef enum { SWITCH_RTP_FLAG_SHUTDOWN = (1 << 19), SWITCH_RTP_FLAG_FLUSH = (1 << 20), SWITCH_RTP_FLAG_AUTOFLUSH = (1 << 21), - SWITCH_RTP_FLAG_STICKY_FLUSH = (1 << 22) + SWITCH_RTP_FLAG_STICKY_FLUSH = (1 << 22), + SWITCH_ZRTP_FLAG_SECURE_SEND = (1 << 23), + SWITCH_ZRTP_FLAG_SECURE_RECV = (1 << 24) } switch_rtp_flag_enum_t; typedef uint32_t switch_rtp_flag_t; diff --git a/src/switch_core.c b/src/switch_core.c index 54805839b2..79daffe07e 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -36,6 +36,7 @@ #include +#include #include #include "private/switch_core_pvt.h" #ifndef WIN32 @@ -1026,6 +1027,48 @@ SWITCH_DECLARE(uint32_t) switch_core_default_dtmf_duration(uint32_t duration) return runtime.default_dtmf_duration; } +static void switch_core_set_serial(void) +{ + char buf[13] = ""; + char path[256]; + + int fd = -1, write_fd = -1; + ssize_t bytes = 0; + + switch_snprintf(path, sizeof(path), "%s%sfreeswitch.serial", SWITCH_GLOBAL_dirs.conf_dir, SWITCH_PATH_SEPARATOR); + + + if ((fd = open(path, O_RDONLY, 0)) < 0) { + char *ip = switch_core_get_variable("local_ip_v4"); + uint32_t ipi = 0; + switch_byte_t *byte; + int i = 0; + + switch_inet_pton(AF_INET, ip, &ipi); + byte = (switch_byte_t *) &ipi; + + for(i = 0; i < 8; i += 2) { + switch_snprintf(buf + i, sizeof(buf) - i, "%0.2x", *byte); + byte++; + } + + switch_stun_random_string(buf + 8, 4, "0123456789abcdef"); + + if ((write_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) >= 0) { + bytes = write(write_fd, buf, sizeof(buf)); + close(write_fd); + write_fd = -1; + } + } else { + bytes = read(fd, buf, sizeof(buf)); + close(fd); + fd = -1; + } + + switch_core_set_variable("switch_serial", buf); +} + + SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switch_bool_t console, const char **err) { switch_uuid_t uuid; @@ -1084,12 +1127,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc runtime.flags = flags; runtime.sps_total = 30; + + switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET); switch_core_set_variable("local_ip_v4", guess_ip); switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET6); switch_core_set_variable("local_ip_v6", guess_ip); switch_core_set_variable("base_dir", SWITCH_GLOBAL_dirs.base_dir); - + switch_core_set_serial(); switch_event_init(runtime.memory_pool); @@ -1253,6 +1298,10 @@ static void switch_load_core_config(const char *file) switch_rtp_set_start_port((switch_port_t) atoi(val)); } else if (!strcasecmp(var, "rtp-end-port") && !switch_strlen_zero(val)) { switch_rtp_set_end_port((switch_port_t) atoi(val)); +#ifdef ENABLE_ZRTP + } else if (!strcasecmp(var, "rtp-enable-zrtp")) { + switch_core_set_variable("zrtp_enabled", val); +#endif } } } diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 41939c7d8b..500b52618d 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -59,6 +59,8 @@ #define RTP_MAGIC_NUMBER 42 #define MAX_SRTP_ERRS 10 + + static switch_port_t START_PORT = RTP_START_PORT; static switch_port_t END_PORT = RTP_END_PORT; static switch_port_t NEXT_PORT = RTP_START_PORT; @@ -66,6 +68,14 @@ static switch_mutex_t *port_lock = NULL; typedef srtp_hdr_t rtp_hdr_t; +#ifdef ENABLE_ZRTP +#include +static zrtp_global_t *zrtp_global; +static zrtp_zid_t zid = { "FreeSWITCH01" }; +static int zrtp_on = 0; + +#endif + #ifdef _MSC_VER #pragma pack(4) #endif @@ -205,6 +215,12 @@ struct switch_rtp { switch_rtp_bug_flag_t rtp_bugs; switch_rtp_stats_t stats; +#ifdef ENABLE_ZRTP + zrtp_session_t *zrtp_session; + zrtp_profile_t *zrtp_profile; + zrtp_stream_t *zrtp_ctx; +#endif + #ifdef RTP_DEBUG_WRITE_DELTA switch_time_t send_time; #endif @@ -397,13 +413,114 @@ static void handle_ice(switch_rtp_t *rtp_session, void *data, switch_size_t len) WRITE_DEC(rtp_session); } +#ifdef ENABLE_ZRTP +static void zrtp_security_event_callback(zrtp_stream_t *stream, unsigned event) +{ + switch_rtp_t *rtp_session = zrtp_stream_get_userdata(stream); + zrtp_session_info_t zrtp_session_info; + + switch (event) { + case ZRTP_EVENT_IS_SECURE: + zrtp_session_get(rtp_session->zrtp_session, &zrtp_session_info); + zrtp_log_print_sessioninfo(&zrtp_session_info); + + break; + default: + break; + } +} + +static int zrtp_send_rtp_callback(const zrtp_stream_t* stream, char* rtp_packet, unsigned int rtp_packet_length) +{ + switch_rtp_t *rtp_session = zrtp_stream_get_userdata(stream); + switch_size_t len = rtp_packet_length; + zrtp_status_t status = zrtp_status_ok; + + switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, rtp_packet, &len); + return status; +} + +static void zrtp_protocol_event_callback(zrtp_stream_t *stream, unsigned event) +{ + switch_rtp_t *rtp_session = zrtp_stream_get_userdata(stream); + + switch (event) { + case ZRTP_EVENT_IS_SECURE_DONE: + break; + case ZRTP_EVENT_IS_SECURE: + switch_set_flag(rtp_session, SWITCH_ZRTP_FLAG_SECURE_SEND); + switch_set_flag(rtp_session, SWITCH_ZRTP_FLAG_SECURE_RECV); + break; + case ZRTP_EVENT_IS_CLIENT_ENROLLMENT: + case ZRTP_EVENT_IS_CLEAR: + case ZRTP_EVENT_IS_INITIATINGSECURE: + case ZRTP_EVENT_IS_PENDINGSECURE: + case ZRTP_EVENT_IS_PENDINGCLEAR: + case ZRTP_EVENT_NO_ZRTP: + case ZRTP_EVENT_LOCAL_SAS_UPDATED: + break; + default: + break; + } +} + +static void zrtp_logger(int level, const char *data, int len) +{ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s", data); +} + +static void zrtp_handler(switch_rtp_t *rtp_session, switch_socket_t *sock, void *data, switch_size_t datalen, switch_sockaddr_t *from_addr) +{ + zrtp_status_t status = zrtp_status_fail; + unsigned int len = datalen; + + status = zrtp_process_srtp(rtp_session->zrtp_ctx, (char*)data, &len); + switch(status) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + break; + case zrtp_status_fail: + break; + default: + break; + } +} +#endif SWITCH_DECLARE(void) switch_rtp_init(switch_memory_pool_t *pool) { +#ifdef ENABLE_ZRTP + const char *zid_string = switch_core_get_variable("switch_serial"); + const char *zrtp_enabled = switch_core_get_variable("zrtp_enabled"); + zrtp_on = zrtp_enabled ? switch_true(zrtp_enabled) : 0; + zrtp_config_t zrtp_config; + char zrtp_cache_path[256] = ""; +#endif if (global_init) { return; } switch_core_hash_init(&alloc_hash, pool); +#ifdef ENABLE_ZRTP + if (zrtp_on) { + zrtp_config_defaults(&zrtp_config); + strcpy(zrtp_config.client_id, "FreeSWITCH"); + zrtp_config.lic_mode = ZRTP_LICENSE_MODE_ACTIVE; + switch_snprintf(zrtp_cache_path, sizeof(zrtp_cache_path), "%s%szrtp.dat", SWITCH_GLOBAL_dirs.db_dir, SWITCH_PATH_SEPARATOR); + zrtp_zstrcpyc( ZSTR_GV(zrtp_config.def_cache_path), zrtp_cache_path); + zrtp_config.cb.event_cb.on_zrtp_protocol_event = zrtp_protocol_event_callback; + zrtp_config.cb.misc_cb.on_send_packet = zrtp_send_rtp_callback; + zrtp_config.cb.event_cb.on_zrtp_security_event = zrtp_security_event_callback; + + zrtp_log_set_log_engine(zrtp_logger); + zrtp_log_set_level(4); + if (zrtp_status_ok != zrtp_init(&zrtp_config, &zrtp_global)) { + abort(); + } + + memcpy(zid, zid_string, 12); + } +#endif srtp_init(); switch_mutex_init(&port_lock, SWITCH_MUTEX_NESTED, pool); global_init = 1; @@ -435,6 +552,9 @@ SWITCH_DECLARE(void) switch_rtp_shutdown(void) switch_core_hash_destroy(&alloc_hash); switch_mutex_unlock(port_lock); +#ifdef ENABLE_ZRTP + zrtp_down(zrtp_global); +#endif crypto_kernel_shutdown(); } @@ -918,6 +1038,29 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session rtp_session->ready = 1; *new_rtp_session = rtp_session; +#ifdef ENABLE_ZRTP + if (zrtp_on) { + rtp_session->zrtp_profile = switch_core_alloc(rtp_session->pool, sizeof(*rtp_session->zrtp_profile)); + zrtp_profile_defaults(rtp_session->zrtp_profile, zrtp_global); + + if (zrtp_status_ok != zrtp_session_init(zrtp_global, rtp_session->zrtp_profile, zid, 1, &rtp_session->zrtp_session)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! zRTP INIT Failed\n"); + zrtp_session_down(rtp_session->zrtp_session); + rtp_session->zrtp_session = NULL; + } + + zrtp_session_set_userdata(rtp_session->zrtp_session, rtp_session); + + if (zrtp_status_ok != zrtp_stream_attach(rtp_session->zrtp_session, &rtp_session->zrtp_ctx)) { + abort(); + } + zrtp_stream_set_userdata(rtp_session->zrtp_ctx, rtp_session); + + zrtp_stream_start(rtp_session->zrtp_ctx, rtp_session->ssrc); + + switch_rtp_set_invald_handler(rtp_session, zrtp_handler); + } +#endif return SWITCH_STATUS_SUCCESS; } @@ -1169,7 +1312,23 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session) (*rtp_session)->recv_ctx = NULL; switch_clear_flag((*rtp_session), SWITCH_RTP_FLAG_SECURE_RECV); } +#ifdef ENABLE_ZRTP + /* ZRTP */ + if (zrtp_on) { + if (switch_test_flag((*rtp_session), SWITCH_ZRTP_FLAG_SECURE_SEND)) { + switch_clear_flag((*rtp_session), SWITCH_ZRTP_FLAG_SECURE_SEND); + } + if (switch_test_flag((*rtp_session), SWITCH_ZRTP_FLAG_SECURE_RECV)) { + switch_clear_flag((*rtp_session), SWITCH_ZRTP_FLAG_SECURE_RECV); + } + + if ((*rtp_session)->zrtp_session) { + zrtp_session_down((*rtp_session)->zrtp_session); + (*rtp_session)->zrtp_session = NULL; + } + } +#endif if ((*rtp_session)->timer.timer_interface) { switch_core_timer_destroy(&(*rtp_session)->timer); } @@ -1316,11 +1475,11 @@ static void do_2833(switch_rtp_t *rtp_session) } } - wrote =switch_rtp_write_manual(rtp_session, - rtp_session->dtmf_data.out_digit_packet, - 4, - rtp_session->rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833 ? 0 : 1, - rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); + wrote = switch_rtp_write_manual(rtp_session, + rtp_session->dtmf_data.out_digit_packet, + 4, + rtp_session->rtp_bugs & RTP_BUG_CISCO_SKIP_MARK_BIT_2833 ? 0 : 1, + rtp_session->te, rtp_session->dtmf_data.timestamp_dtmf, &flags); rtp_session->stats.outbound.raw_bytes += wrote; rtp_session->stats.outbound.dtmf_packet_count++; @@ -1592,7 +1751,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if (!bytes && (io_flags & SWITCH_IO_FLAG_NOBLOCK)) { return_cng_frame(); - } + } if (check && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_AUTO_CNG) && @@ -1670,6 +1829,30 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ bytes = sbytes; } +#ifdef ENABLE_ZRTP + /* ZRTP Recv */ + + if (bytes && switch_test_flag(rtp_session, SWITCH_ZRTP_FLAG_SECURE_RECV)) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = 0; + + stat = zrtp_process_srtp(rtp_session->zrtp_ctx, (void *)&rtp_session->recv_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + ret = -1; + goto end; + default: + break; + } + bytes = sbytes; + } +#endif #ifdef DEBUG_2833 if (rtp_session->dtmf_data.in_digit_sanity && !(rtp_session->dtmf_data.in_digit_sanity % 100)) { @@ -2235,7 +2418,29 @@ static int rtp_common_write(switch_rtp_t *rtp_session, bytes = sbytes; } +#ifdef ENABLE_ZRTP + /* ZRTP Send */ + if (switch_test_flag(rtp_session, SWITCH_ZRTP_FLAG_SECURE_SEND)) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = zrtp_status_fail; + + stat = zrtp_process_rtp(rtp_session->zrtp_ctx, (void*)send_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + default: + break; + } + + bytes = sbytes; + } +#endif #ifdef RTP_DEBUG_WRITE_DELTA { @@ -2477,7 +2682,29 @@ SWITCH_DECLARE(int) switch_rtp_write_manual(switch_rtp_t *rtp_session, } bytes = sbytes; } +#ifdef ENABLE_ZRTP + /* ZRTP Send */ + if (switch_test_flag(rtp_session, SWITCH_ZRTP_FLAG_SECURE_SEND)) { + unsigned int sbytes = (int) bytes; + zrtp_status_t stat = zrtp_status_fail; + + stat = zrtp_process_rtp(rtp_session->zrtp_ctx, (void*)&rtp_session->write_msg, &sbytes); + + switch (stat) { + case zrtp_status_ok: + break; + case zrtp_status_drop: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat); + case zrtp_status_fail: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat); + default: + break; + } + + bytes = sbytes; + } +#endif if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, (void *) &rtp_session->write_msg, &bytes) != SWITCH_STATUS_SUCCESS) { rtp_session->seq--; ret = -1;