summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-02-26 02:33:14 +0000
committerBenny Prijono <bennylp@teluu.com>2007-02-26 02:33:14 +0000
commitbf839cd77520ad28437e55a73fd8167838023f42 (patch)
tree140617414ee6d99323f69d2d478d767ddf4b7ecd
parenta34fbb64e27b5075a4207318ba356349669b4f08 (diff)
Added CRC32 code to pjlib-util, and implemented STUN FINGERPRINT and MESSAGE-INTEGRITY
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1002 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjlib-util/build/Makefile2
-rw-r--r--pjlib-util/build/pjlib_util.dsp10
-rw-r--r--pjlib-util/build/pjlib_util.vcproj8
-rw-r--r--pjlib-util/build/wince-evc4/pjlib_util_wince.vcp244
-rw-r--r--pjlib-util/include/pjlib-util.h1
-rw-r--r--pjlib-util/include/pjlib-util/crc32.h95
-rw-r--r--pjlib-util/include/pjlib-util/errno.h32
-rw-r--r--pjlib-util/include/pjlib-util/stun_msg.h277
-rw-r--r--pjlib-util/src/pjlib-util-test/encryption.c56
-rw-r--r--pjlib-util/src/pjlib-util/crc32.c192
-rw-r--r--pjlib-util/src/pjlib-util/stun_msg.c552
-rw-r--r--pjlib-util/src/pjstun-client/stun_session.c9
-rw-r--r--pjlib-util/src/pjstun-srv/server_main.c41
13 files changed, 1382 insertions, 137 deletions
diff --git a/pjlib-util/build/Makefile b/pjlib-util/build/Makefile
index c7ff0dfa..75089c12 100644
--- a/pjlib-util/build/Makefile
+++ b/pjlib-util/build/Makefile
@@ -26,7 +26,7 @@ export _LDFLAGS := $(subst /,$(HOST_PSEP),$(PJLIB_UTIL_LIB)) \
#
export PJLIB_UTIL_SRCDIR = ../src/pjlib-util
export PJLIB_UTIL_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
- errno.o dns.o dns_dump.o getopt.o \
+ crc32.o errno.o dns.o dns_dump.o getopt.o \
hmac_md5.o hmac_sha1.o md5.o resolver.o \
scanner.o sha1.o string.o stun_simple.o \
stun_simple_client.o xml.o
diff --git a/pjlib-util/build/pjlib_util.dsp b/pjlib-util/build/pjlib_util.dsp
index 3f5d9f6c..555a6c15 100644
--- a/pjlib-util/build/pjlib_util.dsp
+++ b/pjlib-util/build/pjlib_util.dsp
@@ -87,15 +87,15 @@ LIB32=link.exe -lib
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
-SOURCE="..\src\pjlib-util\dns.c"
+SOURCE="..\src\pjlib-util\crc32.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util\dns_dump.c"
+SOURCE="..\src\pjlib-util\dns.c"
# End Source File
# Begin Source File
-SOURCE="..\src\pjlib-util-test\encryption.c"
+SOURCE="..\src\pjlib-util\dns_dump.c"
# End Source File
# Begin Source File
@@ -189,6 +189,10 @@ SOURCE="..\include\pjlib-util\config.h"
# End Source File
# Begin Source File
+SOURCE="..\include\pjlib-util\crc32.h"
+# End Source File
+# Begin Source File
+
SOURCE="..\include\pjlib-util\dns.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/build/pjlib_util.vcproj b/pjlib-util/build/pjlib_util.vcproj
index 204bcdce..d07f073d 100644
--- a/pjlib-util/build/pjlib_util.vcproj
+++ b/pjlib-util/build/pjlib_util.vcproj
@@ -175,6 +175,10 @@
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
+ RelativePath="..\src\pjlib-util\crc32.c"
+ >
+ </File>
+ <File
RelativePath="..\src\pjlib-util\dns.c"
>
<FileConfiguration
@@ -492,6 +496,10 @@
>
</File>
<File
+ RelativePath="..\include\pjlib-util\crc32.h"
+ >
+ </File>
+ <File
RelativePath="..\include\pjlib-util\dns.h"
>
</File>
diff --git a/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp b/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
index 6ba8eacf..d0a44f04 100644
--- a/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
+++ b/pjlib-util/build/wince-evc4/pjlib_util_wince.vcp
@@ -318,6 +318,243 @@ BSC32=bscmake.exe
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
+SOURCE="..\..\src\pjlib-util\crc32.c"
+
+!IF "$(CFG)" == "pjlib_util_wince - Win32 (WCE emulator) Release"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE emulator) Debug"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4I) Release"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4I) Debug"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Release"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4) Debug"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4T) Release"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE ARMV4T) Debug"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE x86) Release"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ELSEIF "$(CFG)" == "pjlib_util_wince - Win32 (WCE x86) Debug"
+
+DEP_CPP_CRC32=\
+ "..\..\..\pjlib\include\pj\compat\cc_gcc.h"\
+ "..\..\..\pjlib\include\pj\compat\cc_msvc.h"\
+ "..\..\..\pjlib\include\pj\compat\m_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_auto.h"\
+ "..\..\..\pjlib\include\pj\compat\os_darwinos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux.h"\
+ "..\..\..\pjlib\include\pj\compat\os_linux_kernel.h"\
+ "..\..\..\pjlib\include\pj\compat\os_palmos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_rtems.h"\
+ "..\..\..\pjlib\include\pj\compat\os_sunos.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32.h"\
+ "..\..\..\pjlib\include\pj\compat\os_win32_wince.h"\
+ "..\..\..\pjlib\include\pj\compat\size_t.h"\
+ "..\..\..\pjlib\include\pj\config.h"\
+ "..\..\..\pjlib\include\pj\config_site.h"\
+ "..\..\..\pjlib\include\pj\config_site_sample.h"\
+ "..\..\..\pjlib\include\pj\types.h"\
+ "..\..\include\pjlib-util\crc32.h"\
+
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
SOURCE="..\..\src\pjlib-util\dns.c"
!IF "$(CFG)" == "pjlib_util_wince - Win32 (WCE emulator) Release"
@@ -6626,7 +6863,10 @@ DEP_CPP_STUN_M=\
"..\..\..\pjlib\include\pj\unicode.h"\
"..\..\..\pjlib\include\pjlib.h"\
"..\..\include\pjlib-util\config.h"\
+ "..\..\include\pjlib-util\crc32.h"\
"..\..\include\pjlib-util\errno.h"\
+ "..\..\include\pjlib-util\hmac_sha1.h"\
+ "..\..\include\pjlib-util\md5.h"\
"..\..\include\pjlib-util\stun_msg.h"\
"..\..\include\pjlib-util\types.h"\
@@ -10777,6 +11017,10 @@ SOURCE="..\..\include\pjlib-util\config.h"
# End Source File
# Begin Source File
+SOURCE="..\..\include\pjlib-util\crc32.h"
+# End Source File
+# Begin Source File
+
SOURCE="..\..\include\pjlib-util\dns.h"
# End Source File
# Begin Source File
diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h
index 0cf5a90d..2b3326b4 100644
--- a/pjlib-util/include/pjlib-util.h
+++ b/pjlib-util/include/pjlib-util.h
@@ -32,6 +32,7 @@
#include <pjlib-util/getopt.h>
/* Crypto */
+#include <pjlib-util/crc32.h>
#include <pjlib-util/hmac_md5.h>
#include <pjlib-util/hmac_sha1.h>
#include <pjlib-util/md5.h>
diff --git a/pjlib-util/include/pjlib-util/crc32.h b/pjlib-util/include/pjlib-util/crc32.h
new file mode 100644
index 00000000..a85a51a6
--- /dev/null
+++ b/pjlib-util/include/pjlib-util/crc32.h
@@ -0,0 +1,95 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __PJLIB_UTIL_CRC32_H__
+#define __PJLIB_UTIL_CRC32_H__
+
+/**
+ * @file crc32.h
+ * @brief CRC32 implementation
+ */
+
+#include <pj/types.h>
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup PJLIB_UTIL_CRC32 CRC32 (Cyclic Redundancy Check)
+ * @ingroup PJLIB_UTIL_ENCRYPTION
+ * @{
+ * This implements CRC32 algorithm. See ITU-T V.42 for the formal
+ * specification.
+ */
+
+/** CRC32 context. */
+typedef struct pj_crc32_context
+{
+ pj_uint32_t crc_state; /**< Current state. */
+} pj_crc32_context;
+
+
+/**
+ * Initialize CRC32 context.
+ *
+ * @param ctx CRC32 context.
+ */
+PJ_DECL(void) pj_crc32_init(pj_crc32_context *ctx);
+
+/**
+ * Feed data incrementally to the CRC32 algorithm.
+ *
+ * @param ctx CRC32 context.
+ * @param data Input data.
+ * @param nbytes Length of the input data.
+ *
+ * @return The current CRC32 value.
+ */
+PJ_DECL(pj_uint32_t) pj_crc32_update(pj_crc32_context *ctx,
+ const pj_uint8_t *data,
+ pj_size_t nbytes);
+
+/**
+ * Finalize CRC32 calculation and retrieve the CRC32 value.
+ *
+ * @param ctx CRC32 context.
+ *
+ * @return The current CRC value.
+ */
+PJ_DECL(pj_uint32_t) pj_crc32_final(pj_crc32_context *ctx);
+
+/**
+ * Perform one-off CRC32 calculation to the specified data.
+ *
+ * @param data Input data.
+ * @param nbytes Length of input data.
+ *
+ * @return CRC value of the data.
+ */
+PJ_DECL(pj_uint32_t) pj_crc32_calc(const pj_uint8_t *data,
+ pj_size_t nbytes);
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif /* __PJLIB_UTIL_CRC32_H__ */
+
diff --git a/pjlib-util/include/pjlib-util/errno.h b/pjlib-util/include/pjlib-util/errno.h
index 6d8c0b1f..3f004ca3 100644
--- a/pjlib-util/include/pjlib-util/errno.h
+++ b/pjlib-util/include/pjlib-util/errno.h
@@ -93,6 +93,16 @@
* Symetric NAT detected by STUN
*/
#define PJLIB_UTIL_ESTUNSYMMETRIC (PJLIB_UTIL_ERRNO_START+11) /* 320011 */
+/**
+ * @hideinitializer
+ * Invalid STUN magic value
+ */
+#define PJLIB_UTIL_ESTUNNOTMAGIC (PJLIB_UTIL_ERRNO_START+12) /* 320012 */
+/**
+ * @hideinitializer
+ * Invalid STUN fingerprint value
+ */
+#define PJLIB_UTIL_ESTUNFINGERPRINT (PJLIB_UTIL_ERRNO_START+13) /* 320013 */
@@ -266,12 +276,12 @@
#define PJLIB_UTIL_ESTUNUNKNOWNATTR (PJLIB_UTIL_ERRNO_START+112)/* 320112 */
/**
* @hideinitializer
- * Invalid socket address length.
+ * Invalid STUN socket address length.
*/
#define PJLIB_UTIL_ESTUNINADDRLEN (PJLIB_UTIL_ERRNO_START+113)/* 320113 */
/**
* @hideinitializer
- * IPv6 attribute not supported
+ * STUN IPv6 attribute not supported
*/
#define PJLIB_UTIL_ESTUNIPV6NOTSUPP (PJLIB_UTIL_ERRNO_START+113)/* 320113 */
/**
@@ -281,7 +291,7 @@
#define PJLIB_UTIL_ESTUNNOTRESPONSE (PJLIB_UTIL_ERRNO_START+114)/* 320114 */
/**
* @hideinitializer
- * Transaction ID mismatch.
+ * STUN transaction ID mismatch.
*/
#define PJLIB_UTIL_ESTUNINVALIDID (PJLIB_UTIL_ERRNO_START+115)/* 320115 */
/**
@@ -289,9 +299,23 @@
* Unable to find handler for the request.
*/
#define PJLIB_UTIL_ESTUNNOHANDLER (PJLIB_UTIL_ERRNO_START+116)/* 320116 */
+/**
+ * @hideinitializer
+ * Invalid STUN MESSAGE-INTEGRITY attribute position in message.
+ * STUN MESSAGE-INTEGRITY must be put last in the message, or before
+ * FINGERPRINT attribute.
+ */
+#define PJLIB_UTIL_ESTUNMSGINT (PJLIB_UTIL_ERRNO_START+117)/* 320117 */
+/**
+ * @hideinitializer
+ * Missing STUN USERNAME attribute.
+ * When credential is included in the STUN message (MESSAGE-INTEGRITY is
+ * present), the USERNAME attribute must be present in the message.
+ */
+#define PJLIB_UTIL_ESTUNNOUSERNAME (PJLIB_UTIL_ERRNO_START+118)/* 320118 */
-#define PJ_STATUS_FROM_STUN_CODE(code) -1
+#define PJ_STATUS_FROM_STUN_CODE(code) (PJLIB_UTIL_ERRNO_START+code)
diff --git a/pjlib-util/include/pjlib-util/stun_msg.h b/pjlib-util/include/pjlib-util/stun_msg.h
index b15b11f9..652472b5 100644
--- a/pjlib-util/include/pjlib-util/stun_msg.h
+++ b/pjlib-util/include/pjlib-util/stun_msg.h
@@ -601,7 +601,7 @@ typedef struct pj_stun_binary_attr
/**
* The raw data.
*/
- char *data;
+ pj_uint8_t *data;
} pj_stun_binary_attr;
@@ -1046,6 +1046,23 @@ typedef struct pj_stun_msg
} pj_stun_msg;
+/** STUN decoding options */
+enum pj_stun_options
+{
+ /**
+ * Tell the decoder that the message was received from datagram
+ * oriented transport (such as UDP).
+ */
+ PJ_STUN_IS_DATAGRAM = 1,
+
+ /**
+ * Tell pj_stun_msg_decode() to check the validity of the STUN
+ * message by calling pj_stun_msg_check() before starting to
+ * decode the packet.
+ */
+ PJ_STUN_CHECK_PACKET = 2
+};
+
/**
* Get STUN message method name.
*
@@ -1087,7 +1104,7 @@ PJ_DECL(pj_str_t) pj_stun_get_err_reason(int err_code);
/**
- * Create a blank STUN message.
+ * Create a generic STUN message.
*
* @param pool Pool to create the STUN message.
* @param msg_type The 14bit message type.
@@ -1105,6 +1122,28 @@ PJ_DECL(pj_status_t) pj_stun_msg_create(pj_pool_t *pool,
const pj_uint8_t tsx_id[12],
pj_stun_msg **p_msg);
+/**
+ * Create STUN response message.
+ *
+ * @param pool Pool to create the mesage.
+ * @param req_msg The request message.
+ * @param err_code STUN error code. If this value is not zero,
+ * then error response will be created, otherwise
+ * successful response will be created.
+ * @param err_msg Optional error message to explain err_code.
+ * If this value is NULL and err_code is not zero,
+ * the error string will be taken from the default
+ * STUN error message.
+ * @param p_response Pointer to receive the response.
+ *
+ * @return PJ_SUCCESS on success, or the appropriate error.
+ */
+PJ_DECL(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
+ const pj_stun_msg *req_msg,
+ unsigned err_code,
+ const pj_str_t *err_msg,
+ pj_stun_msg **p_response);
+
/**
* Add STUN attribute to STUN message.
@@ -1120,6 +1159,41 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
/**
+ * Print the STUN message structure to a packet buffer, ready to be
+ * sent to remote destination. This function will take care about
+ * calculating the MESSAGE-INTEGRITY digest as well as FINGERPRINT
+ * value.
+ *
+ * If MESSAGE-INTEGRITY attribute is present, the function assumes
+ * that application wants to include credential (short or long term)
+ * in the message, and this function will calculate the HMAC digest
+ * from the message using the supplied password in the parameter.
+ * If REALM attribute is present, the HMAC digest is calculated as
+ * long term credential, otherwise as short term credential.
+ *
+ * If FINGERPRINT attribute is present, this function will calculate
+ * the FINGERPRINT CRC attribute for the message.
+ *
+ * @param msg The STUN message to be printed.
+ * @param pkt_buf The buffer to be filled with the packet.
+ * @param buf_size Size of the buffer.
+ * @param options Options, which currently must be zero.
+ * @param password Password to be used when credential is to be
+ * included. This parameter MUST be specified when
+ * the message contains MESSAGE-INTEGRITY attribute.
+ * @param p_msg_len Upon return, it will be filed with the size of
+ * the packet in bytes, or negative value on error.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
+ pj_uint8_t *pkt_buf,
+ unsigned buf_size,
+ unsigned options,
+ const pj_str_t *password,
+ unsigned *p_msg_len);
+
+/**
* Check that the PDU is potentially a valid STUN message. This function
* is useful when application needs to multiplex STUN packets with other
* application traffic. When this function returns PJ_SUCCESS, there is a
@@ -1130,35 +1204,38 @@ PJ_DECL(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
*
* @param pdu The packet buffer.
* @param pdu_len The length of the packet buffer.
- * @param options Options.
+ * @param options Additional options to be applied in the checking,
+ * which can be taken from pj_stun_options. One of the
+ * useful option is PJ_STUN_IS_DATAGRAM which means that
+ * the pdu represents a whole STUN packet.
*
* @return PJ_SUCCESS if the PDU is a potentially valid STUN
* message.
*/
-PJ_DECL(pj_status_t) pj_stun_msg_check(const void *pdu, unsigned pdu_len,
+PJ_DECL(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
unsigned options);
/**
- * Parse incoming packet into STUN message.
+ * Decode incoming packet into STUN message.
*
* @param pool Pool to allocate the message.
* @param pdu The incoming packet to be parsed.
* @param pdu_len The length of the incoming packet.
- * @param options Parsing flags.
+ * @param options Parsing flags, according to pj_stun_options.
* @param p_msg Pointer to receive the parsed message.
* @param p_parsed_len Optional pointer to receive how many bytes have
* been parsed for the STUN message. This is useful
* when the packet is received over stream oriented
* transport.
- * @param p_err_code Optional pointer to receive STUN error code when
- * parsing failed.
- * @param uattr_cnt Optional pointer to specify the number of elements
- * in uattr array. On return, this will be filled with
- * the actual number of attributes set in the uattr.
- * @param uattr Optional array to receive unknown attribute types.
+ * @param p_response Optional pointer to receive an instance of response
+ * message, if one can be created. If the packet being
+ * decoded is a request message, and it contains error,
+ * and a response can be created, then the STUN
+ * response message will be returned on this argument.
*
- * @return PJ_SUCCESS on success or the appropriate error code.
+ * @return PJ_SUCCESS if a STUN message has been successfully
+ * decoded.
*/
PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
const pj_uint8_t *pdu,
@@ -1166,44 +1243,43 @@ PJ_DECL(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
unsigned options,
pj_stun_msg **p_msg,
unsigned *p_parsed_len,
- unsigned *p_err_code,
- unsigned *uattr_cnt,
- pj_uint16_t uattr[]);
+ pj_stun_msg **p_response);
/**
- * Print the STUN message structure to a packet buffer, ready to be
- * sent to remote destination. This function will take care about
- * calculating the MESSAGE-INTEGRITY digest as well as FINGERPRINT
- * value.
- *
- * If MESSAGE-INTEGRITY attribute is present, the function assumes
- * that application wants to include credential (short or long term)
- * in the message, and this function will calculate the HMAC digest
- * from the message using the supplied password in the parameter.
- * If REALM attribute is present, the HMAC digest is calculated as
- * long term credential, otherwise as short term credential.
+ * Verify credential in the STUN message. Note that before calling this
+ * function, application must have checked that the message contains
+ * PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute by calling pj_stun_msg_find_attr()
+ * function, because this function will reject the message with 401 error
+ * if it doesn't contain PJ_STUN_ATTR_MESSAGE_INTEGRITY attribute.
*
- * If FINGERPRINT attribute is present, this function will calculate
- * the FINGERPRINT CRC attribute for the message.
- *
- * @param msg The STUN message to be printed.
- * @param pkt_buf The buffer to be filled with the packet.
- * @param buf_size Size of the buffer.
- * @param options Options, which currently must be zero.
- * @param password Password to be used when credential is to be
- * included. This parameter MUST be specified when
- * the message contains MESSAGE-INTEGRITY attribute.
- * @param p_msg_len Upon return, it will be filed with the size of
- * the packet in bytes, or negative value on error.
+ * @param msg The message to be verified.
+ * @param realm Realm, if long term credential is required. If
+ * short term credential is required, this argument
+ * must be set to NULL.
+ * @param username If this attribute is specified, then the USERNAME
+ * attribute in the message will be compared against
+ * this value. If NULL is specified, then this function
+ * will accept any usernames.
+ * @param password The password.
+ * @param options Options, must be zero for now.
+ * @param pool If response is to be created, then memory will
+ * be allocated from this pool.
+ * @param p_response Optional pointer to receive the response message
+ * then the credential in the request fails to
+ * authenticate.
*
- * @return PJ_SUCCESS on success or the appropriate error code.
+ * @return PJ_SUCCESS if credential is verified successfully.
+ * If the verification fails and \a p_response is not
+ * NULL, an appropriate response will be returned in
+ * \a p_response.
*/
-PJ_DECL(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
- pj_uint8_t *pkt_buf,
- unsigned buf_size,
- unsigned options,
- const pj_str_t *password,
- unsigned *p_msg_len);
+PJ_DECL(pj_status_t) pj_stun_verify_credential(const pj_stun_msg *msg,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *password,
+ unsigned options,
+ pj_pool_t *pool,
+ pj_stun_msg **p_response);
/**
@@ -1243,8 +1319,9 @@ PJ_DECL(pj_stun_attr_hdr*) pj_stun_msg_find_attr(const pj_stun_msg *msg,
/**
- * Create a generic STUN IP address attribute for IPv4 address. Note that
- * the port and ip_addr parameters are in host byte order.
+ * Create a generic STUN IP address attribute. The \a addr_len and
+ * \a addr parameters specify whether the address is IPv4 or IPv4
+ * address.
*
* @param pool The pool to allocate memory from.
* @param attr_type Attribute type, from #pj_stun_attr_type.
@@ -1266,6 +1343,29 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
/**
+ * Create and add generic STUN IP address attribute to a STUN message.
+ * The \a addr_len and \a addr parameters specify whether the address is
+ * IPv4 or IPv4 address.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message.
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
+ * @param xor_ed If non-zero, the port and address will be XOR-ed
+ * with magic, to make the XOR-MAPPED-ADDRESS attribute.
+ * @param addr_len Length of \a addr parameter.
+ * @param addr A pj_sockaddr_in or pj_sockaddr_in6 structure.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_bool_t xor_ed,
+ unsigned addr_len,
+ const pj_sockaddr_t *addr);
+
+/**
* Create a STUN generic string attribute.
*
* @param pool The pool to allocate memory from.
@@ -1281,6 +1381,21 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool,
const pj_str_t *value,
pj_stun_generic_string_attr **p_attr);
+/**
+ * Create and add STUN generic string attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message.
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
+ * @param value The string value to be assigned to the attribute.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_str_t *value);
/**
* Create a STUN generic 32bit value attribute.
@@ -1298,6 +1413,22 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool,
pj_uint32_t value,
pj_stun_generic_uint_attr **p_attr);
+/**
+ * Create and add STUN generic 32bit value attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message
+ * @param attr_type Attribute type, from #pj_stun_attr_type.
+ * @param value The 32bit value to be assigned to the attribute.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_uint32_t value);
+
/**
* Create a STUN MESSAGE-INTEGRITY attribute.
@@ -1311,7 +1442,6 @@ PJ_DECL(pj_status_t)
pj_stun_msg_integrity_attr_create(pj_pool_t *pool,
pj_stun_msg_integrity_attr **p_attr);
-
/**
* Create a STUN ERROR-CODE attribute.
*
@@ -1331,7 +1461,8 @@ pj_stun_error_code_attr_create(pj_pool_t *pool,
/**
- * Create an empty instance of STUN UNKNOWN-ATTRIBUTES attribute.
+ * Create instance of STUN UNKNOWN-ATTRIBUTES attribute and copy the
+ * unknown attribute array to the attribute.
*
* @param pool The pool to allocate memory from.
* @param attr_cnt Number of attributes in the array (can be zero).
@@ -1343,15 +1474,34 @@ pj_stun_error_code_attr_create(pj_pool_t *pool,
PJ_DECL(pj_status_t)
pj_stun_unknown_attr_create(pj_pool_t *pool,
unsigned attr_cnt,
- pj_uint16_t attr[],
+ const pj_uint16_t attr[],
pj_stun_unknown_attr **p_attr);
+/**
+ * Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message.
+ * @param attr_cnt Number of attributes in the array (can be zero).
+ * @param attr Optional array of attributes.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ unsigned attr_cnt,
+ const pj_uint16_t attr[]);
/**
- * Create a blank binary attribute.
+ * Create STUN binary attribute.
*
* @param pool The pool to allocate memory from.
* @param attr_type The attribute type, from #pj_stun_attr_type.
+ * @param data Data to be coped to the attribute, or NULL
+ * if no data to be copied now.
+ * @param length Length of data, or zero if no data is to be
+ * copied now.
* @param p_attr Pointer to receive the attribute.
*
* @return PJ_SUCCESS on success or the appropriate error code.
@@ -1359,8 +1509,31 @@ pj_stun_unknown_attr_create(pj_pool_t *pool,
PJ_DECL(pj_status_t)
pj_stun_binary_attr_create(pj_pool_t *pool,
int attr_type,
+ const pj_uint8_t *data,
+ unsigned length,
pj_stun_binary_attr **p_attr);
+/**
+ * Create STUN binary attribute and add the attribute to the message.
+ *
+ * @param pool The pool to allocate memory from.
+ * @param msg The STUN message.
+ * @param attr_type The attribute type, from #pj_stun_attr_type.
+ * @param data Data to be coped to the attribute, or NULL
+ * if no data to be copied now.
+ * @param length Length of data, or zero if no data is to be
+ * copied now.
+ * @param p_attr Pointer to receive the attribute.
+ *
+ * @return PJ_SUCCESS on success or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
+pj_stun_msg_add_binary_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_uint8_t *data,
+ unsigned length);
+
/**
* @}
diff --git a/pjlib-util/src/pjlib-util-test/encryption.c b/pjlib-util/src/pjlib-util-test/encryption.c
index 0c5de154..34e5ae59 100644
--- a/pjlib-util/src/pjlib-util-test/encryption.c
+++ b/pjlib-util/src/pjlib-util-test/encryption.c
@@ -383,6 +383,58 @@ static int rfc2202_test(void)
return 0;
}
+/* CRC32 test data, generated from crc32 test on a Linux box */
+struct
+{
+ char *input;
+ pj_uint32_t crc;
+} crc32_test_data[] =
+{
+ {
+ "",
+ 0x0
+ },
+ {
+ "Hello World",
+ 0x4a17b156
+ },
+ {
+ /* Something read from /dev/random */
+ "\x21\x21\x98\x10\x62\x59\xbc\x58\x42\x24\xe5\xf3\x92\x0a\x68\x3c\xa7\x67\x73\xc3",
+ 0x506693be
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ 0xcab11777
+ },
+ {
+ "123456789",
+ 0xCBF43926
+ }
+};
+
+/*
+ * CRC32 test
+ */
+static int crc32_test(void)
+{
+ unsigned i;
+
+ PJ_LOG(3, (THIS_FILE, " crc32 test.."));
+
+ for (i=0; i<PJ_ARRAY_SIZE(crc32_test_data); ++i) {
+ pj_uint32_t crc;
+
+ crc = pj_crc32_calc((pj_uint8_t*)crc32_test_data[i].input,
+ pj_ansi_strlen(crc32_test_data[i].input));
+ if (crc != crc32_test_data[i].crc) {
+ PJ_LOG(3,(THIS_FILE, " error: crc mismatch on test %d", i));
+ return -80;
+ }
+ }
+ return 0;
+}
+
int encryption_test()
{
@@ -400,6 +452,10 @@ int encryption_test()
if (rc != 0)
return rc;
+ rc = crc32_test();
+ if (rc != 0)
+ return rc;
+
return 0;
}
diff --git a/pjlib-util/src/pjlib-util/crc32.c b/pjlib-util/src/pjlib-util/crc32.c
new file mode 100644
index 00000000..fa225ac9
--- /dev/null
+++ b/pjlib-util/src/pjlib-util/crc32.c
@@ -0,0 +1,192 @@
+/* $Id$ */
+/*
+ * This is an implementation of CRC32. See ISO 3309 and ITU-T V.42
+ * for a formal specification
+ *
+ * This file is partly taken from Crypto++ library (http://www.cryptopp.com).
+ *
+ * Since the original version of the code is put in public domain,
+ * this file is put on public domain as well.
+ */
+#include <pjlib-util/crc32.h>
+
+// crc.cpp - written and placed in the public domain by Wei Dai
+
+/* Table of CRC-32's of all single byte values (made by makecrc.c) */
+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN != 0
+
+#define CRC32_INDEX(c) (c & 0xff)
+#define CRC32_SHIFTED(c) (c >> 8)
+
+static const pj_uint32_t crc_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+
+#elif defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN != 0
+#define CRC32_INDEX(c) (c >> 24)
+#define CRC32_SHIFTED(c) (c << 8)
+
+static const pj_uint32_t crc_tab[] = {
+ 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
+ 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
+ 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
+ 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
+ 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
+ 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
+ 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
+ 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
+ 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
+ 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
+ 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
+ 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
+ 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
+ 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
+ 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
+ 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
+ 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
+ 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
+ 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
+ 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
+ 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
+ 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
+ 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
+ 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
+ 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
+ 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
+ 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
+ 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
+ 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
+ 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
+ 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
+ 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
+ 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
+ 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
+ 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
+ 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
+ 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
+ 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
+ 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
+ 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
+ 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
+ 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
+ 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
+ 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
+ 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
+ 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
+ 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
+ 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
+ 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
+ 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
+ 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
+ 0x8def022dL
+};
+
+#else
+# error "Endianness not defined"
+#endif
+
+
+#define CRC32_NEGL 0xffffffffL
+
+
+PJ_DEF(void) pj_crc32_init(pj_crc32_context *ctx)
+{
+ ctx->crc_state = 0;
+}
+
+PJ_DEF(pj_uint32_t) pj_crc32_update(pj_crc32_context *ctx,
+ const pj_uint8_t *data,
+ pj_size_t nbytes)
+{
+ pj_uint32_t crc = ctx->crc_state ^ CRC32_NEGL;
+
+ for( ; (((pj_uint32_t)data) & 0x03) && nbytes > 0; --nbytes) {
+ crc = crc_tab[CRC32_INDEX(crc) ^ *data++] ^ CRC32_SHIFTED(crc);
+ }
+
+ while (nbytes >= 4) {
+ crc ^= *(const pj_uint32_t *)data;
+ crc = crc_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+ crc = crc_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+ crc = crc_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+ crc = crc_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
+ nbytes -= 4;
+ data += 4;
+ }
+
+ while (nbytes--) {
+ crc = crc_tab[CRC32_INDEX(crc) ^ *data++] ^ CRC32_SHIFTED(crc);
+ }
+
+ ctx->crc_state = crc ^ CRC32_NEGL;
+
+ return ctx->crc_state;
+}
+
+PJ_DEF(pj_uint32_t) pj_crc32_final(pj_crc32_context *ctx)
+{
+ return ctx->crc_state;
+}
+
+PJ_DEF(pj_uint32_t) pj_crc32_calc( const pj_uint8_t *data,
+ pj_size_t nbytes)
+{
+ pj_crc32_context ctx;
+
+ pj_crc32_init(&ctx);
+ pj_crc32_update(&ctx, data, nbytes);
+ return pj_crc32_final(&ctx);
+}
+
diff --git a/pjlib-util/src/pjlib-util/stun_msg.c b/pjlib-util/src/pjlib-util/stun_msg.c
index fbe2223c..44c390d8 100644
--- a/pjlib-util/src/pjlib-util/stun_msg.c
+++ b/pjlib-util/src/pjlib-util/stun_msg.c
@@ -17,7 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjlib-util/stun_msg.h>
+#include <pjlib-util/crc32.h>
#include <pjlib-util/errno.h>
+#include <pjlib-util/hmac_sha1.h>
+#include <pjlib-util/md5.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/os.h>
@@ -25,8 +28,8 @@
#include <pj/rand.h>
#include <pj/string.h>
-#define THIS_FILE "stun_msg.c"
-
+#define THIS_FILE "stun_msg.c"
+#define STUN_XOR_FINGERPRINT 0x5354554eL
static const char *stun_method_names[] =
{
@@ -547,6 +550,28 @@ pj_stun_generic_ip_addr_attr_create(pj_pool_t *pool,
}
+/*
+ * Create and add generic STUN IP address attribute to a STUN message.
+ */
+PJ_DEF(pj_status_t)
+pj_stun_msg_add_generic_ip_addr_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_bool_t xor_ed,
+ unsigned addr_len,
+ const pj_sockaddr_t *addr)
+{
+ pj_stun_generic_ip_addr_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_generic_ip_addr_attr_create(pool, attr_type, xor_ed,
+ addr_len, addr, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
static pj_status_t decode_generic_ip_addr_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
@@ -658,6 +683,27 @@ pj_stun_generic_string_attr_create(pj_pool_t *pool,
}
+/*
+ * Create and add STUN generic string attribute to the message.
+ */
+PJ_DEF(pj_status_t)
+pj_stun_msg_add_generic_string_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_str_t *value)
+{
+ pj_stun_generic_string_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_generic_string_attr_create(pool, attr_type, value,
+ &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
+
static pj_status_t decode_generic_string_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
@@ -827,6 +873,22 @@ pj_stun_generic_uint_attr_create(pj_pool_t *pool,
return PJ_SUCCESS;
}
+/* Create and add STUN generic 32bit value attribute to the message. */
+PJ_DEF(pj_status_t)
+pj_stun_msg_add_generic_uint_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ pj_uint32_t value)
+{
+ pj_stun_generic_uint_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_generic_uint_attr_create(pool, attr_type, value, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
static pj_status_t decode_generic_uint_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
@@ -1087,7 +1149,7 @@ static pj_status_t encode_error_code_attr(const void *a, pj_uint8_t *buf,
PJ_DEF(pj_status_t)
pj_stun_unknown_attr_create(pj_pool_t *pool,
unsigned attr_cnt,
- pj_uint16_t attr_array[],
+ const pj_uint16_t attr_array[],
pj_stun_unknown_attr **p_attr)
{
pj_stun_unknown_attr *attr;
@@ -1116,6 +1178,23 @@ pj_stun_unknown_attr_create(pj_pool_t *pool,
}
+/* Create and add STUN UNKNOWN-ATTRIBUTES attribute to the message. */
+PJ_DEF(pj_status_t)
+pj_stun_msg_add_unknown_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ unsigned attr_cnt,
+ const pj_uint16_t attr_types[])
+{
+ pj_stun_unknown_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_unknown_attr_create(pool, attr_cnt, attr_types, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
static pj_status_t decode_unknown_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
@@ -1193,6 +1272,8 @@ static pj_status_t encode_unknown_attr(const void *a, pj_uint8_t *buf,
PJ_DEF(pj_status_t)
pj_stun_binary_attr_create(pj_pool_t *pool,
int attr_type,
+ const pj_uint8_t *data,
+ unsigned length,
pj_stun_binary_attr **p_attr)
{
pj_stun_binary_attr *attr;
@@ -1202,12 +1283,38 @@ pj_stun_binary_attr_create(pj_pool_t *pool,
attr = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_binary_attr);
INIT_ATTR(attr, attr_type, sizeof(pj_stun_binary_attr));
+ if (data && length) {
+ attr->length = length;
+ attr->data = pj_pool_alloc(pool, length);
+ pj_memcpy(attr->data, data, length);
+ }
+
*p_attr = attr;
return PJ_SUCCESS;
}
+/* Create and add binary attr. */
+PJ_DEF(pj_status_t)
+pj_stun_msg_add_binary_attr(pj_pool_t *pool,
+ pj_stun_msg *msg,
+ int attr_type,
+ const pj_uint8_t *data,
+ unsigned length)
+{
+ pj_stun_binary_attr *attr;
+ pj_status_t status;
+
+ status = pj_stun_binary_attr_create(pool, attr_type,
+ data, length, &attr);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ return pj_stun_msg_add_attr(msg, &attr->hdr);
+}
+
+
static pj_status_t decode_binary_attr(pj_pool_t *pool,
const pj_uint8_t *buf,
void **p_attr)
@@ -1324,42 +1431,119 @@ PJ_DEF(pj_status_t) pj_stun_msg_add_attr(pj_stun_msg *msg,
}
+PJ_INLINE(pj_uint16_t) GET_VAL16(const pj_uint8_t *pdu, unsigned pos)
+{
+ pj_uint16_t val = (pj_uint16_t) ((pdu[pos] << 8) + pdu[pos+1]);
+ return pj_ntohs(val);
+}
+
+PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos)
+{
+ pj_uint32_t val = (pdu[pos+0] << 24) +
+ (pdu[pos+1] << 16) +
+ (pdu[pos+2] << 8) +
+ (pdu[pos+3]);
+ return pj_ntohl(val);
+}
+
+
/*
* Check that the PDU is potentially a valid STUN message.
*/
-PJ_DEF(pj_status_t) pj_stun_msg_check(const void *pdu, unsigned pdu_len,
+PJ_DEF(pj_status_t) pj_stun_msg_check(const pj_uint8_t *pdu, unsigned pdu_len,
unsigned options)
{
- pj_stun_msg_hdr *hdr;
+ unsigned msg_len;
PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
if (pdu_len < sizeof(pj_stun_msg_hdr))
return PJLIB_UTIL_ESTUNINMSGLEN;
- PJ_UNUSED_ARG(options);
-
- hdr = (pj_stun_msg_hdr*) pdu;
-
/* First byte of STUN message is always 0x00 or 0x01. */
- if ((*(const char*)pdu) != 0x00 && (*(const char*)pdu) != 0x01)
+ if (*pdu != 0x00 && *pdu != 0x01)
return PJLIB_UTIL_ESTUNINMSGTYPE;
/* If magic is set, then there is great possibility that this is
* a STUN message.
*/
- if (pj_ntohl(hdr->magic) == PJ_STUN_MAGIC)
- return PJ_SUCCESS;
+ if (GET_VAL32(pdu, 4) != PJ_STUN_MAGIC)
+ return PJLIB_UTIL_ESTUNNOTMAGIC;
/* Check the PDU length */
- if (pj_ntohs(hdr->length) > pdu_len)
+ msg_len = GET_VAL16(pdu, 2);
+ if ((msg_len > pdu_len) ||
+ ((options & PJ_STUN_IS_DATAGRAM) && msg_len != pdu_len))
+ {
return PJLIB_UTIL_ESTUNINMSGLEN;
+ }
+
+ /* Check if FINGERPRINT attribute is present */
+ if (GET_VAL16(pdu, msg_len + 20) == PJ_STUN_ATTR_FINGERPRINT) {
+ pj_uint16_t attr_len = GET_VAL16(pdu, msg_len + 22);
+ pj_uint32_t fingerprint = GET_VAL32(pdu, msg_len + 24);
+ pj_uint32_t crc;
+
+ if (attr_len != 4)
+ return PJLIB_UTIL_ESTUNINATTRLEN;
+
+ crc = pj_crc32_calc(pdu, msg_len + 20);
+ crc ^= STUN_XOR_FINGERPRINT;
+
+ if (crc != fingerprint)
+ return PJLIB_UTIL_ESTUNFINGERPRINT;
+ }
/* Could be a STUN message */
return PJ_SUCCESS;
}
+/* Create error response */
+PJ_DEF(pj_status_t) pj_stun_msg_create_response(pj_pool_t *pool,
+ const pj_stun_msg *req_msg,
+ unsigned err_code,
+ const pj_str_t *err_msg,
+ pj_stun_msg **p_response)
+{
+ unsigned msg_type = req_msg->hdr.type;
+ pj_stun_msg *response;
+ pj_stun_error_code_attr *err_attr;
+ pj_status_t status;
+
+ PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL);
+
+ PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type),
+ PJLIB_UTIL_ESTUNINMSGTYPE);
+
+ /* Create response or error response */
+ if (err_code)
+ msg_type |= PJ_STUN_ERROR_RESPONSE_BIT;
+ else
+ msg_type |= PJ_STUN_RESPONSE_BIT;
+
+ status = pj_stun_msg_create(pool, msg_type, req_msg->hdr.magic,
+ req_msg->hdr.tsx_id, &response);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ /* Add error code attribute */
+ if (err_code) {
+ status = pj_stun_error_code_attr_create(pool, err_code, err_msg,
+ &err_attr);
+ if (status != PJ_SUCCESS) {
+ return status;
+ }
+
+ pj_stun_msg_add_attr(response, &err_attr->hdr);
+ }
+
+ *p_response = response;
+ return PJ_SUCCESS;
+}
+
+
/*
* Parse incoming packet into STUN message.
*/
@@ -1369,9 +1553,7 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
unsigned options,
pj_stun_msg **p_msg,
unsigned *p_parsed_len,
- unsigned *p_err_code,
- unsigned *p_uattr_cnt,
- pj_uint16_t uattr[])
+ pj_stun_msg **p_response)
{
pj_stun_msg *msg;
@@ -1384,9 +1566,17 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
PJ_ASSERT_RETURN(pool && pdu && pdu_len && p_msg, PJ_EINVAL);
PJ_ASSERT_RETURN(sizeof(pj_stun_msg_hdr) == 20, PJ_EBUG);
- /* Application should have checked that this is a valid STUN msg */
- PJ_ASSERT_RETURN((status=pj_stun_msg_check(pdu, pdu_len, options))
- == PJ_SUCCESS, status);
+ if (p_parsed_len)
+ *p_parsed_len = 0;
+ if (p_response)
+ *p_response = NULL;
+
+ /* Check if this is a STUN message, if necessary */
+ if (options & PJ_STUN_CHECK_PACKET) {
+ status = pj_stun_msg_check(pdu, pdu_len, options);
+ if (status != PJ_SUCCESS)
+ return status;
+ }
/* Create the message, copy the header, and convert to host byte order */
msg = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_msg);
@@ -1398,8 +1588,9 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
pdu += sizeof(pj_stun_msg_hdr);
pdu_len -= sizeof(pj_stun_msg_hdr);
- if (p_err_code)
- *p_err_code = 0;
+ /* No need to create response if this is not a request */
+ if (!PJ_STUN_IS_REQUEST(msg->hdr.type))
+ p_response = NULL;
/* Parse attributes */
uattr_cnt = 0;
@@ -1415,8 +1606,25 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
attr_val_len = (attr_val_len + 3) & (~3);
/* Check length */
- if (pdu_len < attr_val_len)
+ if (pdu_len < attr_val_len) {
+ pj_str_t err_msg;
+ char err_msg_buf[80];
+
+ err_msg.ptr = err_msg_buf;
+ err_msg.slen = pj_ansi_snprintf(err_msg_buf, sizeof(err_msg_buf),
+ "Attribute %s has invalid length",
+ pj_stun_get_attr_name(attr_type));
+
+ PJ_LOG(4,(THIS_FILE, "Error decoding message: %.*s",
+ (int)err_msg.slen, err_msg.ptr));
+
+ if (p_response) {
+ pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_BAD_REQUEST,
+ &err_msg, p_response);
+ }
return PJLIB_UTIL_ESTUNINATTRLEN;
+ }
/* Get the attribute descriptor */
adesc = find_attr_desc(attr_type);
@@ -1427,38 +1635,71 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
PJ_LOG(4,(THIS_FILE, "Unrecognized attribute type %d",
attr_type));
- /* Put to unrecognized attribute array */
- if (p_uattr_cnt && uattr && uattr_cnt < *p_uattr_cnt) {
- uattr[uattr_cnt++] = (pj_uint16_t)attr_type;
- }
-
/* Is this a fatal condition? */
if (attr_type <= 0x7FFF) {
/* This is a mandatory attribute, we must return error
* if we don't understand the attribute.
*/
- if (p_err_code && *p_err_code == 0)
- *p_err_code = PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE;
+ if (p_response) {
+ unsigned err_code = PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE;
+
+ status = pj_stun_msg_create_response(pool, msg,
+ err_code, NULL,
+ p_response);
+ if (status==PJ_SUCCESS) {
+ pj_uint16_t d = (pj_uint16_t)attr_type;
+ pj_stun_msg_add_unknown_attr(pool, *p_response, 1, &d);
+ }
+ }
return PJLIB_UTIL_ESTUNUNKNOWNATTR;
}
} else {
void *attr;
+ char err_msg1[PJ_ERR_MSG_SIZE],
+ err_msg2[PJ_ERR_MSG_SIZE];
/* Parse the attribute */
status = (adesc->decode_attr)(pool, pdu, &attr);
if (status != PJ_SUCCESS) {
+ pj_strerror(status, err_msg1, sizeof(err_msg1));
+
+ if (p_response) {
+ pj_str_t e;
+
+ e.ptr = err_msg2;
+ e.slen= pj_ansi_snprintf(err_msg2, sizeof(err_msg2),
+ "%s in %s",
+ err_msg1,
+ pj_stun_get_attr_name(attr_type));
+
+ pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_BAD_REQUEST,
+ &e, p_response);
+ }
+
PJ_LOG(4,(THIS_FILE,
- "Error parsing STUN attribute type %d: status=%d",
- attr_type, status));
+ "Error parsing STUN attribute %s: %s",
+ pj_stun_get_attr_name(attr_type),
+ err_msg1));
+
return status;
}
/* Make sure we have rooms for the new attribute */
- if (msg->attr_count >= PJ_STUN_MAX_ATTR)
+ if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
+ if (p_response) {
+ pj_str_t e;
+
+ e = pj_str("Too many attributes");
+ pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_BAD_REQUEST,
+ &e, p_response);
+ }
return PJLIB_UTIL_ESTUNTOOMANYATTR;
+ }
/* Add the attribute */
msg->attr[msg->attr_count++] = (pj_stun_attr_hdr*)attr;
@@ -1470,9 +1711,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_decode(pj_pool_t *pool,
*p_msg = msg;
- if (p_uattr_cnt)
- *p_uattr_cnt = uattr_cnt;
-
if (p_parsed_len)
*p_parsed_len = (pdu - start_pdu);
@@ -1494,7 +1732,11 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
pj_stun_realm_attr *arealm = NULL;
pj_stun_username_attr *auname = NULL;
pj_stun_msg_integrity_attr *amsg_integrity = NULL;
- unsigned i;
+ pj_stun_fingerprint_attr *afingerprint = NULL;
+ unsigned printed;
+ pj_status_t status;
+ unsigned i, length;
+
PJ_ASSERT_RETURN(msg && buf && buf_size, PJ_EINVAL);
@@ -1519,8 +1761,6 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
for (i=0; i<msg->attr_count; ++i) {
const struct attr_desc *adesc;
const pj_stun_attr_hdr *attr_hdr;
- unsigned printed;
- pj_status_t status;
attr_hdr = msg->attr[i];
@@ -1534,9 +1774,14 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
} else if (attr_hdr->type == PJ_STUN_ATTR_USERNAME) {
pj_assert(auname == NULL);
auname = (pj_stun_username_attr*) attr_hdr;
+
} else if (attr_hdr->type == PJ_STUN_ATTR_REALM) {
pj_assert(arealm == NULL);
arealm = (pj_stun_realm_attr*) attr_hdr;
+
+ } else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
+ afingerprint = (pj_stun_fingerprint_attr*) attr_hdr;
+ break;
}
adesc = find_attr_desc(attr_hdr->type);
@@ -1550,16 +1795,128 @@ PJ_DEF(pj_status_t) pj_stun_msg_encode(const pj_stun_msg *msg,
buf_size -= printed;
}
+ /* Calculate message integrity, if present */
if (amsg_integrity != NULL) {
- PJ_TODO(IMPLEMENT_MSG_INTEGRITY);
+
+ pj_uint8_t md5_key_buf[16];
+ pj_str_t key;
+
+ /* MESSAGE-INTEGRITY must be the last attribute in the message, or
+ * the last attribute before FINGERPRINT.
+ */
+ if (i < msg->attr_count-2) {
+ /* Should not happen for message generated by us */
+ pj_assert(PJ_FALSE);
+ return PJLIB_UTIL_ESTUNMSGINT;
+
+ } else if (i == msg->attr_count-2) {
+ if (msg->attr[i+1]->type != PJ_STUN_ATTR_FINGERPRINT) {
+ /* Should not happen for message generated by us */
+ pj_assert(PJ_FALSE);
+ return PJLIB_UTIL_ESTUNMSGINT;
+ } else {
+ afingerprint = (pj_stun_fingerprint_attr*) msg->attr[i+1];
+ }
+ }
+
+ /* Must have USERNAME attribute */
+ if (auname == NULL) {
+ /* Should not happen for message generated by us */
+ pj_assert(PJ_FALSE);
+ return PJLIB_UTIL_ESTUNNOUSERNAME;
+ }
+
+ /* Password must be specified */
+ PJ_ASSERT_RETURN(password, PJ_EINVAL);
+
+ /* Get the key to sign the message */
+ if (arealm == NULL ) {
+ /* For short term credential, the key is the password */
+ key = *password;
+
+ } else {
+ /* The 16-byte key for MESSAGE-INTEGRITY HMAC is formed by taking
+ * the MD5 hash of the result of concatenating the following five
+ * fields: (1) The username, with any quotes and trailing nulls
+ * removed, (2) A single colon, (3) The realm, with any quotes and
+ * trailing nulls removed, (4) A single colon, and (5) The
+ * password, with any trailing nulls removed.
+ */
+ pj_md5_context ctx;
+ pj_str_t s;
+
+ pj_md5_init(&ctx);
+
+#define REMOVE_QUOTE(s) if (s.slen && *s.ptr=='"') \
+ s.ptr++, s.slen--; \
+ if (s.slen && s.ptr[s.slen-1]=='"') \
+ s.slen--;
+
+ /* Add username */
+ s = auname->value;
+ REMOVE_QUOTE(s);
+ pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, s.slen);
+
+ /* Add single colon */
+ pj_md5_update(&ctx, (pj_uint8_t*)":", 1);
+
+ /* Add realm */
+ s = arealm->value;
+ REMOVE_QUOTE(s);
+ pj_md5_update(&ctx, (pj_uint8_t*)s.ptr, s.slen);
+
+#undef REMOVE_QUOTE
+
+ /* Another colon */
+ pj_md5_update(&ctx, (pj_uint8_t*)":", 1);
+
+ /* Add password */
+ pj_md5_update(&ctx, (pj_uint8_t*)password->ptr, password->slen);
+
+ /* Done */
+ pj_md5_final(&ctx, md5_key_buf);
+ key.ptr = (char*) md5_key_buf;
+ key.slen = 16;
+ }
+
+ /* Calculate HMAC-SHA1 digest */
+ pj_hmac_sha1((pj_uint8_t*)buf, buf-start,
+ (pj_uint8_t*)key.ptr, key.slen,
+ amsg_integrity->hmac);
+
+ /* Put this attribute in the message */
+ status = encode_msg_integrity_attr(amsg_integrity, buf, buf_size,
+ &printed);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ buf += printed;
+ buf_size -= printed;
}
+ /* Calculate FINGERPRINT if present */
+ if (afingerprint != NULL) {
+ afingerprint->value = pj_crc32_calc(start, buf-start);
+ afingerprint->value ^= STUN_XOR_FINGERPRINT;
+
+ /* Put this attribute in the message */
+ status = encode_generic_uint_attr(afingerprint, buf, buf_size,
+ &printed);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ buf += printed;
+ buf_size -= printed;
+ }
/* Update the message length in the header.
* Note that length is not including the 20 bytes header.
*/
- hdr->length = (pj_uint16_t)((buf - start) - 20);
- hdr->length = pj_htons(hdr->length);
+ length = (pj_uint16_t)((buf - start) - 20);
+ /* hdr->length = pj_htons(length); */
+ *(buf+2) = (pj_uint8_t)((length >> 8) & 0x00FF);
+ *(buf+3) = (pj_uint8_t)(length & 0x00FF);
+
/* Done */
if (p_msg_len)
@@ -1587,3 +1944,116 @@ PJ_DEF(pj_stun_attr_hdr*) pj_stun_msg_find_attr( const pj_stun_msg *msg,
return NULL;
}
+
+/* Verify credential */
+PJ_DEF(pj_status_t) pj_stun_verify_credential( const pj_stun_msg *msg,
+ const pj_str_t *realm,
+ const pj_str_t *username,
+ const pj_str_t *password,
+ unsigned options,
+ pj_pool_t *pool,
+ pj_stun_msg **p_response)
+{
+ const pj_stun_msg_integrity_attr *amsgi;
+ const pj_stun_username_attr *auser;
+ const pj_stun_realm_attr *arealm;
+
+ PJ_ASSERT_RETURN(msg && password, PJ_EINVAL);
+ PJ_ASSERT_RETURN(options==0, PJ_EINVAL);
+ PJ_UNUSED_ARG(options);
+
+ if (p_response)
+ *p_response = NULL;
+
+ /* First check that MESSAGE-INTEGRITY is present */
+ amsgi = (const pj_stun_msg_integrity_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0);
+ if (amsgi == NULL) {
+ if (pool && p_response) {
+ pj_status_t rc;
+
+ rc = pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_UNAUTHORIZED,
+ NULL, p_response);
+ if (rc==PJ_SUCCESS && realm) {
+ pj_stun_msg_add_generic_string_attr(pool, *p_response,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ }
+ }
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_UNAUTHORIZED);
+ }
+
+ /* Next check that USERNAME is present */
+ auser = (const pj_stun_username_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
+ if (auser == NULL) {
+ if (pool && p_response) {
+ pj_status_t rc;
+
+ rc = pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_MISSING_USERNAME,
+ NULL, p_response);
+ if (rc==PJ_SUCCESS && realm) {
+ pj_stun_msg_add_generic_string_attr(pool, *p_response,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ }
+ }
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_USERNAME);
+ }
+
+ /* Check if username match */
+ if (username && pj_stricmp(&auser->value, username) != 0) {
+ /* Username mismatch */
+ if (pool && p_response) {
+ pj_status_t rc;
+
+ rc = pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_WRONG_USERNAME,
+ NULL, p_response);
+ if (rc==PJ_SUCCESS && realm) {
+ pj_stun_msg_add_generic_string_attr(pool, *p_response,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ }
+ }
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_WRONG_USERNAME);
+ }
+
+ /* Next check that REALM is present */
+ arealm = (const pj_stun_realm_attr*)
+ pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
+ if (realm != NULL && arealm == NULL) {
+ /* Long term credential is required */
+ if (pool && p_response) {
+ pj_status_t rc;
+
+ rc = pj_stun_msg_create_response(pool, msg,
+ PJ_STUN_STATUS_MISSING_REALM,
+ NULL, p_response);
+ if (rc==PJ_SUCCESS) {
+ pj_stun_msg_add_generic_string_attr(pool, *p_response,
+ PJ_STUN_ATTR_REALM,
+ realm);
+ }
+ }
+ return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_STATUS_MISSING_REALM);
+
+ } else if (realm != NULL && arealm != NULL) {
+
+
+ } else if (realm == NULL && arealm != NULL) {
+ /* We want to use short term credential, but client uses long
+ * term credential. The draft doesn't mention anything about
+ * switching between long term and short term.
+ */
+ PJ_TODO(SWITCHING_BETWEEN_SHORT_TERM_AND_LONG_TERM);
+ }
+
+ PJ_TODO(CONTINUE_IMPLEMENTATION);
+
+ return PJ_SUCCESS;
+}
+
+
diff --git a/pjlib-util/src/pjstun-client/stun_session.c b/pjlib-util/src/pjstun-client/stun_session.c
index 101bb0b4..03dc6f19 100644
--- a/pjlib-util/src/pjstun-client/stun_session.c
+++ b/pjlib-util/src/pjstun-client/stun_session.c
@@ -484,7 +484,7 @@ PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
/* Encode message */
status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len,
- 0, &tdata->pkt_size);
+ 0, NULL, &tdata->pkt_size);
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "STUN encode() error", status);
destroy_tdata(tdata);
@@ -540,7 +540,7 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
pj_size_t pkt_size,
unsigned *parsed_len)
{
- pj_stun_msg *msg;
+ pj_stun_msg *msg, *response;
pj_pool_t *tmp_pool;
char *dump;
pj_status_t status;
@@ -554,9 +554,12 @@ PJ_DEF(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
/* Try to parse the message */
status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet,
pkt_size, 0, &msg, parsed_len,
- NULL, NULL, NULL);
+ &response);
if (status != PJ_SUCCESS) {
LOG_ERR_(sess, "STUN msg_decode() error", status);
+ if (response) {
+ PJ_TODO(SEND_RESPONSE);
+ }
pj_pool_release(tmp_pool);
return status;
}
diff --git a/pjlib-util/src/pjstun-srv/server_main.c b/pjlib-util/src/pjstun-srv/server_main.c
index 5fd58ef9..46dc2752 100644
--- a/pjlib-util/src/pjstun-srv/server_main.c
+++ b/pjlib-util/src/pjstun-srv/server_main.c
@@ -51,31 +51,12 @@ static pj_status_t create_response(pj_pool_t *pool,
{
pj_uint32_t msg_type = req_msg->hdr.type;
pj_stun_msg *response;
- pj_stun_error_code_attr *err_attr;
pj_status_t status;
- /* Create response or error response */
- if (err_code)
- msg_type |= PJ_STUN_ERROR_RESPONSE_BIT;
- else
- msg_type |= PJ_STUN_RESPONSE_BIT;
-
- status = pj_stun_msg_create(pool, msg_type, req_msg->hdr.magic,
- req_msg->hdr.tsx_id, &response);
- if (status != PJ_SUCCESS) {
+ status = pj_stun_msg_create_response(pool, req_msg, err_code, NULL,
+ &response);
+ if (status != PJ_SUCCESS)
return status;
- }
-
- /* Add error code attribute */
- if (err_code) {
- status = pj_stun_error_code_attr_create(pool, err_code, NULL,
- &err_attr);
- if (status != PJ_SUCCESS) {
- return status;
- }
-
- pj_stun_msg_add_attr(response, &err_attr->hdr);
- }
/* Add unknown_attribute attributes if err_code is 420 */
if (err_code == PJ_STUN_STATUS_UNKNOWN_ATTRIBUTE) {
@@ -110,7 +91,7 @@ static pj_status_t send_msg(struct service *svc, const pj_stun_msg *msg)
/* Encode packet */
tx_pkt_len = sizeof(svc->tx_pkt);
status = pj_stun_msg_encode(msg, svc->tx_pkt, tx_pkt_len, 0,
- &tx_pkt_len);
+ NULL, &tx_pkt_len);
if (status != PJ_SUCCESS)
return status;
@@ -223,10 +204,7 @@ static void on_read_complete(pj_ioqueue_key_t *key,
{
struct service *svc = (struct service *) pj_ioqueue_get_user_data(key);
pj_pool_t *pool = NULL;
- pj_stun_msg *rx_msg;
- unsigned err_code;
- unsigned uattr_cnt;
- pj_uint16_t uattr_types[16];
+ pj_stun_msg *rx_msg, *response;
char dump[512];
pj_status_t status;
@@ -235,16 +213,13 @@ static void on_read_complete(pj_ioqueue_key_t *key,
pool = pj_pool_create(&server.cp.factory, "service", 4000, 4000, NULL);
- err_code = 0;
- uattr_cnt = PJ_ARRAY_SIZE(uattr_types);
rx_msg = NULL;
status = pj_stun_msg_decode(pool, svc->rx_pkt, bytes_read, 0, &rx_msg,
- NULL, &err_code, &uattr_cnt, uattr_types);
+ NULL, &response);
if (status != PJ_SUCCESS) {
server_perror(THIS_FILE, "STUN msg_decode() error", status);
- if (err_code != 0 && rx_msg && PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) {
- err_respond(svc, pool, rx_msg, err_code,
- uattr_cnt, uattr_types);
+ if (response) {
+ send_msg(svc, response);
}
goto next_read;
}