Rework tor exceptions to be more useful (#4854)

This commit is contained in:
Chris Stewart 2022-10-23 08:12:59 -05:00 committed by GitHub
parent 89a4c9e13e
commit 63b05e398a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 39 deletions

View file

@ -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)
Success(socket)
case 0x03 => case 0x03 =>
val len = data(4) val len = data(4)
val start = 5 val start = 5
val end = start + len val end = start + len
val domain = data.slice(start, end).utf8String val domain = data.slice(start, end).utf8String
val port = data(end).toInt << 8 | data(end + 1) val port = data(end).toInt << 8 | data(end + 1)
new InetSocketAddress(domain, port) val socket = new InetSocketAddress(domain, port)
Success(socket)
case 0x04 => case 0x04 =>
val ip = Array.ofDim[Byte](16) val ip = Array.ofDim[Byte](16)
data.copyToArray(ip, 4, 4 + ip.length) data.copyToArray(ip, 4, 4 + ip.length)
val port = data(4 + ip.length).toInt << 8 | data(4 + ip.length + 1) val port = data(4 + ip.length).toInt << 8 | data(4 + ip.length + 1)
val socket =
new InetSocketAddress(InetAddress.getByAddress(ip), port) new InetSocketAddress(InetAddress.getByAddress(ip), port)
case b => throw Socks5Error(s"Unrecognized address type $b") 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(

View 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
}
}