From acfb1beb4e150787d40745bbbc0b2d26e941fc1c Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 29 Jun 2026 18:02:49 -0400 Subject: [PATCH 1/3] Add specs for handling a 0 LocalPort in the local comm --- spec/rex/socket/comm/local_spec.rb | 37 ++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/rex/socket/comm/local_spec.rb b/spec/rex/socket/comm/local_spec.rb index d825660..fa8fdbe 100644 --- a/spec/rex/socket/comm/local_spec.rb +++ b/spec/rex/socket/comm/local_spec.rb @@ -108,6 +108,43 @@ end end + describe 'LocalPort 0 assignment' do + context 'when creating a TCP server bound to port 0' do + it 'updates localport to the OS-assigned port' do + params = Rex::Socket::Parameters.new( + 'Proto' => 'tcp', + 'Server' => true, + 'LocalHost' => '127.0.0.1', + 'LocalPort' => 0 + ) + sock = described_class.create(params) + begin + expect(sock.localport).to be > 0 + expect(sock.localport).to eq(sock.local_address.ip_port) + ensure + sock.close + end + end + end + + context 'when creating a UDP socket bound to port 0' do + it 'updates localport to the OS-assigned port' do + params = Rex::Socket::Parameters.new( + 'Proto' => 'udp', + 'LocalHost' => '127.0.0.1', + 'LocalPort' => 0 + ) + sock = described_class.create(params) + begin + expect(sock.localport).to be > 0 + expect(sock.localport).to eq(sock.local_address.ip_port) + ensure + sock.close + end + end + end + end + describe 'Interface option' do context 'when Interface is set and a proxy is also configured' do it 'raises Rex::BindFailed before creating a socket' do From bed6e203cb88dfe350a2144471f8d07d40f1beb0 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Mon, 29 Jun 2026 18:03:30 -0400 Subject: [PATCH 2/3] Propagate the OS-assigned port --- lib/rex/socket/comm/local.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/rex/socket/comm/local.rb b/lib/rex/socket/comm/local.rb index df2c754..f427863 100644 --- a/lib/rex/socket/comm/local.rb +++ b/lib/rex/socket/comm/local.rb @@ -273,10 +273,11 @@ def self.create_by_type(param, type, proto = 0) end sock.bind(Rex::Socket.to_sockaddr(ip, param.localport)) - rescue ::Errno::EADDRNOTAVAIL,::Errno::EADDRINUSE sock.close raise Rex::BindFailed.new(param.localhost, param.localport), caller + else + param.localport = sock.local_address.ip_port end end From a6e3dc7d5f377ee1a20fd14d78be6b524e296ebf Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 30 Jun 2026 15:00:16 -0400 Subject: [PATCH 3/3] Update specs --- lib/rex/socket/proxies.rb | 1 + spec/rex/socket/comm/local_spec.rb | 2 ++ 2 files changed, 3 insertions(+) diff --git a/lib/rex/socket/proxies.rb b/lib/rex/socket/proxies.rb index e69c878..feb309f 100644 --- a/lib/rex/socket/proxies.rb +++ b/lib/rex/socket/proxies.rb @@ -1,4 +1,5 @@ # -*- coding: binary -*- +require 'uri' module Rex module Socket diff --git a/spec/rex/socket/comm/local_spec.rb b/spec/rex/socket/comm/local_spec.rb index fa8fdbe..ac10c53 100644 --- a/spec/rex/socket/comm/local_spec.rb +++ b/spec/rex/socket/comm/local_spec.rb @@ -7,6 +7,7 @@ let(:proto) { ::Socket::IPPROTO_TCP } let(:params) { Rex::Socket::Parameters.new({ 'PeerHost' => '192.0.2.1', 'PeerPort' => 1234 }) } let(:sock) { RSpec::Mocks::Double.new('socket') } + let(:local_address) { RSpec::Mocks::Double.new('local address', ip_port: 49152) } before(:each) do allow(Rex::Socket).to receive(:support_ipv6?).with(no_args).and_return(true) @@ -14,6 +15,7 @@ allow(sock).to receive(:setsockopt).with(any_args) allow(sock).to receive(:bind).with(any_args) allow(sock).to receive(:connect).with(any_args).and_return(nil) + allow(sock).to receive(:local_address).with(no_args).and_return(local_address) end it 'creates an IPv4 socket' do