forked from PurpleI2P/i2pd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSSU.h
195 lines (166 loc) · 6.81 KB
/
SSU.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#ifndef SSU_H__
#define SSU_H__
#include <inttypes.h>
#include <map>
#include <list>
#include <set>
#include <boost/asio.hpp>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include "I2PEndian.h"
#include "Identity.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
namespace i2p
{
namespace ssu
{
#pragma pack(1)
struct SSUHeader
{
uint8_t mac[16];
uint8_t iv[16];
uint8_t flag;
uint32_t time;
uint8_t GetPayloadType () const { return flag >> 4; };
};
#pragma pack()
const size_t SSU_MTU = 1484;
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
// payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
const uint8_t PAYLOAD_TYPE_SESSION_CREATED = 1;
const uint8_t PAYLOAD_TYPE_SESSION_CONFIRMED = 2;
const uint8_t PAYLOAD_TYPE_RELAY_REQUEST = 3;
const uint8_t PAYLOAD_TYPE_RELAY_RESPONSE = 4;
const uint8_t PAYLOAD_TYPE_RELAY_INTRO = 5;
const uint8_t PAYLOAD_TYPE_DATA = 6;
const uint8_t PAYLOAD_TYPE_PEER_TEST = 7;
const uint8_t PAYLOAD_TYPE_SESSION_DESTROYED = 8;
// data flags
const uint8_t DATA_FLAG_EXTENDED_DATA_INCLUDED = 0x02;
const uint8_t DATA_FLAG_WANT_REPLY = 0x04;
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
enum SessionState
{
eSessionStateUnknown,
eSessionStateRequestSent,
eSessionStateRequestReceived,
eSessionStateCreatedSent,
eSessionStateCreatedReceived,
eSessionStateConfirmedSent,
eSessionStateConfirmedReceived,
eSessionStateRelayRequestSent,
eSessionStateRelayRequestReceived,
eSessionStateIntroduced,
eSessionStateEstablished,
eSessionStateFailed
};
class SSUServer;
class SSUSession
{
public:
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
const i2p::data::RouterInfo * router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession ();
void Connect ();
void Introduce (uint32_t iTag, const uint8_t * iKey);
void WaitForIntroduction ();
void Close ();
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
const i2p::data::RouterInfo * GetRemoteRouter () const { return m_RemoteRouter; };
void SendI2NPMessage (I2NPMessage * msg);
void SendPeerTest (); // Alice
private:
void CreateAESandMacKey (const uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendSessionRequest ();
void SendRelayRequest (uint32_t iTag, const uint8_t * iKey);
void ProcessSessionCreated (uint8_t * buf, size_t len);
void SendSessionCreated (const uint8_t * x);
void ProcessSessionConfirmed (uint8_t * buf, size_t len);
void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress);
void ProcessRelayRequest (uint8_t * buf, size_t len);
void SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from, const uint8_t * introKey, const boost::asio::ip::udp::endpoint& to);
void SendRelayIntro (SSUSession * session, const boost::asio::ip::udp::endpoint& from);
void ProcessRelayResponse (uint8_t * buf, size_t len);
void ProcessRelayIntro (uint8_t * buf, size_t len);
void Established ();
void Failed ();
void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey); // Charlie to Alice
void ProcessData (uint8_t * buf, size_t len);
void SendMsgAck (uint32_t msgID);
void SendSesionDestroyed ();
void Send (i2p::I2NPMessage * msg);
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey);
void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey);
bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey);
const uint8_t * GetIntroKey () const;
void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode);
private:
struct IncompleteMessage
{
I2NPMessage * msg;
uint8_t nextFragmentNum;
IncompleteMessage (I2NPMessage * m): msg (m), nextFragmentNum (1) {};
};
SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
const i2p::data::RouterInfo * m_RemoteRouter;
boost::asio::deadline_timer m_Timer;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
bool m_PeerTest;
SessionState m_State;
bool m_IsSessionKey;
uint32_t m_RelayTag;
std::set<uint32_t> m_PeerTestNonces;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
uint8_t m_SessionKey[32], m_MacKey[32];
std::map<uint32_t, IncompleteMessage *> m_IncomleteMessages;
std::list<i2p::I2NPMessage *> m_DelayedMessages;
};
class SSUServer
{
public:
SSUServer (boost::asio::io_service& service, int port);
~SSUServer ();
void Start ();
void Stop ();
SSUSession * GetSession (const i2p::data::RouterInfo * router, bool peerTest = false);
SSUSession * FindSession (const i2p::data::RouterInfo * router);
SSUSession * FindSession (const boost::asio::ip::udp::endpoint& e);
void DeleteSession (SSUSession * session);
void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Socket.get_io_service(); };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay);
SSUSession * FindRelaySession (uint32_t tag);
private:
void Receive ();
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred);
private:
boost::asio::ip::udp::endpoint m_Endpoint;
boost::asio::ip::udp::socket m_Socket;
boost::asio::ip::udp::endpoint m_SenderEndpoint;
uint8_t m_ReceiveBuffer[2*SSU_MTU];
std::map<boost::asio::ip::udp::endpoint, SSUSession *> m_Sessions;
std::map<uint32_t, boost::asio::ip::udp::endpoint> m_Relays; // we are introducer
public:
// for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
};
}
}
#endif