Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
libnice
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
libnice
Commits
b9669017
Commit
b9669017
authored
Jun 06, 2008
by
Youness Alaoui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Updating stun to include an agent
parent
c07afc9a
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
915 additions
and
1550 deletions
+915
-1550
stun/Makefile.am
stun/Makefile.am
+12
-10
stun/constants.h
stun/constants.h
+2
-2
stun/stun-msg.h
stun/stun-msg.h
+1
-327
stun/stun3489bis.c
stun/stun3489bis.c
+27
-5
stun/stun3489bis.h
stun/stun3489bis.h
+3
-1
stun/stunagent.c
stun/stunagent.c
+461
-0
stun/stunagent.h
stun/stunagent.h
+111
-0
stun/stuncrc32.c
stun/stuncrc32.c
+1
-1
stun/stunhmac.c
stun/stunhmac.c
+1
-1
stun/stunhmac.h
stun/stunhmac.h
+3
-1
stun/stunmessage.c
stun/stunmessage.c
+59
-21
stun/stunmessage.h
stun/stunmessage.h
+73
-60
stun/stunrecv.c
stun/stunrecv.c
+0
-567
stun/stunsend.c
stun/stunsend.c
+0
-481
stun/tests/test-parse.c
stun/tests/test-parse.c
+3
-0
stun/tools/stunbdc.c
stun/tools/stunbdc.c
+1
-1
stun/utils.c
stun/utils.c
+146
-59
stun/utils.h
stun/utils.h
+11
-13
No files found.
stun/Makefile.am
View file @
b9669017
...
...
@@ -19,16 +19,18 @@ CLEANFILES += $(BUILT_SOURCES)
noinst_LTLIBRARIES
=
libstun.la
dist_noinst_SCRIPTS
=
build-unknown.sh
libstun_la_SOURCES
=
\
stun-msg.h stunsend.c stunrecv.c
\
stun3489bis.c
\
utils.c
\
unknown.c
\
crc32.c hmac.c
\
usages/timer.h usages/timer.c
\
usages/trans.h usages/trans.c
\
usages/stun-ice.c usages/stun-ice.h
\
usages/bind.c usages/bind.h
libstun_la_SOURCES
=
stun.h constants.h
\
stunagent.c stunagent.h
\
stunmessage.c stunmessage.h
\
stun3489bis.c stun3489bis.h
\
stuncrc32.c stuncrc32.h
\
stunhmac.c stunhmac.h
\
utils.c utils.h
# usages/timer.h usages/timer.c \
# usages/trans.h usages/trans.c \
# usages/stun-ice.c usages/stun-ice.h \
# usages/bind.c usages/bind.h
libstun_la_LIBADD
=
$(OPENSSL_LIBS)
$(LIBRT)
...
...
stun/constants.h
View file @
b9669017
...
...
@@ -67,9 +67,9 @@
#define STUN_ID_LEN 16
#define STUN_AGENT_MAX_SAVED_IDS 20
#define STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES 256
#define STUN_COOKIE 0x2112A442
#define STUN_MAGIC_COOKIE 0x2112A442
#ifndef TRUE
#define TRUE (1 == 1)
...
...
stun/stun-msg.h
View file @
b9669017
...
...
@@ -54,138 +54,12 @@
# define STUN_MAXCHR 127u
# define STUN_MAXSTR ((STUN_MAXCHR * 6u) + 1)
# define STUN_COOKIE 0x2112A442
typedef
struct
stun_hdr_s
{
uint16_t
msg_type
;
uint16_t
msg_len
;
uint32_t
msg_cookie
;
uint32_t
msg_id
[
3
];
}
stun_hdr_t
;
typedef
uint8_t
stun_msg_t
[
STUN_MAXMSG
];
/* Message classes */
typedef
enum
{
STUN_REQUEST
=
0
,
STUN_INDICATION
=
1
,
STUN_RESPONSE
=
2
,
STUN_ERROR
=
3
}
stun_class_t
;
/* Message methods */
typedef
enum
{
STUN_BINDING
=
0x001
,
/* RFC3489bis-11 */
STUN_OLD_SHARED_SECRET
=
0x002
,
/* old RFC3489 */
STUN_ALLOCATE
=
0x003
,
/* TURN-04 */
STUN_SET_ACTIVE_DST
=
0x004
,
/* TURN-04 */
STUN_CONNECT
=
0x005
,
/* TURN-04 */
STUN_IND_SEND
=
0x006
,
/* TURN-04 */
STUN_IND_DATA
=
0x007
,
/* TURN-04 */
STUN_IND_CONNECT_STATUS
=
0x008
/* TURN-04 */
}
stun_method_t
;
/**
* STUN attribute types
* Should be in sync with stun_is_unknown()
*/
typedef
enum
{
/* Mandatory attributes */
/* 0x0000 */
/* reserved */
STUN_MAPPED_ADDRESS
=
0x0001
,
/* RFC3489bis-11 */
STUN_OLD_RESPONSE_ADDRESS
=
0x0002
,
/* old RFC3489 */
STUN_OLD_CHANGE_REQUEST
=
0x0003
,
/* old RFC3489 */
STUN_OLD_SOURCE_ADDRESS
=
0x0004
,
/* old RFC3489 */
STUN_OLD_CHANGED_ADDRESS
=
0x0005
,
/* old RFC3489 */
STUN_USERNAME
=
0x0006
,
/* RFC3489bis-11 */
STUN_OLD_PASSWORD
=
0x0007
,
/* old RFC3489 */
STUN_MESSAGE_INTEGRITY
=
0x0008
,
/* RFC3489bis-11 */
STUN_ERROR_CODE
=
0x0009
,
/* RFC3489bis-11 */
STUN_UNKNOWN_ATTRIBUTES
=
0x000A
,
/* RFC3489bis-11 */
STUN_OLD_REFLECTED_FROM
=
0x000B
,
/* old RFC3489 */
/* 0x000C */
/* reserved */
STUN_LIFETIME
=
0x000D
,
/* TURN-04 */
/* 0x000E */
/* reserved */
/* 0x000F */
/* reserved */
STUN_BANDWIDTH
=
0x0010
,
/* TURN-04 */
/* 0x0011 */
/* reserved */
STUN_REMOTE_ADDRESS
=
0x0012
,
/* TURN-04 */
STUN_DATA
=
0x0013
,
/* TURN-04 */
STUN_REALM
=
0x0014
,
/* RFC3489bis-11 */
STUN_NONCE
=
0x0015
,
/* RFC3489bis-11 */
STUN_RELAY_ADDRESS
=
0x0016
,
/* TURN-04 */
STUN_REQUESTED_ADDRESS_TYPE
=
0x0017
,
/* TURN-IPv6-03 */
STUN_REQUESTED_PORT_PROPS
=
0x0018
,
/* TURN-04 */
STUN_REQUESTED_TRANSPORT
=
0x0019
,
/* TURN-04 */
/* 0x001A */
/* reserved */
/* 0x001B */
/* reserved */
/* 0x001C */
/* reserved */
/* 0x001D */
/* reserved */
/* 0x001E */
/* reserved */
/* 0x001F */
/* reserved */
STUN_XOR_MAPPED_ADDRESS
=
0x0020
,
/* RFC3489bis-11 */
STUN_TIMER_VAL
=
0x0021
,
/* TURN-04 */
STUN_REQUESTED_IP
=
0x0022
,
/* TURN-04 */
STUN_CONNECT_STAT
=
0x0023
,
/* TURN-04 */
STUN_PRIORITY
=
0x0024
,
/* ICE-18 */
STUN_USE_CANDIDATE
=
0x0025
,
/* ICE-18 */
/* 0x0026 */
/* reserved */
/* 0x0027 */
/* reserved */
/* 0x0028 */
/* reserved */
STUN_XOR_INTERNAL_ADDRESS
=
0x0029
,
/* wing-nat-control-04 */
/* 0x002A-0x7fff */
/* reserved */
/* Optional attributes */
/* 0x8000-0x8021 */
/* reserved */
STUN_SERVER
=
0x8022
,
/* RFC3489bis-11 */
STUN_ALTERNATE_SERVER
=
0x8023
,
/* RFC3489bis-11 */
STUN_REFRESH_INTERVAL
=
0x8024
,
/* wing-nat-control-04 */
/* 0x8025 */
/* reserved */
/* 0x8026 */
/* reserved */
/* 0x8027 */
/* reserved */
STUN_FINGERPRINT
=
0x8028
,
/* RFC3489bis-11 */
STUN_ICE_CONTROLLED
=
0x8029
,
/* ICE-18 */
STUN_ICE_CONTROLLING
=
0x802A
,
/* ICE-18 */
/* 0x802B-0xFFFF */
/* reserved */
}
stun_attr_type_t
;
typedef
uint8_t
stun_transid_t
[
12
];
/**
* STUN error codes
* Should be in sync with stun_strerror()
*/
typedef
enum
{
STUN_TRY_ALTERNATE
=
300
,
/* RFC3489bis-11 */
STUN_BAD_REQUEST
=
400
,
/* RFC3489bis-11 */
STUN_UNAUTHORIZED
=
401
,
/* RFC3489bis-11 */
STUN_UNKNOWN_ATTRIBUTE
=
420
,
/* RFC3489bis-11 */
STUN_NO_BINDING
=
437
,
/* TURN-04 */
STUN_STALE_NONCE
=
438
,
/* RFC3489bis-11 */
STUN_ACT_DST_ALREADY
=
439
,
/* TURN-04 */
STUN_UNSUPP_FAMILY
=
440
,
/* TURN-IPv6-03 */
STUN_UNSUPP_TRANSPORT
=
442
,
/* TURN-04 */
STUN_INVALID_IP
=
443
,
/* TURN-04 */
STUN_INVALID_PORT
=
444
,
/* TURN-04 */
STUN_OP_TCP_ONLY
=
445
,
/* TURN-04 */
STUN_CONN_ALREADY
=
446
,
/* TURN-04 */
STUN_ALLOC_OVER_QUOTA
=
486
,
/* TURN-04 */
STUN_ROLE_CONFLICT
=
487
,
/* ICE-18 */
STUN_SERVER_ERROR
=
500
,
/* RFC3489bis-11 */
STUN_SERVER_CAPACITY
=
507
,
/* TURN-04 */
STUN_ERROR_MAX
=
699
}
stun_error_t
;
#include "utils.h"
#include "stun3489bis.h"
#include "stunhmac.h"
# ifndef NDEBUG
# include <stdio.h>
...
...
@@ -204,31 +78,6 @@ extern "C" {
# endif
/**
* Computes the MESSAGE-INTEGRITY hash of a STUN message.
* @param msg pointer to the STUN message
* @param len size of the message from header (inclusive) and up to
* MESSAGE-INTEGRITY attribute (inclusive)
* @param sha output buffer for SHA1 hash (20 bytes)
* @param key HMAC key
* @param keylen HMAC key bytes length
*
* @return fingerprint value in <b>host</b> byte order.
*/
void
stun_sha1
(
const
uint8_t
*
msg
,
size_t
len
,
uint8_t
*
sha
,
const
void
*
key
,
size_t
keylen
);
/**
* SIP H(A1) computation
*/
void
stun_hash_creds
(
const
char
*
realm
,
const
char
*
login
,
const
char
*
pw
,
unsigned
char
md5
[
16
]);
/**
* Generates a pseudo-random secure STUN transaction ID.
*/
void
stun_make_transid
(
stun_transid_t
id
);
int
stun_xor_address
(
const
uint8_t
*
msg
,
struct
sockaddr
*
addr
,
socklen_t
addrlen
);
...
...
@@ -280,102 +129,6 @@ int stun_verify_key (const uint8_t *msg, const void *key, size_t keylen);
int
stun_verify_password
(
const
uint8_t
*
msg
,
const
char
*
pw
);
int
stun_verify_username
(
const
uint8_t
*
msg
,
const
char
*
local_ufrag
,
uint32_t
compat
);
/**
* Looks for an attribute in a *valid* STUN message.
* @param msg message buffer
* @param type STUN attribute type (host byte order)
* @param palen [OUT] pointer to store the byte length of the attribute
* @return a pointer to the start of the attribute payload if found,
* otherwise NULL.
*/
const
void
*
stun_find
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
uint16_t
*
restrict
palen
);
/**
* Looks for a flag attribute within a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @return 0 if flag is present, ENOENT if it is not, EINVAL if flag payload
* size is not zero.
*/
int
stun_find_flag
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
);
/**
* Extracts a 32-bits attribute from a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param pval [OUT] where to store the host byte ordered value
*
* @return 0 on success, ENOENT if attribute not found,
* EINVAL if attribute payload was not 32-bits.
* In case of error, @a *pval is not modified.
*/
int
stun_find32
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
,
uint32_t
*
pval
);
/**
* Extracts a 64-bits attribute from a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param pval [OUT] where to store the host byte ordered value
* @return 0 on success, ENOENT if attribute not found,
* EINVAL if attribute payload was not 64-bits.
* In case of error, @a *pval is not modified.
*/
int
stun_find64
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
,
uint64_t
*
pval
);
/**
* Extracts an UTF-8 string from a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param buf buffer to store the extracted string
* @param maxcp maximum number of code points allowed
* (@a buf should be (6*maxcp+1) bytes long)
*
* @return 0 on success, ENOENT if attribute not found, EINVAL if attribute
* improperly encoded, ENOBUFS if the buffer size was too small.
*
* @note A nul-byte is appended at the end.
*/
int
stun_find_string
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
char
*
buf
,
size_t
buflen
);
# define STUN_MAX_STR (763u)
# define STUN_MAX_CP (127u)
/**
* Extracts a network address attribute from a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param addr [OUT] where to store the socket address
* @param addrlen [IN/OUT] pointer to the size of the socket address
* buffer upon entry, set to the length of the extracted socket
* address upon return,
* @return 0 on success, ENOENT if attribute not found,
* EINVAL if attribute payload size was wrong or addrlen too small,
* EAFNOSUPPORT if address family is unknown.
*/
int
stun_find_addr
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
struct
sockaddr
*
restrict
addr
,
socklen_t
*
restrict
addrlen
);
/**
* Extracts an obfuscated network address attribute from a valid STUN message.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param addr [OUT] where to store the socket address
* @param addrlen [IN/OUT] pointer to the size of the socket address
* buffer upon entry, set to the length of the extracted socket
* address upon return,
* @return 0 on success, ENOENT if attribute not found,
* EINVAL if attribute payload size was wrong or addrlen too small,
* EAFNOSUPPORT if address family is unknown.
*/
int
stun_find_xor_addr
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
struct
sockaddr
*
restrict
addr
,
socklen_t
*
restrict
addrlen
);
/**
* Compares the length and content of an attribute.
*
...
...
@@ -515,85 +268,6 @@ size_t stun_finish_short (uint8_t *msg, size_t *restrict plen,
size_t
stun_finish
(
uint8_t
*
restrict
msg
,
size_t
*
restrict
plen
,
int
compat
);
void
*
stun_append
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
size_t
length
);
int
stun_append_bytes
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
void
*
data
,
size_t
len
);
/**
* Appends an empty ("flag") attribute to a STUN message.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribute type (host byte order)
* @return 0 on success, ENOBUFS on error.
*/
int
stun_append_flag
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
);
/**
* Appends an attribute consisting of a 32-bits value to a STUN message.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribute type (host byte order)
* @param value payload (host byte order)
* @return 0 on success, ENOBUFS on error.
*/
int
stun_append32
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
uint32_t
value
);
/**
* Appends an attribute consisting of a 64-bits value to a STUN message.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribute type (host byte order)
* @param value payload (host byte order)
* @return 0 on success, ENOBUFS on error.
*/
int
stun_append64
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
uint64_t
value
);
/**
* Appends an attribute from a nul-terminated string.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribute type (host byte order)
* @param str nul-terminated string
* @return 0 on success, ENOBUFS on error.
*/
int
stun_append_string
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
char
*
str
);
/**
* Appends an attribute consisting of a network address to a STUN message.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribyte type (host byte order)
* @param addr socket address to convert into an attribute
* @param addrlen byte length of socket address
* @return 0 on success, ENOBUFS if the message buffer overflowed,
* EAFNOSUPPORT is the socket address family is not supported,
* EINVAL if the socket address length is too small w.r.t. the address family.
*/
int
stun_append_addr
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
);
/**
* Appends an attribute consisting of a xor'ed network address.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribyte type (host byte order)
* @param addr socket address to convert into an attribute
* @param addrlen byte length of socket address
* @return 0 on success, ENOBUFS if the message buffer overflowed,
* EAFNOSUPPORT is the socket address family is not supported,
* EINVAL if the socket address length is too small w.r.t. the address family.
*/
int
stun_append_xor_addr
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
);
# ifdef __cplusplus
}
# endif
...
...
stun/stun3489bis.c
View file @
b9669017
...
...
@@ -35,19 +35,24 @@
* file under either the MPL or the LGPL.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
/* htons() */
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "crc32.h"
#include "stun
-msg
.h"
#include "
stun
crc32.h"
#include "stun
message
.h"
uint32_t
stun_fingerprint
(
const
uint8_t
*
msg
,
size_t
len
)
{
struct
iovec
iov
[
3
];
uint16_t
fakelen
=
htons
(
len
-
20u
);
assert
(
len
>=
28u
);
//
assert (len >= 28u);
iov
[
0
].
iov_base
=
(
void
*
)
msg
;
iov
[
0
].
iov_len
=
2
;
...
...
@@ -57,5 +62,22 @@ uint32_t stun_fingerprint (const uint8_t *msg, size_t len)
/* first 4 bytes done, last 8 bytes not summed */
iov
[
2
].
iov_len
=
len
-
12u
;
return
crc32
(
iov
,
sizeof
(
iov
)
/
sizeof
(
iov
[
0
]))
^
0x5354554e
;
return
htonl
(
crc32
(
iov
,
sizeof
(
iov
)
/
sizeof
(
iov
[
0
]))
^
0x5354554e
);
}
bool
stun_has_cookie
(
const
StunMessage
*
msg
)
{
stun_transid_t
id
;
stun_message_id
(
msg
,
id
);
uint32_t
cookie
=
htonl
(
STUN_MAGIC_COOKIE
);
return
memcmp
(
id
,
&
cookie
,
sizeof
(
cookie
))
==
0
;
}
int
stun_message_append_server
(
StunMessage
*
msg
)
{
static
const
char
server
[]
=
PACKAGE_STRING
;
// assert (strlen (server) < 128);
return
stun_message_append_string
(
msg
,
STUN_ATTRIBUTE_SERVER
,
server
);
}
stun/stun3489bis.h
View file @
b9669017
...
...
@@ -54,8 +54,10 @@
*/
uint32_t
stun_fingerprint
(
const
uint8_t
*
msg
,
size_t
len
);
bool
stun_has_cookie
(
const
StunMessage
*
msg
);
int
stun_message_append_server
(
StunMessage
*
msg
);
bool
stun_has_cookie
(
const
uint8_t
*
msg
);
#endif
/* _STUN_3489BIS_H */
stun/stunagent.c
0 → 100644
View file @
b9669017
/*
* This file is part of the Nice GLib ICE library.
*
* (C) 2007 Nokia Corporation. All rights reserved.
* Contact: Rémi Denis-Courmont
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Nice GLib ICE library.
*
* The Initial Developers of the Original Code are Collabora Ltd and Nokia
* Corporation. All Rights Reserved.
*
* Contributors:
* Rémi Denis-Courmont, Nokia
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
* case the provisions of LGPL are applicable instead of those above. If you
* wish to allow use of your version of this file only under the terms of the
* LGPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replace
* them with the notice and other provisions required by the LGPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the LGPL.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include "stunmessage.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <netinet/in.h>
static
bool
stun_agent_is_unknown
(
StunAgent
*
agent
,
uint16_t
type
);
static
unsigned
stun_agent_find_unknowns
(
StunAgent
*
agent
,
const
StunMessage
*
msg
,
uint16_t
*
list
,
unsigned
max
);
void
stun_agent_init
(
StunAgent
*
agent
,
const
uint16_t
*
known_attributes
,
StunCompatibility
compatibility
,
uint32_t
usage_flags
)
{
int
i
;
agent
->
known_attributes
=
(
uint16_t
*
)
known_attributes
;
agent
->
compatibility
=
compatibility
;
agent
->
usage_flags
=
usage_flags
;
for
(
i
=
0
;
i
<
STUN_AGENT_MAX_SAVED_IDS
;
i
++
)
{
agent
->
sent_ids
[
i
].
valid
=
FALSE
;
}
}
StunValidationStatus
stun_agent_validate
(
StunAgent
*
agent
,
StunMessage
*
msg
,
const
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessageIntegrityValidate
validater
,
void
*
validater_data
)
{
stun_transid_t
msg_id
;
uint32_t
fpr
;
uint32_t
crc32
;
int
len
;
int
error_code
;
uint8_t
*
username
=
NULL
;
uint16_t
username_len
;
uint8_t
*
key
=
NULL
;
size_t
key_len
;
uint8_t
*
hash
;
uint8_t
sha
[
20
];
uint16_t
hlen
;
int
sent_id_idx
=
-
1
;
len
=
stun_message_validate_buffer_length
(
buffer
,
buffer_len
);
if
(
len
==
STUN_MESSAGE_BUFFER_INVALID
)
{
return
STUN_VALIDATION_NOT_STUN
;
}
else
if
(
len
==
STUN_MESSAGE_BUFFER_INCOMPLETE
)
{
return
STUN_VALIDATION_INCOMPLETE_STUN
;
}
else
if
(
len
!=
(
int
)
buffer_len
)
{
return
STUN_VALIDATION_NOT_STUN
;
}
msg
->
buffer
=
(
uint8_t
*
)
buffer
;
msg
->
buffer_len
=
buffer_len
;
msg
->
agent
=
agent
;
msg
->
key
=
NULL
;
msg
->
key_len
=
0
;
/* TODO: reject it or not ? */
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
&&
!
stun_has_cookie
(
msg
))
{
stun_debug
(
"STUN demux error: no cookie!
\n
"
);
return
STUN_VALIDATION_BAD_REQUEST
;
}
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
&&
agent
->
usage_flags
&
STUN_AGENT_USAGE_USE_FINGERPRINT
)
{
/* Looks for FINGERPRINT */
if
(
stun_message_find32
(
msg
,
STUN_ATTRIBUTE_FINGERPRINT
,
&
fpr
)
!=
0
)
{
stun_debug
(
"STUN demux error: no FINGERPRINT attribute!
\n
"
);
return
STUN_VALIDATION_BAD_REQUEST
;
}
/* Checks FINGERPRINT */
crc32
=
stun_fingerprint
(
msg
->
buffer
,
stun_message_length
(
msg
)
-
8
);
if
(
fpr
!=
crc32
)
{
stun_debug
(
"STUN demux error: bad fingerprint: 0x%08x,"
" expected: 0x%08x!
\n
"
,
fpr
,
crc32
);
return
STUN_VALIDATION_BAD_REQUEST
;
}
stun_debug
(
"STUN demux: OK!
\n
"
);
}
if
(
stun_message_get_class
(
msg
)
==
STUN_RESPONSE
||
stun_message_get_class
(
msg
)
==
STUN_ERROR
)
{
stun_message_id
(
msg
,
msg_id
);
for
(
sent_id_idx
=
0
;
sent_id_idx
<
STUN_AGENT_MAX_SAVED_IDS
;
sent_id_idx
++
)
{
if
(
agent
->
sent_ids
[
sent_id_idx
].
valid
==
TRUE
&&
agent
->
sent_ids
[
sent_id_idx
].
method
==
stun_message_get_method
(
msg
)
&&
memcmp
(
msg_id
,
agent
->
sent_ids
[
sent_id_idx
].
id
,
sizeof
(
stun_transid_t
))
==
0
)
{
if
(
stun_message_get_class
(
msg
)
==
STUN_ERROR
&&
stun_message_find_error
(
msg
,
&
error_code
)
!=
0
)
{
stun_debug
(
"STUN demux error: STUN_ERROR with no ERROR_CODE"
);
return
STUN_VALIDATION_BAD_REQUEST
;
}
key
=
agent
->
sent_ids
[
sent_id_idx
].
key
;
key_len
=
agent
->
sent_ids
[
sent_id_idx
].
key_len
;
break
;
}
}
if
(
sent_id_idx
==
STUN_AGENT_MAX_SAVED_IDS
)
{
return
STUN_VALIDATION_UNMATCHED_RESPONSE
;
}
}
if
((
agent
->
usage_flags
&
STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS
&&
(
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_USERNAME
)
||
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_MESSAGE_INTEGRITY
)))
||
(
agent
->
usage_flags
&
STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS
&&
stun_message_get_class
(
msg
)
!=
STUN_INDICATION
&&
(
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_USERNAME
)
||
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_MESSAGE_INTEGRITY
)
||
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_NONCE
)
||
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_REALM
)))
||
((
agent
->
usage_flags
&
STUN_AGENT_USAGE_IGNORE_CREDENTIALS
)
==
0
&&
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_USERNAME
)
&&
!
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_MESSAGE_INTEGRITY
)))
{
return
STUN_VALIDATION_UNAUTHORIZED
;
}
if
((
agent
->
usage_flags
&
STUN_AGENT_USAGE_IGNORE_CREDENTIALS
)
==
0
&&
stun_message_has_attribute
(
msg
,
STUN_ATTRIBUTE_USERNAME
))
{
username
=
(
uint8_t
*
)
stun_message_find
(
msg
,
STUN_ATTRIBUTE_USERNAME
,
&
username_len
);
if
(
username
)
{
if
(
key
==
NULL
)
{
if
(
validater
(
agent
,
msg
,
username
,
username_len
,
&
key
,
&
key_len
,
validater_data
)
==
FALSE
)
{
return
STUN_VALIDATION_UNAUTHORIZED
;
}
}
}
}
if
(
key
!=
NULL
&&
key_len
>
0
)
{
hash
=
(
uint8_t
*
)
stun_message_find
(
msg
,
STUN_ATTRIBUTE_MESSAGE_INTEGRITY
,
&
hlen
);
stun_sha1
(
msg
->
buffer
,
stun_message_length
(
msg
),
sha
,
key
,
key_len
);
stun_debug
(
" Message HMAC-SHA1 fingerprint:"
);
stun_debug
(
"
\n
key : "
);
stun_debug_bytes
(
key
,
key_len
);
stun_debug
(
"
\n
expected: "
);
stun_debug_bytes
(
sha
,
sizeof
(
sha
));
stun_debug
(
"
\n
received: "
);
stun_debug_bytes
(
hash
,
sizeof
(
sha
));
stun_debug
(
"
\n
"
);
if
(
memcmp
(
sha
,
hash
,
sizeof
(
sha
)))
{
stun_debug
(
"STUN auth error: SHA1 fingerprint mismatch!
\n
"
);
return
STUN_VALIDATION_UNAUTHORIZED
;
}
stun_debug
(
"STUN auth: OK!
\n
"
);
}
if
(
sent_id_idx
!=
-
1
&&
sent_id_idx
<
STUN_AGENT_MAX_SAVED_IDS
)
{
agent
->
sent_ids
[
sent_id_idx
].
valid
=
FALSE
;
}
return
STUN_VALIDATION_SUCCESS
;
}
bool
stun_agent_init_request
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
)
{
bool
ret
;
stun_transid_t
id
;
msg
->
buffer
=
buffer
;
msg
->
buffer_len
=
buffer_len
;
msg
->
agent
=
agent
;
msg
->
key
=
NULL
;
msg
->
key_len
=
0
;
stun_make_transid
(
id
);
ret
=
stun_message_init
(
msg
,
STUN_REQUEST
,
m
,
id
);
if
(
ret
)
{
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
)
{
uint32_t
cookie
=
htonl
(
STUN_MAGIC_COOKIE
);
memcpy
(
msg
->
buffer
+
STUN_MESSAGE_TRANS_ID_POS
,
&
cookie
,
sizeof
(
cookie
));
}
}
return
ret
;
}
bool
stun_agent_init_indication
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
)
{
bool
ret
;
stun_transid_t
id
;
msg
->
buffer
=
buffer
;
msg
->
buffer_len
=
buffer_len
;
msg
->
agent
=
agent
;
msg
->
key
=
NULL
;
msg
->
key_len
=
0
;
stun_make_transid
(
id
);
ret
=
stun_message_init
(
msg
,
STUN_INDICATION
,
m
,
id
);
if
(
ret
)
{
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
)
{
uint32_t
cookie
=
htonl
(
STUN_MAGIC_COOKIE
);
memcpy
(
msg
->
buffer
+
STUN_MESSAGE_TRANS_ID_POS
,
&
cookie
,
sizeof
(
cookie
));
}
}
return
ret
;
}
bool
stun_agent_init_response
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
,
StunMessage
*
request
)
{
stun_transid_t
id
;
if
(
stun_message_get_class
(
request
)
!=
STUN_REQUEST
)
{
return
FALSE
;
}
msg
->
buffer
=
buffer
;
msg
->
buffer_len
=
buffer_len
;
msg
->
agent
=
agent
;
msg
->
key
=
NULL
;
msg
->
key_len
=
0
;
stun_message_id
(
request
,
id
);
if
(
stun_message_init
(
msg
,
STUN_RESPONSE
,
stun_message_get_method
(
request
),
id
))
{
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
&&
agent
->
usage_flags
&
STUN_AGENT_USAGE_ADD_SERVER
)
{
stun_message_append_server
(
msg
);
}
return
TRUE
;
}
return
FALSE
;
}
bool
stun_agent_init_error
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessage
*
request
,
stun_error_t
err
)
{
stun_transid_t
id
;
if
(
stun_message_get_class
(
request
)
!=
STUN_REQUEST
)
{
return
FALSE
;
}
msg
->
buffer
=
buffer
;
msg
->
buffer_len
=
buffer_len
;
msg
->
agent
=
agent
;
msg
->
key
=
NULL
;
msg
->
key_len
=
0
;
stun_message_id
(
request
,
id
);
if
(
stun_message_init
(
msg
,
STUN_ERROR
,
stun_message_get_method
(
request
),
id
))
{
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
&&
agent
->
usage_flags
&
STUN_AGENT_USAGE_ADD_SERVER
)
{
stun_message_append_server
(
msg
);
}
if
(
stun_message_append_error
(
msg
,
err
)
==
0
)
{
return
TRUE
;
}
}
return
FALSE
;
}
size_t
stun_agent_build_unknown_attributes_error
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessage
*
request
)
{
unsigned
counter
;
uint16_t
ids
[
STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES
];
counter
=
stun_agent_find_unknowns
(
agent
,
request
,
ids
,
STUN_AGENT_MAX_UNKNOWN_ATTRIBUTES
);
if
(
stun_agent_init_error
(
agent
,
msg
,
buffer
,
buffer_len
,
request
,
STUN_ERROR_UNKNOWN_ATTRIBUTE
)
==
FALSE
)
{
return
0
;
}
/* NOTE: Old RFC3489 compatibility:
* When counter is odd, duplicate one value for 32-bits padding. */
if
(
!
stun_has_cookie
(
request
)
&&
(
counter
&
1
))
ids
[
counter
++
]
=
ids
[
0
];
if
(
stun_message_append_bytes
(
msg
,
STUN_ATTRIBUTE_UNKNOWN_ATTRIBUTES
,
ids
,
counter
*
2
)
==
0
)
{
return
stun_agent_finish_message
(
agent
,
msg
,
request
->
key
,
request
->
key_len
);
}
return
0
;
}
size_t
stun_agent_finish_message
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
key
,
size_t
key_len
)
{
uint8_t
*
ptr
;
uint32_t
fpr
;
int
i
;
stun_transid_t
id
;
if
(
key
!=
NULL
)
{
ptr
=
stun_message_append
(
msg
,
STUN_ATTRIBUTE_MESSAGE_INTEGRITY
,
20
);
if
(
ptr
==
NULL
)
{
return
0
;
}
stun_sha1
(
msg
->
buffer
,
stun_message_length
(
msg
),
ptr
,
key
,
key_len
);
stun_debug
(
" Message HMAC-SHA1 fingerprint:"
"
\n
key : "
);
stun_debug_bytes
(
key
,
key_len
);
stun_debug
(
"
\n
sent : "
);
stun_debug_bytes
(
ptr
,
20
);
stun_debug
(
"
\n
"
);
}
if
(
agent
->
compatibility
==
STUN_COMPATIBILITY_3489BIS
&&
agent
->
usage_flags
&
STUN_AGENT_USAGE_USE_FINGERPRINT
)
{
ptr
=
stun_message_append
(
msg
,
STUN_ATTRIBUTE_FINGERPRINT
,
4
);
if
(
ptr
==
NULL
)
{
return
0
;
}
fpr
=
stun_fingerprint
(
msg
->
buffer
,
stun_message_length
(
msg
));
memcpy
(
ptr
,
&
fpr
,
sizeof
(
fpr
));
}
if
(
stun_message_get_class
(
msg
)
==
STUN_REQUEST
)
{
for
(
i
=
0
;
i
<
STUN_AGENT_MAX_SAVED_IDS
;
i
++
)
{
if
(
agent
->
sent_ids
[
i
].
valid
==
FALSE
)
{
stun_message_id
(
msg
,
id
);
memcpy
(
agent
->
sent_ids
[
i
].
id
,
id
,
sizeof
(
stun_transid_t
));
agent
->
sent_ids
[
i
].
method
=
stun_message_get_method
(
msg
);
agent
->
sent_ids
[
i
].
key
=
key
;
agent
->
sent_ids
[
i
].
key_len
=
key_len
;
agent
->
sent_ids
[
i
].
valid
=
TRUE
;
return
TRUE
;
}
}
}
msg
->
key
=
key
;
msg
->
key_len
=
key_len
;
return
stun_message_length
(
msg
);
}
static
bool
stun_agent_is_unknown
(
StunAgent
*
agent
,
uint16_t
type
)
{
uint16_t
*
known_attr
=
agent
->
known_attributes
;
while
(
*
known_attr
!=
0
)
{
if
(
*
known_attr
==
type
)
{
return
FALSE
;
}
known_attr
++
;
}
return
TRUE
;
}
static
unsigned
stun_agent_find_unknowns
(
StunAgent
*
agent
,
const
StunMessage
*
msg
,
uint16_t
*
list
,
unsigned
max
)
{
unsigned
count
=
0
;
uint16_t
len
=
stun_message_length
(
msg
);
size_t
offset
=
0
;
offset
=
STUN_MESSAGE_ATTRIBUTES_POS
;
while
((
offset
<
len
)
&&
(
count
<
max
))
{
size_t
alen
=
stun_getw
(
msg
->
buffer
+
offset
+
STUN_ATTRIBUTE_TYPE_LEN
);
uint16_t
atype
=
stun_getw
(
msg
->
buffer
+
offset
);
offset
+=
STUN_ATTRIBUTE_VALUE_POS
+
stun_align
(
alen
);
if
(
!
stun_optional
(
atype
)
&&
stun_agent_is_unknown
(
agent
,
atype
))
{
stun_debug
(
"STUN unknown: attribute 0x%04x(%u bytes)
\n
"
,
(
unsigned
)
atype
,
(
unsigned
)
alen
);
list
[
count
++
]
=
htons
(
atype
);
}
}
stun_debug
(
"STUN unknown: %u mandatory attribute(s)!
\n
"
,
count
);
return
count
;
}
stun/stunagent.h
0 → 100644
View file @
b9669017
/*
* This file is part of the Nice GLib ICE library.
*
* (C) 2008 Collabora Ltd.
* (C) 2008 Nokia Corporation. All rights reserved.
* Contact: Youness Alaoui
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Nice GLib ICE library.
*
* The Initial Developers of the Original Code are Collabora Ltd and Nokia
* Corporation. All Rights Reserved.
*
*
* Alternatively, the contents of this file may be used under the terms of the
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
* case the provisions of LGPL are applicable instead of those above. If you
* wish to allow use of your version of this file only under the terms of the
* LGPL and not to allow others to use your version of this file under the
* MPL, indicate your decision by deleting the provisions above and replace
* them with the notice and other provisions required by the LGPL. If you do
* not delete the provisions above, a recipient may use your version of this
* file under either the MPL or the LGPL.
*/
#ifndef _STUN_AGENT_H
#define _STUN_AGENT_H
#include <stdint.h>
#include <sys/types.h>
#include <stdbool.h>
typedef
struct
stun_agent_t
StunAgent
;
#include "stunmessage.h"
typedef
enum
{
STUN_COMPATIBILITY_RFC3489
,
STUN_COMPATIBILITY_3489BIS
,
STUN_COMPATIBILITY_LAST
=
STUN_COMPATIBILITY_3489BIS
}
StunCompatibility
;
typedef
enum
{
STUN_VALIDATION_SUCCESS
,
STUN_VALIDATION_NOT_STUN
,
STUN_VALIDATION_INCOMPLETE_STUN
,
STUN_VALIDATION_BAD_REQUEST
,
STUN_VALIDATION_UNAUTHORIZED
,
STUN_VALIDATION_UNMATCHED_RESPONSE
,
STUN_VALIDATION_UNKNOWN_ATTRIBUTE
,
STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE
}
StunValidationStatus
;
#define STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS 0x0001
#define STUN_AGENT_USAGE_LONG_TERM_CREDENTIALS 0x0002
#define STUN_AGENT_USAGE_USE_FINGERPRINT 0x0004
#define STUN_AGENT_USAGE_ADD_SERVER 0x0008
#define STUN_AGENT_USAGE_IGNORE_CREDENTIALS 0x000F
typedef
struct
{
stun_transid_t
id
;
stun_method_t
method
;
uint8_t
*
key
;
size_t
key_len
;
bool
valid
;
}
StunAgentSavedIds
;
struct
stun_agent_t
{
StunCompatibility
compatibility
;
StunAgentSavedIds
sent_ids
[
STUN_AGENT_MAX_SAVED_IDS
];
uint16_t
*
known_attributes
;
uint32_t
usage_flags
;
};
typedef
bool
(
*
StunMessageIntegrityValidate
)
(
StunAgent
*
agent
,
StunMessage
*
message
,
uint8_t
*
username
,
uint16_t
username_len
,
uint8_t
**
password
,
size_t
*
password_len
,
void
*
user_data
);
void
stun_agent_init
(
StunAgent
*
agent
,
const
uint16_t
*
known_attributes
,
StunCompatibility
compatibility
,
uint32_t
usage_flags
);
StunValidationStatus
stun_agent_validate
(
StunAgent
*
agent
,
StunMessage
*
msg
,
const
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessageIntegrityValidate
validater
,
void
*
validater_data
);
bool
stun_agent_init_request
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
);
bool
stun_agent_init_indication
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
);
bool
stun_agent_init_response
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
stun_method_t
m
,
StunMessage
*
request
);
bool
stun_agent_init_error
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessage
*
request
,
stun_error_t
err
);
size_t
stun_agent_build_unknown_attributes_error
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
buffer
,
size_t
buffer_len
,
StunMessage
*
request
);
size_t
stun_agent_finish_message
(
StunAgent
*
agent
,
StunMessage
*
msg
,
uint8_t
*
key
,
size_t
key_len
);
#endif
/* _STUN_AGENT_H */
stun/stuncrc32.c
View file @
b9669017
...
...
@@ -87,7 +87,7 @@
# include <config.h>
#endif
#include "crc32.h"
#include "
stun
crc32.h"
static
const
uint32_t
crc32_tab
[]
=
{
...
...
stun/stunhmac.c
View file @
b9669017
...
...
@@ -45,7 +45,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include "stun
-msg
.h"
#include "stun
message
.h"
#include "stunhmac.h"
#include <string.h>
...
...
stun/stunhmac.h
View file @
b9669017
...
...
@@ -35,6 +35,8 @@
#ifndef _STUN_HMAC_H
#define _STUN_HMAC_H
#include "stunmessage.h"
/**
* Computes the MESSAGE-INTEGRITY hash of a STUN message.
* @param msg pointer to the STUN message
...
...
@@ -61,4 +63,4 @@ void stun_hash_creds (const char *realm, const char *login, const char *pw,
void
stun_make_transid
(
stun_transid_t
id
);
/* _STUN_HMAC_H */
#endif
/* _STUN_HMAC_H */
stun/stunmessage.c
View file @
b9669017
...
...
@@ -61,12 +61,8 @@ bool stun_message_init (StunMessage *msg, stun_class_t c, stun_method_t m,
memset
(
msg
->
buffer
,
0
,
4
);
stun_set_type
(
msg
->
buffer
,
c
,
m
);
if
(
msg
->
buffer
!=
id
)
{
uint32_t
cookie
=
htonl
(
STUN_COOKIE
);
memcpy
(
msg
->
buffer
+
4
,
&
cookie
,
sizeof
(
cookie
));
memcpy
(
msg
->
buffer
+
8
,
id
,
12
);
}
memcpy
(
msg
->
buffer
+
STUN_MESSAGE_TRANS_ID_POS
,
id
,
sizeof
(
STUN_MESSAGE_TRANS_ID_LEN
));
return
TRUE
;
}
...
...
@@ -107,12 +103,12 @@ stun_message_find (const StunMessage *msg, stun_attr_type_t type,
/* Look for and ignore misordered attributes */
switch
(
atype
)
{
case
STUN_MESSAGE_INTEGRITY
:
case
STUN_
ATTRIBUTE_
MESSAGE_INTEGRITY
:
/* Only fingerprint may come after M-I */
if
(
type
==
STUN_FINGERPRINT
)
if
(
type
==
STUN_
ATTRIBUTE_
FINGERPRINT
)
break
;
case
STUN_FINGERPRINT
:
case
STUN_
ATTRIBUTE_
FINGERPRINT
:
/* Nothing may come after FPR */
return
NULL
;
}
...
...
@@ -273,10 +269,10 @@ stun_message_find_xor_addr (const StunMessage *msg, stun_attr_type_t type,
return
stun_xor_address
(
msg
,
addr
,
*
addrlen
);
}
int
stun_message_find_err
no
(
const
StunMessage
*
msg
,
int
*
restrict
code
)
int
stun_message_find_err
or
(
const
StunMessage
*
msg
,
int
*
restrict
code
)
{
uint16_t
alen
;
const
uint8_t
*
ptr
=
stun_message_find
(
msg
,
STUN_ERROR_CODE
,
&
alen
);
const
uint8_t
*
ptr
=
stun_message_find
(
msg
,
STUN_
ATTRIBUTE_
ERROR_CODE
,
&
alen
);
uint8_t
class
,
number
;
if
(
ptr
==
NULL
)
...
...
@@ -319,7 +315,7 @@ stun_message_append (StunMessage *msg, stun_attr_type_t type, size_t length)
a
=
stun_setw
(
a
,
type
);
/* NOTE: If cookie is not present, we need to force the attribute length
* to a multiple of 4 for compatibility with old RFC3489 */
a
=
stun_setw
(
a
,
stun_has_cookie
(
msg
->
buffer
)
?
length
:
stun_align
(
length
));
a
=
stun_setw
(
a
,
stun_has_cookie
(
msg
)
?
length
:
stun_align
(
length
));
mlen
+=
4
+
length
;
/* Add padding if needed */
...
...
@@ -473,7 +469,7 @@ stun_message_append_error (StunMessage *msg, stun_error_t code)
size_t
len
=
strlen
(
str
);
div_t
d
=
div
(
code
,
100
);
uint8_t
*
ptr
=
stun_message_append
(
msg
,
STUN_ERROR_CODE
,
4
+
len
);
uint8_t
*
ptr
=
stun_message_append
(
msg
,
STUN_
ATTRIBUTE_
ERROR_CODE
,
4
+
len
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
...
...
@@ -484,7 +480,7 @@ stun_message_append_error (StunMessage *msg, stun_error_t code)
return
0
;
}
bool
stun_message_is_valid
(
const
uint8_t
*
msg
,
size_t
length
)
int
stun_message_validate_buffer_length
(
const
uint8_t
*
msg
,
size_t
length
)
{
size_t
mlen
;
size_t
len
;
...
...
@@ -492,19 +488,19 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
if
(
length
<
1
)
{
stun_debug
(
"STUN error: No data!
\n
"
);
return
FALSE
;
return
STUN_MESSAGE_BUFFER_INVALID
;
}
if
(
msg
[
0
]
>>
6
)
{
stun_debug
(
"STUN error: RTP or other non-protocol packet!
\n
"
);
return
FALSE
;
// RTP or other non-STUN packet
return
STUN_MESSAGE_BUFFER_INVALID
;
// RTP or other non-STUN packet
}
if
(
length
<
4
)
{
stun_debug
(
"STUN error: Incomplete STUN message header!
\n
"
);
return
FALS
E
;
return
STUN_MESSAGE_BUFFER_INCOMPLET
E
;
}
mlen
=
stun_getw
(
msg
+
STUN_MESSAGE_LENGTH_POS
)
+
...
...
@@ -513,14 +509,14 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
if
(
stun_padding
(
mlen
))
{
stun_debug
(
"STUN error: Invalid message length: %u!
\n
"
,
(
unsigned
)
mlen
);
return
FALSE
;
// wrong padding
return
STUN_MESSAGE_BUFFER_INVALID
;
// wrong padding
}
if
(
length
<
mlen
)
{
stun_debug
(
"STUN error: Incomplete message: %u of %u bytes!
\n
"
,
(
unsigned
)
length
,
(
unsigned
)
mlen
);
return
FALS
E
;
// partial message
return
STUN_MESSAGE_BUFFER_INCOMPLET
E
;
// partial message
}
msg
+=
20
;
...
...
@@ -539,12 +535,54 @@ bool stun_message_is_valid (const uint8_t *msg, size_t length)
{
stun_debug
(
"STUN error: %u instead of %u bytes for attribute!
\n
"
,
(
unsigned
)
len
,
(
unsigned
)
alen
);
return
-
1
;
// no room for attribute value + padding
return
STUN_MESSAGE_BUFFER_INVALID
;
// no room for attribute value + padding
}
len
-=
alen
;
msg
+=
4
+
alen
;
}
return
mlen
==
length
;
return
mlen
;
}
/**
* copies STUN message transaction ID
*/
void
stun_message_id
(
const
StunMessage
*
msg
,
stun_transid_t
id
)
{
memcpy
(
id
,
msg
->
buffer
+
STUN_MESSAGE_TRANS_ID_POS
,
STUN_MESSAGE_TRANS_ID_LEN
);
}
/**
* @return STUN message method (value from 0 to 0xfff)
*/
stun_method_t
stun_message_get_method
(
const
StunMessage
*
msg
)
{
uint16_t
t
=
stun_getw
(
msg
->
buffer
);
return
(
stun_method_t
)(((
t
&
0x3e00
)
>>
2
)
|
((
t
&
0x00e0
)
>>
1
)
|
(
t
&
0x000f
));
}
/**
* @return STUN message class in host byte order (value from 0 to 3)
*/
stun_class_t
stun_message_get_class
(
const
StunMessage
*
msg
)
{
uint16_t
t
=
stun_getw
(
msg
->
buffer
);
return
(
stun_class_t
)(((
t
&
0x0100
)
>>
7
)
|
((
t
&
0x0010
)
>>
4
));
}
/**
* Checks if an attribute is present within a STUN message.
*
* @param msg valid STUN message
* @param type STUN attribute type (host byte order)
*
* @return whether there is a MESSAGE-INTEGRITY attribute
*/
bool
stun_message_has_attribute
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
)
{
uint16_t
dummy
;
return
stun_message_find
(
msg
,
type
,
&
dummy
)
!=
NULL
;
}
stun/stunmessage.h
View file @
b9669017
...
...
@@ -41,12 +41,7 @@
#include <stdbool.h>
#include "constants.h"
typedef
struct
{
uint8_t
*
buffer
;
size_t
buffer_len
;
bool
message_id_validated
;
}
StunMessage
;
typedef
struct
stun_message_t
StunMessage
;
/* Message classes */
typedef
enum
...
...
@@ -78,65 +73,65 @@ typedef enum
{
/* Mandatory attributes */
/* 0x0000 */
/* reserved */
STUN_MAPPED_ADDRESS
=
0x0001
,
/* RFC3489bis-11 */
STUN_OLD_RESPONSE_ADDRESS
=
0x0002
,
/* old RFC3489 */
STUN_OLD_CHANGE_REQUEST
=
0x0003
,
/* old RFC3489 */
STUN_OLD_SOURCE_ADDRESS
=
0x0004
,
/* old RFC3489 */
STUN_OLD_CHANGED_ADDRESS
=
0x0005
,
/* old RFC3489 */
STUN_USERNAME
=
0x0006
,
/* RFC3489bis-11 */
STUN_OLD_PASSWORD
=
0x0007
,
/* old RFC3489 */
STUN_MESSAGE_INTEGRITY
=
0x0008
,
/* RFC3489bis-11 */
STUN_ERROR_CODE
=
0x0009
,
/* RFC3489bis-11 */
STUN_UNKNOWN_ATTRIBUTES
=
0x000A
,
/* RFC3489bis-11 */
STUN_OLD_REFLECTED_FROM
=
0x000B
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
MAPPED_ADDRESS
=
0x0001
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
OLD_RESPONSE_ADDRESS
=
0x0002
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
OLD_CHANGE_REQUEST
=
0x0003
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
OLD_SOURCE_ADDRESS
=
0x0004
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
OLD_CHANGED_ADDRESS
=
0x0005
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
USERNAME
=
0x0006
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
OLD_PASSWORD
=
0x0007
,
/* old RFC3489 */
STUN_
ATTRIBUTE_
MESSAGE_INTEGRITY
=
0x0008
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
ERROR_CODE
=
0x0009
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
UNKNOWN_ATTRIBUTES
=
0x000A
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
OLD_REFLECTED_FROM
=
0x000B
,
/* old RFC3489 */
/* 0x000C */
/* reserved */
STUN_LIFETIME
=
0x000D
,
/* TURN-04 */
STUN_
ATTRIBUTE_
LIFETIME
=
0x000D
,
/* TURN-04 */
/* 0x000E */
/* reserved */
/* 0x000F */
/* reserved */
STUN_BANDWIDTH
=
0x0010
,
/* TURN-04 */
STUN_
ATTRIBUTE_
BANDWIDTH
=
0x0010
,
/* TURN-04 */
/* 0x0011 */
/* reserved */
STUN_REMOTE_ADDRESS
=
0x0012
,
/* TURN-04 */
STUN_DATA
=
0x0013
,
/* TURN-04 */
STUN_REALM
=
0x0014
,
/* RFC3489bis-11 */
STUN_NONCE
=
0x0015
,
/* RFC3489bis-11 */
STUN_RELAY_ADDRESS
=
0x0016
,
/* TURN-04 */
STUN_REQUESTED_ADDRESS_TYPE
=
0x0017
,
/* TURN-IPv6-03 */
STUN_REQUESTED_PORT_PROPS
=
0x0018
,
/* TURN-04 */
STUN_REQUESTED_TRANSPORT
=
0x0019
,
/* TURN-04 */
STUN_
ATTRIBUTE_
REMOTE_ADDRESS
=
0x0012
,
/* TURN-04 */
STUN_
ATTRIBUTE_
DATA
=
0x0013
,
/* TURN-04 */
STUN_
ATTRIBUTE_
REALM
=
0x0014
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
NONCE
=
0x0015
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
RELAY_ADDRESS
=
0x0016
,
/* TURN-04 */
STUN_
ATTRIBUTE_
REQUESTED_ADDRESS_TYPE
=
0x0017
,
/* TURN-IPv6-03 */
STUN_
ATTRIBUTE_
REQUESTED_PORT_PROPS
=
0x0018
,
/* TURN-04 */
STUN_
ATTRIBUTE_
REQUESTED_TRANSPORT
=
0x0019
,
/* TURN-04 */
/* 0x001A */
/* reserved */
/* 0x001B */
/* reserved */
/* 0x001C */
/* reserved */
/* 0x001D */
/* reserved */
/* 0x001E */
/* reserved */
/* 0x001F */
/* reserved */
STUN_XOR_MAPPED_ADDRESS
=
0x0020
,
/* RFC3489bis-11 */
STUN_TIMER_VAL
=
0x0021
,
/* TURN-04 */
STUN_REQUESTED_IP
=
0x0022
,
/* TURN-04 */
STUN_CONNECT_STAT
=
0x0023
,
/* TURN-04 */
STUN_PRIORITY
=
0x0024
,
/* ICE-18 */
STUN_USE_CANDIDATE
=
0x0025
,
/* ICE-18 */
STUN_
ATTRIBUTE_
XOR_MAPPED_ADDRESS
=
0x0020
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
TIMER_VAL
=
0x0021
,
/* TURN-04 */
STUN_
ATTRIBUTE_
REQUESTED_IP
=
0x0022
,
/* TURN-04 */
STUN_
ATTRIBUTE_
CONNECT_STAT
=
0x0023
,
/* TURN-04 */
STUN_
ATTRIBUTE_
PRIORITY
=
0x0024
,
/* ICE-18 */
STUN_
ATTRIBUTE_
USE_CANDIDATE
=
0x0025
,
/* ICE-18 */
/* 0x0026 */
/* reserved */
/* 0x0027 */
/* reserved */
/* 0x0028 */
/* reserved */
STUN_XOR_INTERNAL_ADDRESS
=
0x0029
,
/* wing-nat-control-04 */
STUN_
ATTRIBUTE_
XOR_INTERNAL_ADDRESS
=
0x0029
,
/* wing-nat-control-04 */
/* 0x002A-0x7fff */
/* reserved */
/* Optional attributes */
/* 0x8000-0x8021 */
/* reserved */
STUN_SERVER
=
0x8022
,
/* RFC3489bis-11 */
STUN_ALTERNATE_SERVER
=
0x8023
,
/* RFC3489bis-11 */
STUN_REFRESH_INTERVAL
=
0x8024
,
/* wing-nat-control-04 */
STUN_
ATTRIBUTE_
SERVER
=
0x8022
,
/* RFC3489bis-11 */
STUN_A
TTRIBUTE_A
LTERNATE_SERVER
=
0x8023
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
REFRESH_INTERVAL
=
0x8024
,
/* wing-nat-control-04 */
/* 0x8025 */
/* reserved */
/* 0x8026 */
/* reserved */
/* 0x8027 */
/* reserved */
STUN_FINGERPRINT
=
0x8028
,
/* RFC3489bis-11 */
STUN_ICE_CONTROLLED
=
0x8029
,
/* ICE-18 */
STUN_ICE_CONTROLLING
=
0x802A
,
/* ICE-18 */
STUN_
ATTRIBUTE_
FINGERPRINT
=
0x8028
,
/* RFC3489bis-11 */
STUN_
ATTRIBUTE_
ICE_CONTROLLED
=
0x8029
,
/* ICE-18 */
STUN_
ATTRIBUTE_
ICE_CONTROLLING
=
0x802A
,
/* ICE-18 */
/* 0x802B-0xFFFF */
/* reserved */
}
stun_attr_type_t
;
typedef
uint8_t
stun_transid_t
[
12
];
typedef
uint8_t
stun_transid_t
[
STUN_MESSAGE_TRANS_ID_LEN
];
/**
...
...
@@ -145,32 +140,41 @@ typedef uint8_t stun_transid_t[12];
*/
typedef
enum
{
STUN_TRY_ALTERNATE
=
300
,
/* RFC3489bis-11 */
STUN_BAD_REQUEST
=
400
,
/* RFC3489bis-11 */
STUN_UNAUTHORIZED
=
401
,
/* RFC3489bis-11 */
STUN_UNKNOWN_ATTRIBUTE
=
420
,
/* RFC3489bis-11 */
STUN_NO_BINDING
=
437
,
/* TURN-04 */
STUN_STALE_NONCE
=
438
,
/* RFC3489bis-11 */
STUN_ACT_DST_ALREADY
=
439
,
/* TURN-04 */
STUN_UNSUPP_FAMILY
=
440
,
/* TURN-IPv6-03 */
STUN_UNSUPP_TRANSPORT
=
442
,
/* TURN-04 */
STUN_INVALID_IP
=
443
,
/* TURN-04 */
STUN_INVALID_PORT
=
444
,
/* TURN-04 */
STUN_OP_TCP_ONLY
=
445
,
/* TURN-04 */
STUN_CONN_ALREADY
=
446
,
/* TURN-04 */
STUN_ALLOC_OVER_QUOTA
=
486
,
/* TURN-04 */
STUN_ROLE_CONFLICT
=
487
,
/* ICE-18 */
STUN_SERVER_ERROR
=
500
,
/* RFC3489bis-11 */
STUN_SERVER_CAPACITY
=
507
,
/* TURN-04 */
STUN_
ERROR_
TRY_ALTERNATE
=
300
,
/* RFC3489bis-11 */
STUN_
ERROR_
BAD_REQUEST
=
400
,
/* RFC3489bis-11 */
STUN_
ERROR_
UNAUTHORIZED
=
401
,
/* RFC3489bis-11 */
STUN_
ERROR_
UNKNOWN_ATTRIBUTE
=
420
,
/* RFC3489bis-11 */
STUN_
ERROR_
NO_BINDING
=
437
,
/* TURN-04 */
STUN_
ERROR_
STALE_NONCE
=
438
,
/* RFC3489bis-11 */
STUN_
ERROR_
ACT_DST_ALREADY
=
439
,
/* TURN-04 */
STUN_
ERROR_
UNSUPP_FAMILY
=
440
,
/* TURN-IPv6-03 */
STUN_
ERROR_
UNSUPP_TRANSPORT
=
442
,
/* TURN-04 */
STUN_
ERROR_
INVALID_IP
=
443
,
/* TURN-04 */
STUN_
ERROR_
INVALID_PORT
=
444
,
/* TURN-04 */
STUN_
ERROR_
OP_TCP_ONLY
=
445
,
/* TURN-04 */
STUN_
ERROR_
CONN_ALREADY
=
446
,
/* TURN-04 */
STUN_
ERROR_
ALLOC_OVER_QUOTA
=
486
,
/* TURN-04 */
STUN_
ERROR_
ROLE_CONFLICT
=
487
,
/* ICE-18 */
STUN_
ERROR_
SERVER_ERROR
=
500
,
/* RFC3489bis-11 */
STUN_
ERROR_
SERVER_CAPACITY
=
507
,
/* TURN-04 */
STUN_ERROR_MAX
=
699
}
stun_error_t
;
#include "stunagent.h"
#include "stunhmac.h"
#include "stuncrc32.h"
#include "utils.h"
#include "stun3489bis.h"
struct
stun_message_t
{
StunAgent
*
agent
;
uint8_t
*
buffer
;
size_t
buffer_len
;
uint8_t
*
key
;
size_t
key_len
;
};
/**
* Initializes a STUN message buffer, with no attributes.
* @param c STUN message class (host byte order)
...
...
@@ -281,7 +285,7 @@ int stun_message_find_xor_addr (const StunMessage *msg, stun_attr_type_t type,
struct
sockaddr
*
restrict
addr
,
socklen_t
*
restrict
addrlen
);
int
stun_message_find_err
no
(
const
StunMessage
*
msg
,
int
*
restrict
code
);
int
stun_message_find_err
or
(
const
StunMessage
*
msg
,
int
*
restrict
code
);
void
*
stun_message_append
(
StunMessage
*
msg
,
stun_attr_type_t
type
,
size_t
length
);
...
...
@@ -368,7 +372,16 @@ int stun_message_append_xor_addr (StunMessage * msg, stun_attr_type_t type,
*/
int
stun_message_append_error
(
StunMessage
*
msg
,
stun_error_t
code
);
bool
stun_message_is_valid
(
const
uint8_t
*
msg
,
size_t
length
);
#define STUN_MESSAGE_BUFFER_INCOMPLETE 0
#define STUN_MESSAGE_BUFFER_INVALID -1
int
stun_message_validate_buffer_length
(
const
uint8_t
*
msg
,
size_t
length
);
void
stun_message_id
(
const
StunMessage
*
msg
,
stun_transid_t
id
);
stun_class_t
stun_message_get_class
(
const
StunMessage
*
msg
);
stun_method_t
stun_message_get_method
(
const
StunMessage
*
msg
);
bool
stun_message_has_attribute
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
);
#endif
/* _STUN_MESSAGE_H */
stun/stunrecv.c
View file @
b9669017
...
...
@@ -48,446 +48,6 @@
#include <errno.h>
#include <netinet/in.h>
ssize_t
stun_validate
(
const
uint8_t
*
msg
,
size_t
len
)
{
size_t
mlen
;
if
(
len
<
1
)
{
DBG
(
"STUN error: No data!
\n
"
);
return
0
;
}
if
(
msg
[
0
]
>>
6
)
{
DBG
(
"STUN error: RTP or other non-protocol packet!
\n
"
);
return
-
1
;
// RTP or other non-STUN packet
}
if
(
len
<
4
)
{
DBG
(
"STUN error: Incomplete STUN message header!
\n
"
);
return
0
;
}
mlen
=
20u
+
stun_length
(
msg
);
if
(
stun_padding
(
mlen
))
{
DBG
(
"STUN error: Invalid message length: %u!
\n
"
,
(
unsigned
)
mlen
);
return
-
1
;
// wrong padding
}
if
(
len
<
mlen
)
{
DBG
(
"STUN error: Incomplete message: %u of %u bytes!
\n
"
,
(
unsigned
)
len
,
(
unsigned
)
mlen
);
return
0
;
// partial message
}
msg
+=
20
;
len
=
mlen
-
20
;
/* from then on, we know we have the entire packet in buffer */
while
(
len
>
0
)
{
size_t
alen
=
stun_align
(
stun_length
(
msg
));
/* thanks to padding check, if (end > msg) then there is not only one
* but at least 4 bytes left */
assert
(
len
>=
4
);
len
-=
4
;
if
(
len
<
alen
)
{
DBG
(
"STUN error: %u instead of %u bytes for attribute!
\n
"
,
(
unsigned
)
len
,
(
unsigned
)
alen
);
return
-
1
;
// no room for attribute value + padding
}
len
-=
alen
;
msg
+=
4
+
alen
;
}
return
mlen
;
}
const
void
*
stun_find
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
uint16_t
*
restrict
palen
)
{
size_t
length
=
stun_length
(
msg
);
assert
(
stun_valid
(
msg
));
assert
(
palen
!=
NULL
);
msg
+=
20
;
while
(
length
>
0
)
{
size_t
alen
=
stun_length
(
msg
);
uint16_t
atype
=
stun_getw
(
msg
);
assert
(
length
>=
4
);
length
-=
4
;
msg
+=
4
;
assert
(
length
>=
stun_align
(
alen
));
if
(
atype
==
type
)
{
assert
(
alen
<=
0xffff
);
*
palen
=
alen
;
return
msg
;
}
/* Look for and ignore misordered attributes */
switch
(
atype
)
{
case
STUN_MESSAGE_INTEGRITY
:
/* Only fingerprint may come after M-I */
if
(
type
==
STUN_FINGERPRINT
)
break
;
case
STUN_FINGERPRINT
:
/* Nothing may come after FPR */
return
NULL
;
}
alen
=
stun_align
(
alen
);
length
-=
alen
;
msg
+=
alen
;
}
return
NULL
;
}
int
stun_find_flag
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
)
{
const
void
*
ptr
;
uint16_t
len
;
ptr
=
stun_find
(
msg
,
type
,
&
len
);
if
(
ptr
==
NULL
)
return
ENOENT
;
return
(
len
==
0
)
?
0
:
EINVAL
;
}
int
stun_find32
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
uint32_t
*
restrict
pval
)
{
const
void
*
ptr
;
uint16_t
len
;
ptr
=
stun_find
(
msg
,
type
,
&
len
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
(
len
==
4
)
{
uint32_t
val
;
memcpy
(
&
val
,
ptr
,
sizeof
(
val
));
*
pval
=
ntohl
(
val
);
return
0
;
}
return
EINVAL
;
}
int
stun_find64
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
,
uint64_t
*
pval
)
{
const
void
*
ptr
;
uint16_t
len
;
ptr
=
stun_find
(
msg
,
type
,
&
len
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
(
len
==
8
)
{
uint32_t
tab
[
2
];
memcpy
(
tab
,
ptr
,
sizeof
(
tab
));
*
pval
=
((
uint64_t
)
ntohl
(
tab
[
0
])
<<
32
)
|
ntohl
(
tab
[
1
]);
return
0
;
}
return
EINVAL
;
}
int
stun_find_string
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
char
*
buf
,
size_t
buflen
)
{
const
unsigned
char
*
ptr
;
uint16_t
len
;
ptr
=
stun_find
(
msg
,
type
,
&
len
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
(
len
>=
buflen
)
return
ENOBUFS
;
memcpy
(
buf
,
ptr
,
len
);
buf
[
len
]
=
'\0'
;
return
0
;
}
int
stun_find_addr
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
struct
sockaddr
*
restrict
addr
,
socklen_t
*
restrict
addrlen
)
{
const
uint8_t
*
ptr
;
uint16_t
len
;
ptr
=
stun_find
(
msg
,
type
,
&
len
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
(
len
<
4
)
return
EINVAL
;
assert
(
addrlen
!=
NULL
);
switch
(
ptr
[
1
])
{
case
1
:
{
struct
sockaddr_in
*
ip4
=
(
struct
sockaddr_in
*
)
addr
;
if
((
*
addrlen
<
sizeof
(
*
ip4
))
||
(
len
!=
8
))
{
*
addrlen
=
sizeof
(
*
ip4
);
return
EINVAL
;
}
memset
(
ip4
,
0
,
*
addrlen
);
ip4
->
sin_family
=
AF_INET
;
#ifdef HAVE_SA_LEN
ip4
->
sin_len
=
#endif
*
addrlen
=
sizeof
(
*
ip4
);
memcpy
(
&
ip4
->
sin_port
,
ptr
+
2
,
2
);
memcpy
(
&
ip4
->
sin_addr
,
ptr
+
4
,
4
);
return
0
;
}
case
2
:
{
struct
sockaddr_in6
*
ip6
=
(
struct
sockaddr_in6
*
)
addr
;
if
((
*
addrlen
<
sizeof
(
*
ip6
))
||
(
len
!=
20
))
{
*
addrlen
=
sizeof
(
*
ip6
);
return
EINVAL
;
}
memset
(
ip6
,
0
,
*
addrlen
);
ip6
->
sin6_family
=
AF_INET6
;
#ifdef HAVE_SA_LEN
ip6
->
sin6_len
=
#endif
*
addrlen
=
sizeof
(
*
ip6
);
memcpy
(
&
ip6
->
sin6_port
,
ptr
+
2
,
2
);
memcpy
(
&
ip6
->
sin6_addr
,
ptr
+
4
,
16
);
return
0
;
}
}
return
EAFNOSUPPORT
;
}
int
stun_xor_address
(
const
uint8_t
*
restrict
msg
,
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
)
{
switch
(
addr
->
sa_family
)
{
case
AF_INET
:
{
struct
sockaddr_in
*
ip4
=
(
struct
sockaddr_in
*
)
addr
;
if
(
addrlen
<
sizeof
(
*
ip4
))
return
EINVAL
;
ip4
->
sin_port
^=
htons
(
STUN_COOKIE
>>
16
);
ip4
->
sin_addr
.
s_addr
^=
htonl
(
STUN_COOKIE
);
return
0
;
}
case
AF_INET6
:
{
struct
sockaddr_in6
*
ip6
=
(
struct
sockaddr_in6
*
)
addr
;
unsigned
short
i
;
if
(
addrlen
<
sizeof
(
*
ip6
))
return
EINVAL
;
ip6
->
sin6_port
^=
htons
(
STUN_COOKIE
>>
16
);
for
(
i
=
0
;
i
<
16
;
i
++
)
ip6
->
sin6_addr
.
s6_addr
[
i
]
^=
((
uint8_t
*
)
msg
)[
4
+
i
];
return
0
;
}
}
return
EAFNOSUPPORT
;
}
int
stun_find_xor_addr
(
const
uint8_t
*
restrict
msg
,
stun_attr_type_t
type
,
struct
sockaddr
*
restrict
addr
,
socklen_t
*
restrict
addrlen
)
{
int
val
=
stun_find_addr
(
msg
,
type
,
addr
,
addrlen
);
if
(
val
)
return
val
;
return
stun_xor_address
(
msg
,
addr
,
*
addrlen
);
}
/**
* Compares the length and content of an attribute.
*
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param data pointer to value to compare with
* @param len byte length of the value
* @return 0 in case of match, ENOENT if attribute was not found,
* EINVAL if it did not match (different length, or same length but
* different content)
*/
int
stun_memcmp
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
,
const
void
*
data
,
size_t
len
)
{
uint16_t
alen
;
const
void
*
ptr
=
stun_find
(
msg
,
type
,
&
alen
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
((
len
!=
alen
)
||
memcmp
(
ptr
,
data
,
len
))
return
EINVAL
;
return
0
;
}
/**
* Compares the content of an attribute with a string.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param str string to compare with
* @return 0 in case of match, ENOENT if attribute was not found,
* EINVAL if it did not match
*/
int
stun_strcmp
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
,
const
char
*
str
)
{
return
stun_memcmp
(
msg
,
type
,
str
,
strlen
(
str
));
}
bool
stun_has_cookie
(
const
uint8_t
*
msg
)
{
uint32_t
cookie
=
htonl
(
STUN_COOKIE
);
return
memcmp
(
msg
+
4
,
&
cookie
,
sizeof
(
cookie
))
==
0
;
}
bool
stun_demux
(
const
uint8_t
*
msg
)
{
const
uint8_t
*
fpr
;
uint32_t
crc32
;
uint16_t
fprlen
;
assert
(
stun_valid
(
msg
));
/* Checks cookie */
if
(
!
stun_has_cookie
(
msg
))
{
DBG
(
"STUN demux error: no cookie!
\n
"
);
return
0
;
}
/* Looks for FINGERPRINT */
fpr
=
stun_find
(
msg
,
STUN_FINGERPRINT
,
&
fprlen
);
if
((
fpr
==
NULL
)
||
(
fprlen
!=
4
))
{
DBG
(
"STUN demux error: no FINGERPRINT attribute!
\n
"
);
return
0
;
}
/* Checks FINGERPRINT */
crc32
=
htonl
(
stun_fingerprint
(
msg
,
fpr
+
4
-
msg
));
if
(
memcmp
(
fpr
,
&
crc32
,
4
))
{
DBG
(
"STUN demux error: bad fingerprint: 0x%08x, expected: 0x%08x!
\n
"
,
(
fpr
[
0
]
<<
24
)
|
(
fpr
[
1
]
<<
16
)
|
(
fpr
[
2
]
<<
8
)
|
fpr
[
3
],
stun_fingerprint
(
msg
,
fpr
+
4
-
msg
));
return
0
;
}
DBG
(
"STUN demux: OK!
\n
"
);
return
1
;
}
/**
* @param msg valid STUN message
* @param key HMAC shared secret key pointer
* @param keylen HMAC shared secret key byte length
* @return 0 if the message integrity has been successfully verified with the
* specified key. EPERM if the hash was incorrect. ENOENT if there was no
* valid MESSAGE-INTEGRITY attribute.
*/
int
stun_verify_key
(
const
uint8_t
*
msg
,
const
void
*
key
,
size_t
keylen
)
{
const
uint8_t
*
hash
;
uint8_t
sha
[
20
];
uint16_t
hlen
;
assert
(
msg
!=
NULL
);
assert
((
keylen
==
0
)
||
(
key
!=
NULL
));
hash
=
stun_find
(
msg
,
STUN_MESSAGE_INTEGRITY
,
&
hlen
);
if
((
hash
==
NULL
)
||
(
hlen
!=
20
))
{
DBG
(
"STUN auth error: no MESSAGE-INTEGRITY attribute!
\n
"
);
return
ENOENT
;
}
stun_sha1
(
msg
,
hash
+
20
-
msg
,
sha
,
key
,
keylen
);
DBG
(
" Message HMAC-SHA1 fingerprint:"
"
\n
key : "
);
DBG_bytes
(
key
,
keylen
);
DBG
(
"
\n
expected: "
);
DBG_bytes
(
sha
,
sizeof
(
sha
));
DBG
(
"
\n
received: "
);
DBG_bytes
(
hash
,
sizeof
(
sha
));
DBG
(
"
\n
"
);
if
(
memcmp
(
sha
,
hash
,
sizeof
(
sha
)))
{
DBG
(
"STUN auth error: SHA1 fingerprint mismatch!
\n
"
);
return
EPERM
;
}
DBG
(
"STUN auth: OK!
\n
"
);
return
0
;
}
/**
* @param msg valid STUN message
* @param pw nul-terminated HMAC shared secret password
* @return 0 if the message integrity has been successfully verified with the
* specified key. EPERM if the hash was incorrect. ENOENT if there was no
* valid MESSAGE-INTEGRITY attribute.
*/
int
stun_verify_password
(
const
uint8_t
*
msg
,
const
char
*
pw
)
{
return
stun_verify_key
(
msg
,
pw
,
strlen
(
pw
));
}
/**
* @param msg valid STUN message
...
...
@@ -529,130 +89,3 @@ int stun_verify_username (const uint8_t *msg, const char *local_ufrag, uint32_t
return
0
;
}
static
int
stun_find_errno
(
const
uint8_t
*
restrict
msg
,
int
*
restrict
code
)
{
uint16_t
alen
;
const
uint8_t
*
ptr
=
stun_find
(
msg
,
STUN_ERROR_CODE
,
&
alen
);
uint8_t
class
,
number
;
if
(
ptr
==
NULL
)
return
ENOENT
;
if
(
alen
<
4
)
return
EINVAL
;
class
=
ptr
[
2
]
&
0x7
;
number
=
ptr
[
3
];
if
((
class
<
3
)
||
(
class
>
6
)
||
(
number
>
99
))
return
EINVAL
;
*
code
=
(
class
*
100
)
+
number
;
return
0
;
}
/**
* @param msg valid STUN message
* @param method STUN method number (host byte order)
* @param id STUN transaction id
* @param key HMAC key, or NULL if there is no authentication
* @param keylen HMAC key byte length, must be 0 if @a key is NULL
* @param error [OUT] set to -1 if the response is not an error,
* to the error code ([0..799]) if it is an error response.
*
* @return true if and only if the message is a response or an error response
* with the STUN cookie and specified method and transaction identifier.
*/
static
bool
stun_match_answer
(
const
uint8_t
*
msg
,
stun_method_t
method
,
const
uint8_t
*
id
,
const
uint8_t
*
key
,
size_t
keylen
,
int
*
restrict
error
)
{
assert
(
stun_valid
(
msg
));
assert
(
error
!=
NULL
);
if
((
stun_get_method
(
msg
)
!=
method
)
/* wrong request type */
||
!
stun_has_cookie
(
msg
)
/* response to old-style request */
||
memcmp
(
msg
+
8
,
id
,
12
))
/* wrong transaction ID */
return
false
;
switch
(
stun_get_class
(
msg
))
{
case
STUN_REQUEST
:
case
STUN_INDICATION
:
return
false
;
case
STUN_RESPONSE
:
*
error
=
-
1
;
break
;
case
STUN_ERROR
:
if
(
stun_find_errno
(
msg
,
error
)
!=
0
)
return
false
;
// missing ERROR-CODE: ignore message
break
;
}
/* If a shared secret exists, verify the message hash.
* If there is no shared secret, verify there is no hash at all. */
if
(
key
!=
NULL
)
{
/* FIXME: 401 errors do not have MESSAGE-INTEGRITY, so that we
* currently ignore them. */
if
(
stun_verify_key
(
msg
,
key
,
keylen
)
!=
0
)
return
false
;
}
/*
else
{
if (stun_present (msg, STUN_MESSAGE_INTEGRITY))
return false;
}*/
return
true
;
}
bool
stun_match_messages
(
const
uint8_t
*
restrict
resp
,
const
uint8_t
*
restrict
req
,
const
uint8_t
*
key
,
size_t
keylen
,
int
*
restrict
error
)
{
assert
(
stun_valid
(
resp
));
assert
(
stun_valid
(
req
));
assert
((
stun_get_class
(
req
)
>>
1
)
==
0
);
return
stun_match_answer
(
resp
,
stun_get_method
(
req
),
stun_id
(
req
),
key
,
keylen
,
error
);
}
unsigned
stun_find_unknown
(
const
uint8_t
*
restrict
msg
,
uint16_t
*
restrict
list
,
unsigned
max
)
{
unsigned
count
=
0
;
uint16_t
len
=
stun_length
(
msg
);
assert
(
stun_valid
(
msg
));
msg
+=
20
;
while
((
len
>
0
)
&&
(
count
<
max
))
{
size_t
alen
=
stun_align
(
stun_length
(
msg
));
uint16_t
atype
=
stun_getw
(
msg
);
msg
+=
4
+
alen
;
assert
(
len
>=
(
4
+
alen
));
len
-=
4
+
alen
;
if
(
!
stun_optional
(
atype
)
&&
stun_is_unknown
(
atype
))
{
DBG
(
"STUN unknown: attribute 0x%04x(%u bytes)
\n
"
,
(
unsigned
)
atype
,
(
unsigned
)
alen
);
list
[
count
++
]
=
atype
;
}
}
DBG
(
"STUN unknown: %u mandatory attribute(s)!
\n
"
,
count
);
return
count
;
}
stun/stunsend.c
View file @
b9669017
...
...
@@ -50,484 +50,3 @@
#include <netinet/in.h>
static
void
*
stun_setw
(
uint8_t
*
ptr
,
uint16_t
value
)
{
*
ptr
++
=
value
>>
8
;
*
ptr
++
=
value
&
0xff
;
return
ptr
;
}
static
void
stun_set_type
(
uint8_t
*
h
,
stun_class_t
c
,
stun_method_t
m
)
{
assert
(
c
<
4
);
assert
(
m
<
(
1
<<
12
));
h
[
0
]
=
(
c
>>
1
)
|
((
m
>>
6
)
&
0x3e
);
h
[
1
]
=
((
c
<<
4
)
&
0x10
)
|
((
m
<<
1
)
&
0xe0
)
|
(
m
&
0x0f
);
assert
(
stun_getw
(
h
)
<
(
1
<<
14
));
assert
(
stun_get_class
(
h
)
==
c
);
assert
(
stun_get_method
(
h
)
==
m
);
}
/**
* Initializes a STUN message buffer, with no attributes.
* @param c STUN message class (host byte order)
* @param m STUN message method (host byte order)
* @param id 16-bytes transaction ID
*/
static
void
stun_init
(
uint8_t
*
msg
,
stun_class_t
c
,
stun_method_t
m
,
const
stun_transid_t
id
)
{
memset
(
msg
,
0
,
4
);
stun_set_type
(
msg
,
c
,
m
);
msg
+=
8
;
if
(
msg
!=
id
)
{
uint32_t
cookie
=
htonl
(
STUN_COOKIE
);
memcpy
(
msg
-
4
,
&
cookie
,
sizeof
(
cookie
));
memcpy
(
msg
,
id
,
12
);
}
}
void
stun_init_request
(
uint8_t
*
req
,
stun_method_t
m
)
{
stun_transid_t
id
;
stun_make_transid
(
id
);
stun_init
(
req
,
STUN_REQUEST
,
m
,
id
);
}
void
stun_init_indication
(
uint8_t
*
req
,
stun_method_t
m
)
{
stun_transid_t
id
;
stun_make_transid
(
id
);
stun_init
(
req
,
STUN_INDICATION
,
m
,
id
);
}
/**
* Reserves room for appending an attribute to an unfinished STUN message.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type message type (host byte order)
* @param length attribute payload byte length
* @return a pointer to an unitialized buffer of <length> bytes to
* where the attribute payload must be written, or NULL if there is not
* enough room in the STUN message buffer. Return value is always on a
* 32-bits boundary.
*/
void
*
stun_append
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
size_t
length
)
{
uint8_t
*
a
;
uint16_t
mlen
=
stun_length
(
msg
);
assert
(
stun_valid
(
msg
));
assert
(
stun_padding
(
mlen
)
==
0
);
if
(
msize
>
STUN_MAXMSG
)
msize
=
STUN_MAXMSG
;
if
((((
size_t
)
mlen
)
+
24u
+
length
)
>
msize
)
return
NULL
;
assert
(
length
<
0xffff
);
a
=
msg
+
20u
+
mlen
;
a
=
stun_setw
(
a
,
type
);
/* NOTE: If cookie is not present, we need to force the attribute length
* to a multiple of 4 for compatibility with old RFC3489 */
a
=
stun_setw
(
a
,
stun_has_cookie
(
msg
)
?
length
:
stun_align
(
length
));
mlen
+=
4
+
length
;
/* Add padding if needed */
memset
(
a
+
length
,
' '
,
stun_padding
(
length
));
mlen
+=
stun_padding
(
length
);
stun_setw
(
msg
+
2
,
mlen
);
return
a
;
}
/**
* Appends an attribute from memory.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param type attribute type (host byte order)
* @param data memory address to copy payload from
* @param len attribute payload length
* @return 0 on success, ENOBUFS on error.
*/
int
stun_append_bytes
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
void
*
data
,
size_t
len
)
{
void
*
ptr
=
stun_append
(
msg
,
msize
,
type
,
len
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
memcpy
(
ptr
,
data
,
len
);
return
0
;
}
int
stun_append_flag
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
)
{
return
stun_append_bytes
(
msg
,
msize
,
type
,
NULL
,
0
);
}
int
stun_append32
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
uint32_t
value
)
{
value
=
htonl
(
value
);
return
stun_append_bytes
(
msg
,
msize
,
type
,
&
value
,
4
);
}
int
stun_append64
(
uint8_t
*
msg
,
size_t
msize
,
stun_attr_type_t
type
,
uint64_t
value
)
{
uint32_t
tab
[
2
];
tab
[
0
]
=
htonl
((
uint32_t
)(
value
>>
32
));
tab
[
1
]
=
htonl
((
uint32_t
)
value
);
return
stun_append_bytes
(
msg
,
msize
,
type
,
tab
,
8
);
}
int
stun_append_string
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
char
*
str
)
{
return
stun_append_bytes
(
msg
,
msize
,
type
,
str
,
strlen
(
str
));
}
static
int
stun_append_server
(
uint8_t
*
restrict
msg
,
size_t
msize
,
int
compat
)
{
static
const
char
server
[]
=
PACKAGE_STRING
;
assert
(
strlen
(
server
)
<
128
);
if
(
compat
==
1
)
return
0
;
else
return
stun_append_string
(
msg
,
msize
,
STUN_SERVER
,
server
);
}
void
stun_init_response
(
uint8_t
*
ans
,
size_t
msize
,
const
uint8_t
*
req
,
int
compat
)
{
assert
(
stun_valid
(
req
));
assert
(
stun_get_class
(
req
)
==
STUN_REQUEST
);
assert
(
msize
>=
20u
);
stun_init
(
ans
,
STUN_RESPONSE
,
stun_get_method
(
req
),
stun_id
(
req
));
/* For RFC3489 compatibility, we cannot assume the cookie */
memcpy
(
ans
+
4
,
req
+
4
,
4
);
(
void
)
stun_append_server
(
ans
,
msize
,
compat
);
}
/**
* @param code host-byte order error code
* @return a static pointer to a nul-terminated error message string.
*/
static
const
char
*
stun_strerror
(
stun_error_t
code
)
{
static
const
struct
{
stun_error_t
code
;
char
phrase
[
32
];
}
tab
[]
=
{
{
STUN_TRY_ALTERNATE
,
"Try alternate server"
},
{
STUN_BAD_REQUEST
,
"Bad request"
},
{
STUN_UNAUTHORIZED
,
"Authorization required"
},
{
STUN_UNKNOWN_ATTRIBUTE
,
"Unknown attribute"
},
/*
{ STUN_STALE_CREDENTIALS, "Authentication expired" },
{ STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
{ STUN_MISSING_USERNAME, "Username required" },
{ STUN_USE_TLS, "Secure connection required" },
{ STUN_MISSING_REALM, "Authentication domain required" },
{ STUN_MISSING_NONCE, "Authentication token missing" },
{ STUN_UNKNOWN_USERNAME, "Unknown user name" },
*/
{
STUN_NO_BINDING
,
"Session expired"
},
{
STUN_STALE_NONCE
,
"Authentication token expired"
},
{
STUN_ACT_DST_ALREADY
,
"Changing remote peer forbidden"
},
{
STUN_UNSUPP_TRANSPORT
,
"Unknown transport protocol"
},
{
STUN_INVALID_IP
,
"Address unavailable"
},
{
STUN_INVALID_PORT
,
"Port unavailable"
},
{
STUN_OP_TCP_ONLY
,
"Invalid operation"
},
{
STUN_CONN_ALREADY
,
"Connection already established"
},
{
STUN_ALLOC_OVER_QUOTA
,
"Quota reached"
},
{
STUN_ROLE_CONFLICT
,
"Role conflict"
},
{
STUN_SERVER_ERROR
,
"Temporary server error"
},
{
STUN_SERVER_CAPACITY
,
"Temporary server congestion"
},
};
const
char
*
str
=
"Unknown error"
;
size_t
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
tab
)
/
sizeof
(
tab
[
0
]));
i
++
)
{
if
(
tab
[
i
].
code
==
code
)
{
str
=
tab
[
i
].
phrase
;
break
;
}
}
/* Maximum allowed error message length */
assert
(
strlen
(
str
)
<
128
);
return
str
;
}
/**
* Appends an ERROR-CODE attribute.
* @param msg STUN message buffer
* @param msize STUN message buffer size
* @param code STUN host-byte order integer error code
* @return 0 on success, or ENOBUFS otherwise
*/
static
int
stun_append_error
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_error_t
code
)
{
const
char
*
str
=
stun_strerror
(
code
);
size_t
len
=
strlen
(
str
);
div_t
d
=
div
(
code
,
100
);
uint8_t
*
ptr
=
stun_append
(
msg
,
msize
,
STUN_ERROR_CODE
,
4
+
len
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
memset
(
ptr
,
0
,
2
);
assert
(
d
.
quot
<=
0x7
);
ptr
[
2
]
=
d
.
quot
;
ptr
[
3
]
=
d
.
rem
;
memcpy
(
ptr
+
4
,
str
,
len
);
return
0
;
}
int
stun_init_error
(
uint8_t
*
ans
,
size_t
msize
,
const
uint8_t
*
req
,
stun_error_t
err
,
int
compat
)
{
assert
(
stun_valid
(
req
));
assert
(
msize
>=
20u
);
assert
(
stun_get_class
(
req
)
==
STUN_REQUEST
);
stun_init
(
ans
,
STUN_ERROR
,
stun_get_method
(
req
),
stun_id
(
req
));
/* For RFC3489 compatibility, we cannot assume the cookie */
memcpy
(
ans
+
4
,
req
+
4
,
4
);
(
void
)
stun_append_server
(
ans
,
msize
,
compat
);
return
stun_append_error
(
ans
,
msize
,
err
);
}
int
stun_init_error_unknown
(
uint8_t
*
ans
,
size_t
msize
,
const
uint8_t
*
req
,
int
compat
)
{
unsigned
counter
,
i
;
#ifdef HAVE_C_VARARRAYS
uint16_t
ids
[
1
+
(
stun_length
(
req
)
/
4
)];
#else
uint16_t
ids
[
256
];
#endif
counter
=
stun_find_unknown
(
req
,
ids
,
sizeof
(
ids
)
/
sizeof
(
ids
[
0
]));
assert
(
counter
>
0
);
if
(
stun_init_error
(
ans
,
msize
,
req
,
STUN_UNKNOWN_ATTRIBUTE
,
compat
))
return
ENOBUFS
;
for
(
i
=
0
;
i
<
counter
;
i
++
)
ids
[
i
]
=
htons
(
ids
[
i
]);
/* NOTE: Old RFC3489 compatibility:
* When counter is odd, duplicate one value for 32-bits padding. */
if
(
!
stun_has_cookie
(
req
)
&&
(
counter
&
1
))
ids
[
counter
++
]
=
ids
[
0
];
return
stun_append_bytes
(
ans
,
msize
,
STUN_UNKNOWN_ATTRIBUTES
,
ids
,
counter
*
2
);
}
int
stun_append_addr
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
)
{
const
void
*
pa
;
uint8_t
*
ptr
;
uint16_t
alen
,
port
;
uint8_t
family
;
if
(
addrlen
<
sizeof
(
struct
sockaddr
))
return
EINVAL
;
switch
(
addr
->
sa_family
)
{
case
AF_INET
:
{
const
struct
sockaddr_in
*
ip4
=
(
const
struct
sockaddr_in
*
)
addr
;
assert
(
addrlen
>=
sizeof
(
*
ip4
));
family
=
1
;
port
=
ip4
->
sin_port
;
alen
=
4
;
pa
=
&
ip4
->
sin_addr
;
break
;
}
case
AF_INET6
:
{
const
struct
sockaddr_in6
*
ip6
=
(
const
struct
sockaddr_in6
*
)
addr
;
if
(
addrlen
<
sizeof
(
*
ip6
))
return
EINVAL
;
family
=
2
;
port
=
ip6
->
sin6_port
;
alen
=
16
;
pa
=
&
ip6
->
sin6_addr
;
break
;
}
default:
return
EAFNOSUPPORT
;
}
ptr
=
stun_append
(
msg
,
msize
,
type
,
4
+
alen
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
ptr
[
0
]
=
0
;
ptr
[
1
]
=
family
;
memcpy
(
ptr
+
2
,
&
port
,
2
);
memcpy
(
ptr
+
4
,
pa
,
alen
);
return
0
;
}
int
stun_append_xor_addr
(
uint8_t
*
restrict
msg
,
size_t
msize
,
stun_attr_type_t
type
,
const
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
)
{
int
val
;
/* Must be big enough to hold any supported address: */
struct
sockaddr_storage
xor
;
if
(
addrlen
>
sizeof
(
xor
))
addrlen
=
sizeof
(
xor
);
memcpy
(
&
xor
,
addr
,
addrlen
);
val
=
stun_xor_address
(
msg
,
(
struct
sockaddr
*
)
&
xor
,
addrlen
);
if
(
val
)
return
val
;
return
stun_append_addr
(
msg
,
msize
,
type
,
(
struct
sockaddr
*
)
&
xor
,
addrlen
);
}
size_t
stun_finish_long
(
uint8_t
*
msg
,
size_t
*
restrict
plen
,
const
char
*
realm
,
const
char
*
username
,
const
char
*
nonce
,
const
void
*
restrict
key
,
size_t
keylen
,
int
compat
)
{
size_t
len
=
*
plen
;
uint8_t
*
ptr
;
int
val
=
ENOBUFS
;
uint32_t
fpr
;
if
(
realm
!=
NULL
)
{
/*if (utf32_strlen (realm) > 127))
return EINVAL;*/
val
=
stun_append_string
(
msg
,
len
,
STUN_REALM
,
realm
);
if
(
val
)
return
val
;
}
if
(
username
!=
NULL
)
{
if
(
strlen
(
username
)
>=
513
)
return
EINVAL
;
val
=
stun_append_string
(
msg
,
len
,
STUN_USERNAME
,
username
);
if
(
val
)
return
val
;
}
if
(
nonce
!=
NULL
)
{
/*if (utf32_strlen (nonce) > 127))
return EINVAL;*/
val
=
stun_append_string
(
msg
,
len
,
STUN_NONCE
,
nonce
);
if
(
val
)
return
val
;
}
if
(
key
!=
NULL
)
{
ptr
=
stun_append
(
msg
,
len
,
STUN_MESSAGE_INTEGRITY
,
20
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
stun_sha1
(
msg
,
ptr
+
20
-
msg
,
ptr
,
key
,
keylen
);
DBG
(
" Message HMAC-SHA1 fingerprint:"
"
\n
key : "
);
DBG_bytes
(
key
,
keylen
);
DBG
(
"
\n
sent : "
);
DBG_bytes
(
ptr
,
20
);
DBG
(
"
\n
"
);
}
if
(
compat
!=
1
)
{
/*
* NOTE: we always add a FINGERPRINT, even when it's not needed.
* This is OK, as it is an optional attribute. It also makes my
* software engineer's life easier.
*/
ptr
=
stun_append
(
msg
,
len
,
STUN_FINGERPRINT
,
4
);
if
(
ptr
==
NULL
)
return
ENOBUFS
;
*
plen
=
ptr
+
4
-
msg
;
fpr
=
htonl
(
stun_fingerprint
(
msg
,
*
plen
));
memcpy
(
ptr
,
&
fpr
,
sizeof
(
fpr
));
}
*
plen
=
stun_length
(
msg
)
+
20
;
return
0
;
}
size_t
stun_finish_short
(
uint8_t
*
msg
,
size_t
*
restrict
plen
,
const
char
*
username
,
const
char
*
restrict
password
,
const
char
*
nonce
,
int
compat
)
{
return
stun_finish_long
(
msg
,
plen
,
NULL
,
username
,
nonce
,
password
,
password
?
strlen
(
password
)
:
0
,
compat
);
}
size_t
stun_finish
(
uint8_t
*
msg
,
size_t
*
restrict
plen
,
int
compat
)
{
return
stun_finish_short
(
msg
,
plen
,
NULL
,
NULL
,
NULL
,
compat
);
}
stun/tests/test-parse.c
View file @
b9669017
...
...
@@ -50,6 +50,9 @@
#include <errno.h>
# define STUN_MAX_STR (763u)
# define STUN_MAX_CP (127u)
static
void
fatal
(
const
char
*
msg
,
...)
{
va_list
ap
;
...
...
stun/tools/stunbdc.c
View file @
b9669017
...
...
@@ -39,7 +39,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include "stun
/usages/bind
.h"
#include "stun
agent
.h"
#include <unistd.h>
#include <getopt.h>
...
...
stun/utils.c
View file @
b9669017
...
...
@@ -38,9 +38,13 @@
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include "utils.h"
/** Compares two socket addresses */
...
...
@@ -115,97 +119,180 @@ uint16_t stun_getw (const uint8_t *ptr)
return
((
ptr
)[
0
]
<<
8
)
|
ptr
[
1
];
}
uint16_t
stun_length
(
const
uint8_t
*
ptr
)
{
return
stun_getw
(
ptr
+
2
);
}
/**
* @return STUN message class in host byte order (value from 0 to 3)
*/
stun_class_t
stun_get_class
(
const
uint8_t
*
msg
)
/* /\** */
/* * @param msg valid STUN message */
/* * @return true if there is at least one unknown mandatory attribute. */
/* *\/ */
/* bool stun_has_unknown (const void *msg) */
/* { */
/* uint16_t dummy; */
/* return stun_find_unknown (msg, &dummy, 1); */
/* } */
void
stun_debug
(
const
char
*
fmt
,
...)
{
uint16_t
t
=
stun_getw
(
msg
);
return
(
stun_class_t
)(((
t
&
0x0100
)
>>
7
)
|
((
t
&
0x0010
)
>>
4
));
va_list
ap
;
va_start
(
ap
,
fmt
);
vfprintf
(
stderr
,
fmt
,
ap
);
va_end
(
ap
);
}
/**
* @return STUN message method (value from 0 to 0xfff)
*/
stun_method_t
stun_get_method
(
const
uint8_t
*
msg
)
void
stun_debug_bytes
(
const
void
*
data
,
size_t
len
)
{
uint16_t
t
=
stun_getw
(
msg
);
return
(
stun_method_t
)(((
t
&
0x3e00
)
>>
2
)
|
((
t
&
0x00e0
)
>>
1
)
|
(
t
&
0x000f
));
}
size_t
i
;
stun_debug
(
"0x"
);
for
(
i
=
0
;
i
<
len
;
i
++
)
stun_debug
(
"%02x"
,
((
const
unsigned
char
*
)
data
)[
i
]);
}
/**
* @return STUN message transaction ID
*/
const
uint8_t
*
stun_id
(
const
uint8_t
*
msg
)
int
stun_xor_address
(
const
StunMessage
*
msg
,
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
)
{
//assert (stun_valid (req));
return
msg
+
8
;
switch
(
addr
->
sa_family
)
{
case
AF_INET
:
{
struct
sockaddr_in
*
ip4
=
(
struct
sockaddr_in
*
)
addr
;
if
(
addrlen
<
sizeof
(
*
ip4
))
return
EINVAL
;
ip4
->
sin_port
^=
htons
(
STUN_MAGIC_COOKIE
>>
16
);
ip4
->
sin_addr
.
s_addr
^=
htonl
(
STUN_MAGIC_COOKIE
);
return
0
;
}
case
AF_INET6
:
{
struct
sockaddr_in6
*
ip6
=
(
struct
sockaddr_in6
*
)
addr
;
unsigned
short
i
;
if
(
addrlen
<
sizeof
(
*
ip6
))
return
EINVAL
;
ip6
->
sin6_port
^=
htons
(
STUN_MAGIC_COOKIE
>>
16
);
for
(
i
=
0
;
i
<
16
;
i
++
)
ip6
->
sin6_addr
.
s6_addr
[
i
]
^=
msg
->
buffer
[
4
+
i
];
return
0
;
}
}
return
EAFNOSUPPORT
;
}
/**
* C
hecks if an attribute is present within a STUN messag
e.
* C
ompares the length and content of an attribut
e.
*
* @param msg valid STUN message
* @param msg valid STUN message
buffer
* @param type STUN attribute type (host byte order)
*
* @return whether there is a MESSAGE-INTEGRITY attribute
* @param data pointer to value to compare with
* @param len byte length of the value
* @return 0 in case of match, ENOENT if attribute was not found,
* EINVAL if it did not match (different length, or same length but
* different content)
*/
bool
stun_present
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
)
int
stun_memcmp
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
,
const
void
*
data
,
size_t
len
)
{
uint16_t
dummy
;
return
stun_find
(
msg
,
type
,
&
dummy
)
!=
NULL
;
uint16_t
alen
;
const
void
*
ptr
=
stun_message_find
(
msg
,
type
,
&
alen
);
if
(
ptr
==
NULL
)
return
ENOENT
;
if
((
len
!=
alen
)
||
memcmp
(
ptr
,
data
,
len
))
return
EINVAL
;
return
0
;
}
/**
* @param msg valid STUN message
* @return true if there is at least one unknown mandatory attribute.
* Compares the content of an attribute with a string.
* @param msg valid STUN message buffer
* @param type STUN attribute type (host byte order)
* @param str string to compare with
* @return 0 in case of match, ENOENT if attribute was not found,
* EINVAL if it did not match
*/
bool
stun_has_unknown
(
const
void
*
msg
)
int
stun_strcmp
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
,
const
char
*
str
)
{
uint16_t
dummy
;
return
stun_find_unknown
(
msg
,
&
dummy
,
1
);
return
stun_memcmp
(
msg
,
type
,
str
,
strlen
(
str
));
}
# ifndef NDEBUG
/**
* This function is for debugging only, which is why it is only defined under
* !NDEBUG. It should really only be used in run-time assertions, as it cannot
* detect all possible errors. stun_validate() should be used instead in real
* code.
*
* @param msg pointer to a potential STUN message
* @return whether the pointer refers to a valid STUN message
*/
bool
stun_valid
(
const
uint8_t
*
msg
)
void
*
stun_setw
(
uint8_t
*
ptr
,
uint16_t
value
)
{
size_t
length
=
20u
+
stun_length
(
msg
);
return
stun_validate
(
msg
,
length
)
==
(
ssize_t
)
length
;
*
ptr
++
=
value
>>
8
;
*
ptr
++
=
value
&
0xff
;
return
ptr
;
}
# endif
void
stun_debug
(
const
char
*
fmt
,
...)
void
stun_set_type
(
uint8_t
*
h
,
stun_class_t
c
,
stun_method_t
m
)
{
va_list
ap
;
va_start
(
ap
,
fmt
);
vfprintf
(
stderr
,
fmt
,
ap
);
va_end
(
ap
);
/* assert (c < 4); */
/* assert (m < (1 << 12)); */
h
[
0
]
=
(
c
>>
1
)
|
((
m
>>
6
)
&
0x3e
);
h
[
1
]
=
((
c
<<
4
)
&
0x10
)
|
((
m
<<
1
)
&
0xe0
)
|
(
m
&
0x0f
);
/* assert (stun_getw (h) < (1 << 14)); */
/* assert (stun_get_class (h) == c); */
/* assert (stun_get_method (h) == m); */
}
void
stun_debug_bytes
(
const
void
*
data
,
size_t
len
)
/**
* @param code host-byte order error code
* @return a static pointer to a nul-terminated error message string.
*/
const
char
*
stun_strerror
(
stun_error_t
code
)
{
static
const
struct
{
stun_error_t
code
;
char
phrase
[
32
];
}
tab
[]
=
{
{
STUN_ERROR_TRY_ALTERNATE
,
"Try alternate server"
},
{
STUN_ERROR_BAD_REQUEST
,
"Bad request"
},
{
STUN_ERROR_UNAUTHORIZED
,
"Authorization required"
},
{
STUN_ERROR_UNKNOWN_ATTRIBUTE
,
"Unknown attribute"
},
/*
{ STUN_STALE_CREDENTIALS, "Authentication expired" },
{ STUN_INTEGRITY_CHECK_FAILURE, "Incorrect username/password" },
{ STUN_MISSING_USERNAME, "Username required" },
{ STUN_USE_TLS, "Secure connection required" },
{ STUN_MISSING_REALM, "Authentication domain required" },
{ STUN_MISSING_NONCE, "Authentication token missing" },
{ STUN_UNKNOWN_USERNAME, "Unknown user name" },
*/
{
STUN_ERROR_NO_BINDING
,
"Session expired"
},
{
STUN_ERROR_STALE_NONCE
,
"Authentication token expired"
},
{
STUN_ERROR_ACT_DST_ALREADY
,
"Changing remote peer forbidden"
},
{
STUN_ERROR_UNSUPP_TRANSPORT
,
"Unknown transport protocol"
},
{
STUN_ERROR_INVALID_IP
,
"Address unavailable"
},
{
STUN_ERROR_INVALID_PORT
,
"Port unavailable"
},
{
STUN_ERROR_OP_TCP_ONLY
,
"Invalid operation"
},
{
STUN_ERROR_CONN_ALREADY
,
"Connection already established"
},
{
STUN_ERROR_ALLOC_OVER_QUOTA
,
"Quota reached"
},
{
STUN_ERROR_ROLE_CONFLICT
,
"Role conflict"
},
{
STUN_ERROR_SERVER_ERROR
,
"Temporary server error"
},
{
STUN_ERROR_SERVER_CAPACITY
,
"Temporary server congestion"
},
};
const
char
*
str
=
"Unknown error"
;
size_t
i
;
DBG
(
"0x"
);
for
(
i
=
0
;
i
<
len
;
i
++
)
DBG
(
"%02x"
,
((
const
unsigned
char
*
)
data
)[
i
]);
for
(
i
=
0
;
i
<
(
sizeof
(
tab
)
/
sizeof
(
tab
[
0
]));
i
++
)
{
if
(
tab
[
i
].
code
==
code
)
{
str
=
tab
[
i
].
phrase
;
break
;
}
}
/* Maximum allowed error message length */
// assert (strlen (str) < 128);
return
str
;
}
stun/utils.h
View file @
b9669017
...
...
@@ -41,7 +41,7 @@
* @brief STUN client generic utility functions
*/
#include "stun
-msg
.h"
#include "stun
message
.h"
# ifdef __cplusplus
extern
"C"
{
...
...
@@ -58,25 +58,23 @@ size_t stun_align (size_t l);
uint16_t
stun_getw
(
const
uint8_t
*
ptr
);
uint16_t
stun_length
(
const
uint8_t
*
ptr
);
stun_class_t
stun_get_class
(
const
uint8_t
*
msg
);
void
stun_debug
(
const
char
*
fmt
,
...);
stun_method_t
stun_get_method
(
const
uint8_t
*
msg
);
void
stun_debug_bytes
(
const
void
*
data
,
size_t
len
);
const
uint8_t
*
stun_id
(
const
uint8_t
*
msg
);
int
stun_xor_address
(
const
StunMessage
*
msg
,
struct
sockaddr
*
restrict
addr
,
socklen_t
addrlen
);
bool
stun_present
(
const
uint8_t
*
msg
,
stun_attr_type_t
type
);
int
stun_memcmp
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
,
const
void
*
data
,
size_t
len
);
bool
stun_has_unknown
(
const
void
*
msg
);
int
stun_strcmp
(
const
StunMessage
*
msg
,
stun_attr_type_t
type
,
const
char
*
str
);
# ifndef NDEBUG
bool
stun_valid
(
const
uint8_t
*
msg
);
# endif
void
*
stun_setw
(
uint8_t
*
ptr
,
uint16_t
value
);
void
stun_
debug
(
const
char
*
fmt
,
...
);
void
stun_
set_type
(
uint8_t
*
h
,
stun_class_t
c
,
stun_method_t
m
);
void
stun_debug_bytes
(
const
void
*
data
,
size_t
len
);
const
char
*
stun_strerror
(
stun_error_t
code
);
# ifdef __cplusplus
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment