forked from rapid7/metasploit-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Land rapid7#10102, SOCKS5 updates for BIND, parsing specs, refactoring
- Loading branch information
Showing
8 changed files
with
658 additions
and
671 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
# -*- coding: binary -*- | ||
|
||
require 'bindata' | ||
require 'rex/socket' | ||
|
||
module Rex | ||
module Proto | ||
module Proxy | ||
|
||
module Socks5 | ||
SOCKS_VERSION = 5 | ||
|
||
# | ||
# Mixin for socks5 packets to include an address field. | ||
# | ||
module Address | ||
ADDRESS_TYPE_IPV4 = 1 | ||
ADDRESS_TYPE_DOMAINNAME = 3 | ||
ADDRESS_TYPE_IPV6 = 4 | ||
|
||
def address | ||
addr = address_array.to_ary.pack('C*') | ||
if address_type == ADDRESS_TYPE_IPV4 || address_type == ADDRESS_TYPE_IPV6 | ||
addr = Rex::Socket.addr_ntoa(addr) | ||
end | ||
addr | ||
end | ||
|
||
def address=(value) | ||
if Rex::Socket.is_ipv4?(value) | ||
address_type.assign(ADDRESS_TYPE_IPV4) | ||
domainname_length.assign(0) | ||
value = Rex::Socket.addr_aton(value) | ||
elsif Rex::Socket.is_ipv6?(value) | ||
address_type.assign(ADDRESS_TYPE_IPV6) | ||
domainname_length.assign(0) | ||
value = Rex::Socket.addr_aton(value) | ||
else | ||
address_type.assign(ADDRESS_TYPE_DOMAINNAME) | ||
domainname_length.assign(value.length) | ||
end | ||
address_array.assign(value.unpack('C*')) | ||
end | ||
|
||
def address_length | ||
case address_type | ||
when ADDRESS_TYPE_IPV4 | ||
4 | ||
when ADDRESS_TYPE_DOMAINNAME | ||
domainname_length | ||
when ADDRESS_TYPE_IPV6 | ||
16 | ||
else | ||
0 | ||
end | ||
end | ||
end | ||
|
||
class AuthRequestPacket < BinData::Record | ||
endian :big | ||
|
||
uint8 :version, :initial_value => SOCKS_VERSION | ||
uint8 :supported_methods_length | ||
array :supported_methods, :type => :uint8, :initial_length => :supported_methods_length | ||
end | ||
|
||
class AuthResponsePacket < BinData::Record | ||
endian :big | ||
|
||
uint8 :version, :initial_value => SOCKS_VERSION | ||
uint8 :chosen_method | ||
end | ||
|
||
class Packet < BinData::Record | ||
include Address | ||
endian :big | ||
hide :reserved, :domainname_length | ||
|
||
uint8 :version, :initial_value => SOCKS_VERSION | ||
uint8 :command | ||
uint8 :reserved | ||
uint8 :address_type | ||
uint8 :domainname_length, :onlyif => lambda { address_type == ADDRESS_TYPE_DOMAINNAME } | ||
array :address_array, :type => :uint8, :initial_length => lambda { address_length } | ||
uint16 :port | ||
end | ||
|
||
class RequestPacket < Packet | ||
end | ||
|
||
class ResponsePacket < Packet | ||
end | ||
|
||
class UdpPacket < BinData::Record | ||
include Address | ||
endian :big | ||
hide :reserved, :domainname_length | ||
|
||
uint16 :reserved | ||
uint8 :frag | ||
uint8 :address_type | ||
uint8 :domainname_length, :onlyif => lambda { address_type == ADDRESS_TYPE_DOMAINNAME } | ||
array :address_array, :type => :uint8, :initial_length => lambda { address_length } | ||
uint16 :port | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# -*- coding: binary -*- | ||
|
||
require 'thread' | ||
require 'rex/logging' | ||
require 'rex/socket' | ||
require 'rex/proto/proxy/socks5/server_client' | ||
|
||
module Rex | ||
module Proto | ||
module Proxy | ||
|
||
module Socks5 | ||
# | ||
# A SOCKS5 proxy server. | ||
# | ||
class Server | ||
# | ||
# Create a new SOCKS5 server. | ||
# | ||
def initialize(opts={}) | ||
@opts = { 'ServerHost' => '0.0.0.0', 'ServerPort' => 1080 } | ||
@opts = @opts.merge(opts) | ||
@server = nil | ||
@clients = ::Array.new | ||
@running = false | ||
@server_thread = nil | ||
end | ||
|
||
# | ||
# Check if the server is running. | ||
# | ||
def is_running? | ||
return @running | ||
end | ||
|
||
# | ||
# Start the SOCKS5 server. | ||
# | ||
def start | ||
begin | ||
# create the servers main socket (ignore the context here because we don't want a remote bind) | ||
@server = Rex::Socket::TcpServer.create('LocalHost' => @opts['ServerHost'], 'LocalPort' => @opts['ServerPort']) | ||
# signal we are now running | ||
@running = true | ||
# start the servers main thread to pick up new clients | ||
@server_thread = Rex::ThreadFactory.spawn("SOCKS5ProxyServer", false) do | ||
while @running | ||
begin | ||
# accept the client connection | ||
sock = @server.accept | ||
# and fire off a new client instance to handle it | ||
ServerClient.new(self, sock, @opts).start | ||
rescue | ||
wlog("SOCKS5.start - server_thread - #{$!}") | ||
end | ||
end | ||
end | ||
rescue | ||
wlog("SOCKS5.start - #{$!}") | ||
return false | ||
end | ||
return true | ||
end | ||
|
||
# | ||
# Block while the server is running. | ||
# | ||
def join | ||
@server_thread.join if @server_thread | ||
end | ||
|
||
# | ||
# Stop the SOCKS5 server. | ||
# | ||
def stop | ||
if @running | ||
# signal we are no longer running | ||
@running = false | ||
# stop any clients we have (create a new client array as client.stop will delete from @clients) | ||
clients = @clients.dup | ||
clients.each do | client | | ||
client.stop | ||
end | ||
# close the server socket | ||
@server.close if @server | ||
# if the server thread did not terminate gracefully, kill it. | ||
@server_thread.kill if @server_thread and @server_thread.alive? | ||
end | ||
return !@running | ||
end | ||
|
||
def add_client(client) | ||
@clients << client | ||
end | ||
|
||
def remove_client(client) | ||
@clients.delete(client) | ||
end | ||
|
||
attr_reader :opts | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.