mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-11-14 05:20:10 +00:00
impement UDP associate in SOCKS proxy
This commit is contained in:
parent
ab6dbe620c
commit
689a35c142
2 changed files with 66 additions and 19 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2024, The PurpleI2P Project
|
* Copyright (c) 2013-2025, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include "I2PService.h"
|
#include "I2PService.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Socks5.h"
|
#include "Socks5.h"
|
||||||
|
#include "UDPTunnel.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
|
@ -172,6 +173,7 @@ namespace proxy
|
||||||
const bool m_UseUpstreamProxy; // do we want to use the upstream proxy for non i2p addresses?
|
const bool m_UseUpstreamProxy; // do we want to use the upstream proxy for non i2p addresses?
|
||||||
const std::string m_UpstreamProxyAddress;
|
const std::string m_UpstreamProxyAddress;
|
||||||
const uint16_t m_UpstreamProxyPort;
|
const uint16_t m_UpstreamProxyPort;
|
||||||
|
std::unique_ptr<i2p::client::I2PUDPClientTunnel> m_UDPTunnel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
@ -229,6 +231,11 @@ namespace proxy
|
||||||
LogPrint(eLogDebug, "SOCKS: Closing stream");
|
LogPrint(eLogDebug, "SOCKS: Closing stream");
|
||||||
m_stream.reset ();
|
m_stream.reset ();
|
||||||
}
|
}
|
||||||
|
if (m_UDPTunnel)
|
||||||
|
{
|
||||||
|
m_UDPTunnel->Stop ();
|
||||||
|
m_UDPTunnel = nullptr;
|
||||||
|
}
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,10 +350,20 @@ namespace proxy
|
||||||
break;
|
break;
|
||||||
case SOCKS5:
|
case SOCKS5:
|
||||||
LogPrint(eLogInfo, "SOCKS: v5 connection success");
|
LogPrint(eLogInfo, "SOCKS: v5 connection success");
|
||||||
auto s = i2p::client::context.GetAddressBook().ToAddress(GetOwner()->GetLocalDestination()->GetIdentHash());
|
if (m_cmd == CMD_UDP && m_UDPTunnel)
|
||||||
address ad; ad.dns.FromString(s);
|
{
|
||||||
// HACK only 16 bits passed in port as SOCKS5 doesn't allow for more
|
address ad;
|
||||||
response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, ad, m_stream->GetRecvStreamID());
|
// TODO: implement ipv6
|
||||||
|
ad.ip = m_UDPTunnel->GetLocalEndpoint ().address ().to_v4 ().to_uint ();
|
||||||
|
response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_IPV4, ad, m_UDPTunnel->GetLocalEndpoint ().port ());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto s = i2p::client::context.GetAddressBook().ToAddress(GetOwner()->GetLocalDestination()->GetIdentHash());
|
||||||
|
address ad; ad.dns.FromString(s);
|
||||||
|
// HACK only 16 bits passed in port as SOCKS5 doesn't allow for more
|
||||||
|
response = GenerateSOCKS5Response(SOCKS5_OK, ADDR_DNS, ad, m_stream ? m_stream->GetRecvStreamID() : 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksDone, shared_from_this(), std::placeholders::_1));
|
boost::asio::async_write(*m_sock, response, std::bind(&SOCKSHandler::SentSocksDone, shared_from_this(), std::placeholders::_1));
|
||||||
|
|
@ -369,7 +386,7 @@ namespace proxy
|
||||||
|
|
||||||
bool SOCKSHandler::ValidateSOCKSRequest()
|
bool SOCKSHandler::ValidateSOCKSRequest()
|
||||||
{
|
{
|
||||||
if ( m_cmd != CMD_CONNECT )
|
if ( m_cmd != CMD_CONNECT && m_cmd != CMD_UDP)
|
||||||
{
|
{
|
||||||
// TODO: we need to support binds and other shit!
|
// TODO: we need to support binds and other shit!
|
||||||
LogPrint(eLogError, "SOCKS: Unsupported command: ", m_cmd);
|
LogPrint(eLogError, "SOCKS: Unsupported command: ", m_cmd);
|
||||||
|
|
@ -619,17 +636,39 @@ namespace proxy
|
||||||
LogPrint(eLogInfo, "SOCKS: Requested ", addr, ":" , m_port);
|
LogPrint(eLogInfo, "SOCKS: Requested ", addr, ":" , m_port);
|
||||||
const size_t addrlen = addr.size();
|
const size_t addrlen = addr.size();
|
||||||
// does it end with .i2p?
|
// does it end with .i2p?
|
||||||
if ( addr.rfind(".i2p") == addrlen - 4) {
|
if (addr.rfind(".i2p") == addrlen - 4)
|
||||||
// yes it does, make an i2p session
|
{
|
||||||
GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete,
|
// yes it does
|
||||||
shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port);
|
switch (m_cmd)
|
||||||
} else if (m_UseUpstreamProxy) {
|
{
|
||||||
|
case CMD_CONNECT:
|
||||||
|
//make an i2p session
|
||||||
|
GetOwner()->CreateStream ( std::bind (&SOCKSHandler::HandleStreamRequestComplete,
|
||||||
|
shared_from_this(), std::placeholders::_1), m_address.dns.ToString(), m_port);
|
||||||
|
break;
|
||||||
|
case CMD_UDP:
|
||||||
|
{
|
||||||
|
// create UDP client tunnel
|
||||||
|
LogPrint (eLogInfo, "SOCKS: New UDP associate connection");
|
||||||
|
const auto& localEndpoint = ((SOCKSServer *)GetOwner ())->GetLocalEndpoint ();
|
||||||
|
m_UDPTunnel = std::make_unique<i2p::client::I2PUDPClientTunnel>("", addr,
|
||||||
|
boost::asio::ip::udp::endpoint (localEndpoint.address (), localEndpoint.port ()), // use proxy endpoint TODO: select UDP port
|
||||||
|
GetOwner ()->GetLocalDestination (), m_port, false, i2p::datagram::eDatagramV3);
|
||||||
|
boost::asio::post (GetOwner ()->GetService (), [this](void)
|
||||||
|
{
|
||||||
|
SocksRequestSuccess();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_UseUpstreamProxy)
|
||||||
// forward it to upstream proxy
|
// forward it to upstream proxy
|
||||||
ForwardSOCKS();
|
ForwardSOCKS();
|
||||||
} else {
|
else
|
||||||
// no upstream proxy
|
// no upstream proxy
|
||||||
SocksRequestFailed(SOCKS5_ADDR_UNSUP);
|
SocksRequestFailed(SOCKS5_ADDR_UNSUP);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
AsyncSockRead();
|
AsyncSockRead();
|
||||||
|
|
@ -648,10 +687,18 @@ namespace proxy
|
||||||
if (!ecode)
|
if (!ecode)
|
||||||
{
|
{
|
||||||
if (Kill()) return;
|
if (Kill()) return;
|
||||||
LogPrint (eLogInfo, "SOCKS: New I2PTunnel connection");
|
if (m_cmd == CMD_CONNECT)
|
||||||
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, m_stream);
|
{
|
||||||
GetOwner()->AddHandler (connection);
|
LogPrint (eLogInfo, "SOCKS: New I2PTunnel connection");
|
||||||
connection->I2PConnect (m_remaining_data,m_remaining_data_len);
|
auto connection = std::make_shared<i2p::client::I2PTunnelConnection>(GetOwner(), m_sock, m_stream);
|
||||||
|
GetOwner()->AddHandler (connection);
|
||||||
|
connection->I2PConnect (m_remaining_data,m_remaining_data_len);
|
||||||
|
}
|
||||||
|
else if (m_cmd == CMD_UDP && m_UDPTunnel)
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "SOCKS: Start UDP tunnel");
|
||||||
|
m_UDPTunnel->Start ();
|
||||||
|
}
|
||||||
Done(shared_from_this());
|
Done(shared_from_this());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,6 @@ namespace client
|
||||||
std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
|
std::vector<std::shared_ptr<DatagramSessionInfo> > GetSessions ();
|
||||||
|
|
||||||
bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
|
bool IsLocalDestination (const i2p::data::IdentHash & destination) const { return destination == m_LocalDest->GetIdentHash(); }
|
||||||
|
|
||||||
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
|
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDest; }
|
||||||
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest)
|
inline void SetLocalDestination (std::shared_ptr<ClientDestination> dest)
|
||||||
{
|
{
|
||||||
|
|
@ -155,7 +154,8 @@ namespace client
|
||||||
if (dest) dest->Acquire ();
|
if (dest) dest->Acquire ();
|
||||||
m_LocalDest = dest;
|
m_LocalDest = dest;
|
||||||
}
|
}
|
||||||
|
const boost::asio::ip::udp::endpoint& GetLocalEndpoint () const { return m_LocalEndpoint; };
|
||||||
|
|
||||||
void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
|
void ExpireStale (const uint64_t delta=I2P_UDP_SESSION_TIMEOUT);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue