mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
"stun and dtls done"
This commit is contained in:
parent
30d8b2209f
commit
9d5495c0c2
19 changed files with 1220 additions and 160 deletions
|
@ -2,27 +2,271 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <srs_core_autofree.hpp>
|
||||
#include <srs_kernel_buffer.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
#include <srs_kernel_utility.hpp>
|
||||
|
||||
static string dump_string_hex(const std::string& str, const int& max_len = 128)
|
||||
{
|
||||
char buf[1024*16];
|
||||
int len = 0;
|
||||
|
||||
for (int i = 0; i < str.size() && i < max_len; ++i) {
|
||||
int nb = snprintf(buf + len, sizeof(buf) - len - 1, "%02X ", (uint8_t)str[i]);
|
||||
if (nb <= 0)
|
||||
break;
|
||||
|
||||
len += nb;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
|
||||
return string(buf, len);
|
||||
}
|
||||
|
||||
static srs_error_t hmac_encode(const std::string& algo, const char* key, const int& key_length,
|
||||
const char* input, const int input_length, char* output, unsigned int& output_length)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
const EVP_MD* engine = NULL;
|
||||
if (algo == "sha512") {
|
||||
engine = EVP_sha512();
|
||||
} else if(algo == "sha256") {
|
||||
engine = EVP_sha256();
|
||||
} else if(algo == "sha1") {
|
||||
engine = EVP_sha1();
|
||||
} else if(algo == "md5") {
|
||||
engine = EVP_md5();
|
||||
} else if(algo == "sha224") {
|
||||
engine = EVP_sha224();
|
||||
} else if(algo == "sha384") {
|
||||
engine = EVP_sha384();
|
||||
} else {
|
||||
return srs_error_wrap(err, "unknown algo=%s", algo.c_str());
|
||||
}
|
||||
|
||||
HMAC_CTX* ctx = HMAC_CTX_new();
|
||||
if (HMAC_Init_ex(ctx, key, key_length, engine, NULL) < 0) {
|
||||
HMAC_CTX_free(ctx);
|
||||
return srs_error_wrap(err, "hmac init faied");
|
||||
}
|
||||
|
||||
if (HMAC_Update(ctx, (const unsigned char*)input, input_length) < 0) {
|
||||
HMAC_CTX_free(ctx);
|
||||
return srs_error_wrap(err, "hmac update faied");
|
||||
}
|
||||
|
||||
if (HMAC_Final(ctx, (unsigned char*)output, &output_length) < 0) {
|
||||
HMAC_CTX_free(ctx);
|
||||
return srs_error_wrap(err, "hmac final faied");
|
||||
}
|
||||
|
||||
HMAC_CTX_free(ctx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
SrsStunPacket::SrsStunPacket()
|
||||
{
|
||||
message_type = 0;
|
||||
local_ufrag = "";
|
||||
remote_ufrag = "";
|
||||
}
|
||||
|
||||
SrsStunPacket::~SrsStunPacket()
|
||||
{
|
||||
}
|
||||
|
||||
string SrsStunPacket::ufrag()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
string SrsStunPacket::pwd()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
srs_error_t SrsStunPacket::decode(const char* buf, const int nb_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
SrsBuffer* stream = new SrsBuffer(const_cast<char*>(buf), nb_buf);
|
||||
SrsAutoFree(SrsBuffer, stream);
|
||||
|
||||
if (stream->left() < 20) {
|
||||
return srs_error_wrap(err, "invalid stun packet, size=%d", stream->size());
|
||||
}
|
||||
|
||||
srs_trace("stun packet, nb_buf=%d", nb_buf);
|
||||
|
||||
message_type = stream->read_2bytes();
|
||||
uint16_t message_len = stream->read_2bytes();
|
||||
string magic_cookie = stream->read_string(4);
|
||||
transcation_id = stream->read_string(12);
|
||||
|
||||
srs_trace("message_type=%u, message_len=%u, magic_cookie=%s, transcation_id=%s",
|
||||
message_type, message_len, magic_cookie.c_str(), transcation_id.c_str());
|
||||
|
||||
if (nb_buf != 20 + message_len) {
|
||||
return srs_error_wrap(err, "invalid stun packet, message_len=%d, nb_buf=%d", message_len, nb_buf);
|
||||
}
|
||||
|
||||
while (stream->left() >= 4) {
|
||||
uint16_t type = stream->read_2bytes();
|
||||
uint16_t len = stream->read_2bytes();
|
||||
|
||||
srs_trace("type=%u, len=%u", type, len);
|
||||
|
||||
if (stream->left() < len) {
|
||||
return srs_error_wrap(err, "invalid stun packet");
|
||||
}
|
||||
|
||||
string val = stream->read_string(len);
|
||||
// padding
|
||||
if (len % 4 != 0) {
|
||||
stream->read_string(4 - (len % 4));
|
||||
}
|
||||
//srs_trace("val=%s", val.c_str());
|
||||
|
||||
switch (type) {
|
||||
// FIXME: enum
|
||||
case 6: {
|
||||
size_t p = val.find(":");
|
||||
if (p != string::npos) {
|
||||
local_ufrag = val.substr(0, p);
|
||||
remote_ufrag = val.substr(p + 1);
|
||||
srs_trace("stun packet local_ufrag=%s, remote_ufrag=%s", local_ufrag.c_str(), remote_ufrag.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsStunPacket::encode(const string& pwd, SrsBuffer* stream)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
if (is_binding_response()) {
|
||||
return encode_binding_response(pwd, stream);
|
||||
}
|
||||
|
||||
return srs_error_wrap(err, "unknown stun type=%d", get_message_type());
|
||||
}
|
||||
|
||||
// FIXME: make this function easy to read
|
||||
srs_error_t SrsStunPacket::encode_binding_response(const string& pwd, SrsBuffer* stream)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
string property_username = encode_username();
|
||||
string mapped_address = encode_mapped_address();
|
||||
|
||||
stream->write_2bytes(BindingResponse);
|
||||
stream->write_2bytes(property_username.size() + mapped_address.size());
|
||||
stream->write_4bytes(0x2112A442);
|
||||
stream->write_string(transcation_id);
|
||||
stream->write_string(property_username);
|
||||
stream->write_string(mapped_address);
|
||||
|
||||
stream->data()[2] = ((stream->pos() - 20 + 20 + 4) & 0x0000FF00) >> 8;
|
||||
stream->data()[3] = ((stream->pos() - 20 + 20 + 4) & 0x000000FF);
|
||||
|
||||
char hmac_buf[20] = {0};
|
||||
unsigned int hmac_buf_len = 0;
|
||||
if (hmac_encode("sha1", pwd.c_str(), pwd.size(), stream->data(), stream->pos(), hmac_buf, hmac_buf_len) != srs_success) {
|
||||
return srs_error_wrap(err, "hmac encode failed");
|
||||
}
|
||||
|
||||
string hmac = encode_hmac(hmac_buf, hmac_buf_len);
|
||||
|
||||
stream->write_string(hmac);
|
||||
stream->data()[2] = ((stream->pos() - 20 + 8) & 0x0000FF00) >> 8;
|
||||
stream->data()[3] = ((stream->pos() - 20 + 8) & 0x000000FF);
|
||||
|
||||
uint32_t crc32 = srs_crc32_ieee(stream->data(), stream->pos(), 0) ^ 0x5354554E;
|
||||
|
||||
string fingerprint = encode_fingerprint(crc32);
|
||||
|
||||
stream->write_string(fingerprint);
|
||||
|
||||
stream->data()[2] = ((stream->pos() - 20) & 0x0000FF00) >> 8;
|
||||
stream->data()[3] = ((stream->pos() - 20) & 0x000000FF);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
string SrsStunPacket::encode_username()
|
||||
{
|
||||
char buf[1460];
|
||||
SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf));
|
||||
SrsAutoFree(SrsBuffer, stream);
|
||||
|
||||
string username = remote_ufrag + ":" + local_ufrag;
|
||||
|
||||
stream->write_2bytes(Username);
|
||||
stream->write_2bytes(username.size());
|
||||
stream->write_string(username);
|
||||
|
||||
if (stream->pos() % 4 != 0) {
|
||||
static char padding[4] = {0};
|
||||
stream->write_bytes(padding, 4 - (stream->pos() % 4));
|
||||
}
|
||||
|
||||
return string(stream->data(), stream->pos());
|
||||
}
|
||||
|
||||
string SrsStunPacket::encode_mapped_address()
|
||||
{
|
||||
char buf[1460];
|
||||
SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf));
|
||||
SrsAutoFree(SrsBuffer, stream);
|
||||
|
||||
uint32_t magic_cookie = 0x2112A442;
|
||||
#if 1
|
||||
stream->write_2bytes(XorMappedAddress);
|
||||
stream->write_2bytes(8);
|
||||
stream->write_1bytes(0); // ignore this bytes
|
||||
stream->write_1bytes(1); // ipv4 family
|
||||
stream->write_2bytes(mapped_port ^ (magic_cookie >> 16));
|
||||
stream->write_4bytes(mapped_address ^ magic_cookie);
|
||||
#else
|
||||
stream->write_2bytes(MappedAddress);
|
||||
stream->write_2bytes(8);
|
||||
stream->write_1bytes(0); // ignore this bytes
|
||||
stream->write_1bytes(1); // ipv4 family
|
||||
stream->write_2bytes(mapped_port);
|
||||
stream->write_4bytes(mapped_address);
|
||||
#endif
|
||||
|
||||
return string(stream->data(), stream->pos());
|
||||
}
|
||||
|
||||
string SrsStunPacket::encode_hmac(char* hmac_buf, const int hmac_buf_len)
|
||||
{
|
||||
char buf[1460];
|
||||
SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf));
|
||||
SrsAutoFree(SrsBuffer, stream);
|
||||
|
||||
stream->write_2bytes(MessageIntegrity);
|
||||
stream->write_2bytes(hmac_buf_len);
|
||||
stream->write_bytes(hmac_buf, hmac_buf_len);
|
||||
|
||||
return string(stream->data(), stream->pos());
|
||||
}
|
||||
|
||||
string SrsStunPacket::encode_fingerprint(uint32_t crc32)
|
||||
{
|
||||
char buf[1460];
|
||||
SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf));
|
||||
SrsAutoFree(SrsBuffer, stream);
|
||||
|
||||
stream->write_2bytes(Fingerprint);
|
||||
stream->write_2bytes(4);
|
||||
stream->write_4bytes(crc32);
|
||||
|
||||
return string(stream->data(), stream->pos());
|
||||
}
|
||||
|
|
|
@ -29,16 +29,81 @@
|
|||
#include <srs_core.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
|
||||
class SrsBuffer;
|
||||
|
||||
enum SrsStunMessageType
|
||||
{
|
||||
// see @ https://tools.ietf.org/html/rfc3489#section-11.1
|
||||
BindingRequest = 0x0001,
|
||||
BindingResponse = 0x0101,
|
||||
BindingErrorResponse = 0x0111,
|
||||
SharedSecretRequest = 0x0002,
|
||||
SharedSecretResponse = 0x0102,
|
||||
SharedSecretErrorResponse = 0x0112,
|
||||
};
|
||||
|
||||
enum SrsStunMessageAttribute
|
||||
{
|
||||
// see @ https://tools.ietf.org/html/rfc3489#section-11.2
|
||||
MappedAddress = 0x0001,
|
||||
ResponseAddress = 0x0002,
|
||||
ChangeRequest = 0x0003,
|
||||
SourceAddress = 0x0004,
|
||||
ChangedAddress = 0x0005,
|
||||
Username = 0x0006,
|
||||
Password = 0x0007,
|
||||
MessageIntegrity = 0x0008,
|
||||
ErrorCode = 0x0009,
|
||||
UnknownAttributes = 0x000A,
|
||||
ReflectedFrom = 0x000B,
|
||||
|
||||
// see @ https://tools.ietf.org/html/rfc5389#section-18.2
|
||||
Realm = 0x0014,
|
||||
Nonce = 0x0015,
|
||||
XorMappedAddress = 0x0020,
|
||||
Software = 0x8022,
|
||||
AlternateServer = 0x8023,
|
||||
Fingerprint = 0x8028,
|
||||
};
|
||||
|
||||
class SrsStunPacket
|
||||
{
|
||||
private:
|
||||
uint16_t message_type;
|
||||
std::string local_ufrag;
|
||||
std::string remote_ufrag;
|
||||
std::string transcation_id;
|
||||
uint32_t mapped_address;
|
||||
uint16_t mapped_port;
|
||||
public:
|
||||
SrsStunPacket();
|
||||
virtual ~SrsStunPacket();
|
||||
|
||||
std::string ufrag();
|
||||
std::string pwd();
|
||||
bool is_binding_request() const { return message_type == BindingRequest; }
|
||||
bool is_binding_response() const { return message_type == BindingResponse; }
|
||||
|
||||
uint16_t get_message_type() const { return message_type; }
|
||||
std::string get_local_ufrag() const { return local_ufrag; }
|
||||
std::string get_remote_ufrag() const { return remote_ufrag; }
|
||||
std::string get_transcation_id() const { return transcation_id; }
|
||||
uint32_t get_mapped_address() const { return mapped_address; }
|
||||
uint16_t get_mapped_port() const { return mapped_port; }
|
||||
|
||||
void set_message_type(const uint16_t& m) { message_type = m; }
|
||||
void set_local_ufrag(const std::string& u) { local_ufrag = u; }
|
||||
void set_remote_ufrag(const std::string& u) { remote_ufrag = u; }
|
||||
void set_transcation_id(const std::string& t) { transcation_id = t; }
|
||||
void set_mapped_address(const uint32_t& addr) { mapped_address = addr; }
|
||||
void set_mapped_port(const uint32_t& port) { mapped_port = port; }
|
||||
|
||||
srs_error_t decode(const char* buf, const int nb_buf);
|
||||
srs_error_t encode(const std::string& pwd, SrsBuffer* stream);
|
||||
private:
|
||||
srs_error_t encode_binding_response(const std::string& pwd, SrsBuffer* stream);
|
||||
std::string encode_username();
|
||||
std::string encode_mapped_address();
|
||||
std::string encode_hmac(char* hamc_buf, const int hmac_buf_len);
|
||||
std::string encode_fingerprint(uint32_t crc32);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue