mistserver/lib/stun.h
2021-10-19 22:29:40 +02:00

251 lines
7.5 KiB
C++

#pragma once
#include <netinet/in.h>
#include <stdint.h>
#include <string>
#include <vector>
/* --------------------------------------- */
#define STUN_IP4 0x01
#define STUN_IP6 0x02
#define STUN_MSG_TYPE_NONE 0x0000
#define STUN_MSG_TYPE_BINDING_REQUEST 0x0001
#define STUN_MSG_TYPE_BINDING_RESPONSE_SUCCESS 0x0101
#define STUN_MSG_TYPE_BINDING_RESPONSE_ERROR 0x0111
#define STUN_MSG_TYPE_BINDING_INDICATION 0x0011
#define STUN_ATTR_TYPE_NONE 0x0000
#define STUN_ATTR_TYPE_MAPPED_ADDR 0x0001
#define STUN_ATTR_TYPE_CHANGE_REQ 0x0003
#define STUN_ATTR_TYPE_USERNAME 0x0006
#define STUN_ATTR_TYPE_MESSAGE_INTEGRITY 0x0008
#define STUN_ATTR_TYPE_ERR_CODE 0x0009
#define STUN_ATTR_TYPE_UNKNOWN_ATTRIBUTES 0x000a
#define STUN_ATTR_TYPE_CHANNEL_NUMBER 0x000c
#define STUN_ATTR_TYPE_LIFETIME 0x000d
#define STUN_ATTR_TYPE_XOR_PEER_ADDR 0x0012
#define STUN_ATTR_TYPE_DATA 0x0013
#define STUN_ATTR_TYPE_REALM 0x0014
#define STUN_ATTR_TYPE_NONCE 0x0015
#define STUN_ATTR_TYPE_XOR_RELAY_ADDRESS 0x0016
#define STUN_ATTR_TYPE_REQ_ADDRESS_FAMILY 0x0017
#define STUN_ATTR_TYPE_EVEN_PORT 0x0018
#define STUN_ATTR_TYPE_REQUESTED_TRANSPORT 0x0019
#define STUN_ATTR_TYPE_DONT_FRAGMENT 0x001a
#define STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS 0x0020
#define STUN_ATTR_TYPE_RESERVATION_TOKEN 0x0022
#define STUN_ATTR_TYPE_PRIORITY 0x0024
#define STUN_ATTR_TYPE_USE_CANDIDATE 0x0025
#define STUN_ATTR_TYPE_PADDING 0x0026
#define STUN_ATTR_TYPE_RESPONSE_PORT 0x0027
#define STUN_ATTR_TYPE_SOFTWARE 0x8022
#define STUN_ATTR_TYPE_ALTERNATE_SERVER 0x8023
#define STUN_ATTR_TYPE_FINGERPRINT 0x8028
#define STUN_ATTR_TYPE_ICE_CONTROLLED 0x8029
#define STUN_ATTR_TYPE_ICE_CONTROLLING 0x802a
#define STUN_ATTR_TYPE_RESPONSE_ORIGIN 0x802b
#define STUN_ATTR_TYPE_OTHER_ADDRESS 0x802c
/* --------------------------------------- */
std::string stun_message_type_to_string(uint16_t type);
std::string stun_attribute_type_to_string(uint16_t type);
std::string stun_family_type_to_string(uint8_t type);
/*
Compute the hmac-sha1 over message.
uint8_t* message: the data over which we compute the hmac sha
uint32_t nbytes: the number of bytse in message
std::string key: key to use for hmac
uint8_t* output: we write the sha1 into this buffer.
*/
int stun_compute_hmac_sha1(uint8_t *message, uint32_t nbytes, std::string key, uint8_t *output);
/*
Compute the Message-Integrity of a stun message.
This will not change the given buffer.
std::vector<uint8_t>& buffer: the buffer that contains a valid stun message
std::string key: key to use for hmac
uint8_t* output: will be filled with the correct hmac-sha1 of that represents the integrity message value.
*/
int stun_compute_message_integrity(std::vector<uint8_t> &buffer, std::string key, uint8_t *output);
/*
Compute the fingerprint value for the stun message.
This will not change the given buffer.
std::vector<uint8_t>& buffer: the buffer that contains a valid stun message.
uint32_t& result: will be set to the calculated crc value.
*/
int stun_compute_fingerprint(std::vector<uint8_t> &buffer, uint32_t &result);
/* --------------------------------------- */
/* https://tools.ietf.org/html/rfc5389#section-15.10 */
class StunAttribSoftware{
public:
char *value;
};
class StunAttribFingerprint{
public:
uint32_t value;
};
/* https://tools.ietf.org/html/rfc5389#section-15.4 */
class StunAttribMessageIntegrity{
public:
uint8_t *sha1;
};
/* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribPriority{
public:
uint32_t value;
};
/* https://tools.ietf.org/html/rfc5245#section-19.1 */
class StunAttribIceControllling{
public:
uint64_t tie_breaker;
};
/* https://tools.ietf.org/html/rfc3489#section-11.2.6 */
class StunAttribUsername{
public:
char *value; /* Must use `length` member of attribute that indicates the number of valid bytes in the username. */
};
/* https://tools.ietf.org/html/rfc5389#section-15.2 */
class StunAttribXorMappedAddress{
public:
uint8_t family;
uint16_t port;
uint8_t ip[16];
};
/* --------------------------------------- */
class StunAttribute{
public:
StunAttribute();
void print();
public:
uint16_t type;
uint16_t length;
union{
StunAttribXorMappedAddress xor_address;
StunAttribUsername username;
StunAttribIceControllling ice_controlling;
StunAttribPriority priority;
StunAttribSoftware software;
StunAttribMessageIntegrity message_integrity;
StunAttribFingerprint fingerprint;
};
};
/* --------------------------------------- */
class StunMessage{
public:
StunMessage();
void setType(uint16_t type);
void setTransactionId(uint32_t a, uint32_t b, uint32_t c);
void print();
void addAttribute(StunAttribute &attr);
void removeAttributes();
StunAttribute *getAttributeByType(uint16_t type);
public:
uint16_t type;
uint16_t length;
uint32_t cookie;
uint32_t transaction_id[3];
std::vector<StunAttribute> attributes;
};
/* --------------------------------------- */
class StunReader{
public:
StunReader();
int parse(uint8_t *data, size_t nbytes, size_t &nparsed, StunMessage &msg); /* `nparsed` and `msg` are filled. */
private:
int parseXorMappedAddress(StunAttribute &attr);
int parseUsername(StunAttribute &attr);
int parseIceControlling(StunAttribute &attr);
int parsePriority(StunAttribute &attr);
int parseSoftware(StunAttribute &attr);
int parseMessageIntegrity(StunAttribute &attr);
int parseFingerprint(StunAttribute &attr);
uint8_t readU8();
uint16_t readU16();
uint32_t readU32();
uint64_t readU64();
private:
uint8_t *buffer_data;
size_t buffer_size;
size_t read_dx;
};
/* --------------------------------------- */
class StunWriter{
public:
StunWriter();
/* write header and finalize. call for each stun message */
int begin(StunMessage &msg,
uint8_t paddingByte = 0x00); /* I've added the padding byte here so that we can use the
examples that can be found here https://tools.ietf.org/html/rfc5769#section-2.2
as they use 0x20 or 0x00 as the padding byte which is correct as you are free to use w/e padding byte you want. */
int end();
/* write attributes */
int writeXorMappedAddress(sockaddr_in addr);
int writeXorMappedAddress(uint8_t family, uint16_t port, uint32_t ip);
int writeXorMappedAddress(uint8_t family, uint16_t port, const std::string &ip);
int writeUsername(const std::string &username);
int writeSoftware(const std::string &software);
int writeMessageIntegrity(const std::string &password); /* When using WebRtc this is the ice-upwd of the other agent. */
int writeFingerprint(); /* Must be the last attribute in the message. When adding a fingerprint, make sure that it is added after the message-integrity (when you also use a message-integrity). */
/* get buffer */
uint8_t *getBufferPtr();
size_t getBufferSize();
private:
void writeU8(uint8_t v);
void writeU16(uint16_t v);
void writeU32(uint32_t v);
void writeU64(uint64_t v);
void rewriteU16(size_t dx, uint16_t v);
void rewriteU32(size_t dx, uint32_t v);
void writeString(const std::string &str);
void writePadding();
int convertIp4StringToInt(const std::string &ip, uint32_t &result);
private:
std::vector<uint8_t> buffer;
uint8_t padding_byte;
};
/* --------------------------------------- */
inline uint8_t *StunWriter::getBufferPtr(){
if (0 == buffer.size()){return NULL;}
return &buffer[0];
}
inline size_t StunWriter::getBufferSize(){
return buffer.size();
}
/* --------------------------------------- */