mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Rework tor exceptions to be more useful (#4854)
This commit is contained in:
parent
89a4c9e13e
commit
63b05e398a
2 changed files with 116 additions and 39 deletions
|
@ -73,7 +73,8 @@ class Socks5Connection(
|
||||||
context.parent ! Socks5Connected(connectedAddress)
|
context.parent ! Socks5Connected(connectedAddress)
|
||||||
isConnected = true
|
isConnected = true
|
||||||
case Failure(err) =>
|
case Failure(err) =>
|
||||||
logger.error(s"Tor connection request failed to $target", err)
|
logger.error(
|
||||||
|
s"Tor connection request failed to $target errMsg=${err.toString}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -125,18 +126,6 @@ object Socks5Connection {
|
||||||
val NoAuth: Byte = 0x00
|
val NoAuth: Byte = 0x00
|
||||||
val PasswordAuth: Byte = 0x02
|
val PasswordAuth: Byte = 0x02
|
||||||
|
|
||||||
val connectErrors: Map[Byte, String] = Map[Byte, String](
|
|
||||||
(0x00, "Request granted"),
|
|
||||||
(0x01, "General failure"),
|
|
||||||
(0x02, "Connection not allowed by ruleset"),
|
|
||||||
(0x03, "Network unreachable"),
|
|
||||||
(0x04, "Host unreachable"),
|
|
||||||
(0x05, "Connection refused by destination host"),
|
|
||||||
(0x06, "TTL expired"),
|
|
||||||
(0x07, "Command not supported / protocol error"),
|
|
||||||
(0x08, "Address type not supported")
|
|
||||||
)
|
|
||||||
|
|
||||||
def socks5Greeting(passwordAuth: Boolean): ByteString = ByteString(
|
def socks5Greeting(passwordAuth: Boolean): ByteString = ByteString(
|
||||||
0x05, // SOCKS version
|
0x05, // SOCKS version
|
||||||
0x01, // number of authentication methods supported
|
0x01, // number of authentication methods supported
|
||||||
|
@ -213,34 +202,39 @@ object Socks5Connection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def parseConnectedAddress(data: ByteString): InetSocketAddress = {
|
def tryParseConnectedAddress(data: ByteString): Try[InetSocketAddress] = {
|
||||||
if (data(0) != 0x05) {
|
if (data(0) != 0x05) {
|
||||||
throw Socks5Error("Invalid proxy version")
|
throw Socks5Error("Invalid proxy version")
|
||||||
} else {
|
} else {
|
||||||
val status = data(1)
|
val status = data(1)
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
val errMsg =
|
val connectionError = TorConnectionError.fromByte(status)
|
||||||
connectErrors.getOrElse(status, s"Unknown SOCKS5 error $status")
|
Failure(connectionError.exn)
|
||||||
throw Socks5Error(errMsg + s" data=$data")
|
} else {
|
||||||
}
|
data(3) match {
|
||||||
data(3) match {
|
case 0x01 =>
|
||||||
case 0x01 =>
|
val ip = Array(data(4), data(5), data(6), data(7))
|
||||||
val ip = Array(data(4), data(5), data(6), data(7))
|
val port = data(8).toInt << 8 | data(9)
|
||||||
val port = data(8).toInt << 8 | data(9)
|
val socket =
|
||||||
new InetSocketAddress(InetAddress.getByAddress(ip), port)
|
new InetSocketAddress(InetAddress.getByAddress(ip), port)
|
||||||
case 0x03 =>
|
Success(socket)
|
||||||
val len = data(4)
|
case 0x03 =>
|
||||||
val start = 5
|
val len = data(4)
|
||||||
val end = start + len
|
val start = 5
|
||||||
val domain = data.slice(start, end).utf8String
|
val end = start + len
|
||||||
val port = data(end).toInt << 8 | data(end + 1)
|
val domain = data.slice(start, end).utf8String
|
||||||
new InetSocketAddress(domain, port)
|
val port = data(end).toInt << 8 | data(end + 1)
|
||||||
case 0x04 =>
|
val socket = new InetSocketAddress(domain, port)
|
||||||
val ip = Array.ofDim[Byte](16)
|
Success(socket)
|
||||||
data.copyToArray(ip, 4, 4 + ip.length)
|
case 0x04 =>
|
||||||
val port = data(4 + ip.length).toInt << 8 | data(4 + ip.length + 1)
|
val ip = Array.ofDim[Byte](16)
|
||||||
new InetSocketAddress(InetAddress.getByAddress(ip), port)
|
data.copyToArray(ip, 4, 4 + ip.length)
|
||||||
case b => throw Socks5Error(s"Unrecognized address type $b")
|
val port = data(4 + ip.length).toInt << 8 | data(4 + ip.length + 1)
|
||||||
|
val socket =
|
||||||
|
new InetSocketAddress(InetAddress.getByAddress(ip), port)
|
||||||
|
Success(socket)
|
||||||
|
case b => Failure(Socks5Error(s"Unrecognized address type $b"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,9 +244,6 @@ object Socks5Connection {
|
||||||
|
|
||||||
def tryParseAuth(data: ByteString): Try[Boolean] = Try(parseAuth(data))
|
def tryParseAuth(data: ByteString): Try[Boolean] = Try(parseAuth(data))
|
||||||
|
|
||||||
def tryParseConnectedAddress(data: ByteString): Try[InetSocketAddress] = Try(
|
|
||||||
parseConnectedAddress(data))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Socks5ProxyParams(
|
case class Socks5ProxyParams(
|
||||||
|
|
86
tor/src/main/scala/org/bitcoins/tor/TorConnectionError.scala
Normal file
86
tor/src/main/scala/org/bitcoins/tor/TorConnectionError.scala
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
package org.bitcoins.tor
|
||||||
|
|
||||||
|
sealed trait TorConnectionError {
|
||||||
|
def prefix: Byte
|
||||||
|
|
||||||
|
def exn: RuntimeException = new RuntimeException(toString)
|
||||||
|
}
|
||||||
|
|
||||||
|
object TorConnectionError {
|
||||||
|
|
||||||
|
val connectErrors: Map[Byte, String] = Map[Byte, String](
|
||||||
|
(0x00, "Request granted"),
|
||||||
|
(0x01, "General failure"),
|
||||||
|
(0x02, "Connection not allowed by ruleset"),
|
||||||
|
(0x03, "Network unreachable"),
|
||||||
|
(0x04, "Host unreachable"),
|
||||||
|
(0x05, "Connection refused by destination host"),
|
||||||
|
(0x06, "TTL expired"),
|
||||||
|
(0x07, "Command not supported / protocol error"),
|
||||||
|
(0x08, "Address type not supported")
|
||||||
|
)
|
||||||
|
|
||||||
|
private val all: Vector[TorConnectionError] = Vector(
|
||||||
|
RequestGranted,
|
||||||
|
GeneralFailure,
|
||||||
|
ConnectionNotAllowed,
|
||||||
|
NetworkUnreachable,
|
||||||
|
HostUnreachable,
|
||||||
|
ConnectionRefusedByDestination,
|
||||||
|
TTLExpired,
|
||||||
|
CommandNotSupportedOrProtocolError,
|
||||||
|
AddressTypeNotSupported
|
||||||
|
)
|
||||||
|
|
||||||
|
def fromByte(byte: Byte): TorConnectionError = {
|
||||||
|
fromByteOpt(byte) match {
|
||||||
|
case Some(err) => err
|
||||||
|
case None =>
|
||||||
|
sys.error(s"Could not find tor connection error by prefix=$byte")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def fromByteOpt(byte: Byte): Option[TorConnectionError] = {
|
||||||
|
all.find(_.prefix == byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
case object RequestGranted extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object GeneralFailure extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 1.toByte
|
||||||
|
|
||||||
|
override def toString: String =
|
||||||
|
s"General failure, this likely means tor timed out when trying to connect. Try using telnet to reproduce error."
|
||||||
|
}
|
||||||
|
|
||||||
|
case object ConnectionNotAllowed extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x02.toByte
|
||||||
|
override val toString: String = "Connection not allowed by ruleset"
|
||||||
|
}
|
||||||
|
|
||||||
|
case object NetworkUnreachable extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x03.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object HostUnreachable extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x04.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object ConnectionRefusedByDestination extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x05.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object TTLExpired extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x06.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object CommandNotSupportedOrProtocolError extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x07.toByte
|
||||||
|
}
|
||||||
|
|
||||||
|
case object AddressTypeNotSupported extends TorConnectionError {
|
||||||
|
override val prefix: Byte = 0x08.toByte
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue