Skip to content

Commit

Permalink
Add i2p support (#873)
Browse files Browse the repository at this point in the history
* add i2p support

if using i2p wrapped daemon.

it would be nice to eventually add i2pd as an option as well.
  • Loading branch information
justinvforvendetta authored and marpme committed Feb 20, 2019
1 parent cd0ff29 commit b685824
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 5 deletions.
41 changes: 38 additions & 3 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
static const unsigned char pchOnionCat[] = {0xFD,0x87,0xD8,0x7E,0xEB,0x43};
static const unsigned char pchGarliCat[] = {0xFD,0x60,0xDB,0x4D,0xDD,0xB5};

// 0xFD + sha256("bitcoin")[0:5]
static const unsigned char g_internal_prefix[] = { 0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24 };
Expand Down Expand Up @@ -78,6 +79,15 @@ bool CNetAddr::SetSpecial(const std::string &strName)
}

}
if (strName.size()>11 && strName.substr(strName.size() - 11, 11) == ".oc.b32.i2p") {
std::vector<unsigned char> vchAddr = DecodeBase32(strName.substr(0, strName.size() - 11).c_str());
if (vchAddr.size() != 16-sizeof(pchGarliCat))
return false;
memcpy(ip, pchOnionCat, sizeof(pchGarliCat));
for (unsigned int i=0; i<16-sizeof(pchGarliCat); i++)
ip[i + sizeof(pchGarliCat)] = vchAddr[i];
return true;
}
return false;
}

Expand All @@ -104,7 +114,7 @@ bool CNetAddr::IsIPv4() const

bool CNetAddr::IsIPv6() const
{
return (!IsIPv4() && !IsTor() && !IsTorV3() && !IsInternal());
return (!IsIPv4() && !IsTor() && !IsI2P() && !IsTorV3() && !IsInternal());
}

bool CNetAddr::IsRFC1918() const
Expand Down Expand Up @@ -190,6 +200,11 @@ bool CNetAddr::IsTorV3() const
return usesTorV3 && (memcmp(ip, pchOnionCat, sizeof(pchOnionCat)) == 0);
}

bool CNetAddr::IsI2P() const
{
return (memcmp(ip, pchGarliCat, sizeof(pchGarliCat)) == 0);
}

bool CNetAddr::IsLocal() const
{
// IPv4 loopback
Expand Down Expand Up @@ -245,7 +260,7 @@ bool CNetAddr::IsValid() const

bool CNetAddr::IsRoutable() const
{
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && (!IsTor() && !IsTorV3())) || IsRFC4843() || IsLocal() || IsInternal());
return IsValid() && !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() || IsRFC6598() || IsRFC5737() || (IsRFC4193() && (!IsTor() && (!IsI2P()) && (!IsTorV3())) || IsRFC4843() || IsLocal() || IsInternal()));
}

bool CNetAddr::IsInternal() const
Expand All @@ -266,6 +281,9 @@ enum Network CNetAddr::GetNetwork() const

if (IsTor() || IsTorV3())
return NET_TOR;

if (IsI2P())
return NET_I2P;

return NET_IPV6;
}
Expand All @@ -274,8 +292,13 @@ std::string CNetAddr::ToStringIP() const
{
if (IsTor())
return EncodeBase32(&ip[6], 10) + ".onion";

if (IsI2P())
return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p";

if (IsTorV3())
return EncodeBase32(&ip[6], 35) + ".onion";

if (IsInternal())
return EncodeBase32(ip + sizeof(g_internal_prefix), sizeof(ip) - sizeof(g_internal_prefix)) + ".internal";
CService serv(*this, 0);
Expand Down Expand Up @@ -379,6 +402,12 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nClass = NET_TOR;
nStartByte = 6;
nBits = 4;
}
else if (IsI2P())
{
nClass = NET_I2P;
nStartByte = 6;
nBits = 4;
}
// for he.net, use /36 groups
else if (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 && GetByte(12) == 0x70)
Expand Down Expand Up @@ -460,6 +489,11 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
case NET_IPV4: return REACH_IPV4; // Tor users can connect to IPv4 as well
case NET_TOR: return REACH_PRIVATE;
}
case NET_I2P:
switch(ourNet) {
default: return REACH_DEFAULT;
case NET_I2P: return REACH_PRIVATE;
}
case NET_TEREDO:
switch(ourNet) {
default: return REACH_DEFAULT;
Expand All @@ -475,6 +509,7 @@ int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const
case NET_TEREDO: return REACH_TEREDO;
case NET_IPV6: return REACH_IPV6_WEAK;
case NET_IPV4: return REACH_IPV4;
case NET_I2P: return REACH_PRIVATE; // assume connections from unroutable addresses are
case NET_TOR: return REACH_PRIVATE; // either from Tor, or don't care about our address
}
}
Expand Down Expand Up @@ -582,7 +617,7 @@ std::string CService::ToStringPort() const

std::string CService::ToStringIPPort() const
{
if (IsIPv4() || IsTor() || IsTorV3() || IsInternal()) {
if (IsIPv4() || IsTor() || IsI2P() || IsTorV3() || IsInternal()) {
return ToStringIP() + ":" + ToStringPort();
} else {
return "[" + ToStringIP() + "]:" + ToStringPort();
Expand Down
6 changes: 4 additions & 2 deletions src/netaddress.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum Network
NET_IPV4,
NET_IPV6,
NET_TOR,
NET_I2P,
NET_INTERNAL,

NET_MAX,
Expand Down Expand Up @@ -57,9 +58,9 @@ class CNetAddr
*/
bool SetInternal(const std::string& name);

bool SetSpecial(const std::string &strName); // for Tor addresses
bool SetSpecial(const std::string &strName); // for Tor & i2p addresses
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor)
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/i2p)
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
bool IsRFC2544() const; // IPv4 inter-network communications (192.18.0.0/15)
bool IsRFC6598() const; // IPv4 ISP-level NAT (100.64.0.0/10)
Expand All @@ -74,6 +75,7 @@ class CNetAddr
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
bool IsTor() const;
bool IsI2P() const;
bool IsTorV3() const;
bool IsLocal() const;
bool IsRoutable() const;
Expand Down
2 changes: 2 additions & 0 deletions src/netbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ enum Network ParseNetwork(std::string net) {
if (net == "ipv4") return NET_IPV4;
if (net == "ipv6") return NET_IPV6;
if (net == "tor" || net == "onion") return NET_TOR;
if (net == "i2p") return NET_I2P;
return NET_UNROUTABLE;
}

Expand All @@ -52,6 +53,7 @@ std::string GetNetworkName(enum Network net) {
case NET_IPV4: return "ipv4";
case NET_IPV6: return "ipv6";
case NET_TOR: return "onion";
case NET_I2P: return "i2p";
default: return "";
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/qt/forms/optionsdialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,29 @@
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="proxyReachI2p">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Shows if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="proxyReachI2pLabel">
<property name="text">
<string>i2p</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2_Network">
Expand Down
5 changes: 5 additions & 0 deletions src/qt/optionsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,11 @@ void OptionsDialog::updateDefaultProxyNets()
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);

model->node().getProxy(NET_I2P, proxy);
strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachI2p->setChecked(true) : ui->proxyReachI2p->setChecked(false);
}

ProxyAddressValidator::ProxyAddressValidator(QObject *parent) :
Expand Down

0 comments on commit b685824

Please sign in to comment.