Skip to content

Align UDP #recvfrom usage with the stdlib#21562

Open
zeroSteiner wants to merge 5 commits into
rapid7:masterfrom
zeroSteiner:fix/udp/recvfrom-stdlib
Open

Align UDP #recvfrom usage with the stdlib#21562
zeroSteiner wants to merge 5 commits into
rapid7:masterfrom
zeroSteiner:fix/udp/recvfrom-stdlib

Conversation

@zeroSteiner

@zeroSteiner zeroSteiner commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Description

This requires the changes from rapid7/rex-socket#83 and incoporates them into the Metasploit framework to align the usage of #recvfrom on UDP sockets to behave the same as the standard library. This has the strong benefit of ensuring that developers do not need to worry about their socket being UDPSocket or Rex::Socket::Udp which by extension makes Metasploit compatible with libraries that need UDP sockets that have no knowledge of Rex.

There are three issues with Rex's #recvfrom vs the standard library

  1. The arguments are different; the size should should be a required argument and the second parameter should be flags, not a timeout.
  2. The shape of the return value is different, the standard library returns the address info as an array.
  3. The standard library's method is blocking and does not support a timeout, the Rex version took a timeout parameter where flags should have been.

Breaking Changes

rapid7/rex-socket#83 is a breaking change. This PR brings framework inline so that nothing breakes on this side. There are no user-facing breaking changes.

Reviewer Notes

It's not really practical to re-test every single module that uses UDP. That's the main reason that #timed_recvfrom was added, so methods could just be changed from #recvfrom -> #timed_recvfrom and not worry about points 1 and 3 from the list of issues above in the description section.

Verification Steps

    • Make sure the tests pass

I ran through multiple tests of the most important modules which covered the main patterns. The new #timed_recvfrom is used in place of the old #recvfrom where there was an expected timeout but the return value is aligned with the standard libraries #recvfrom.

Things I tested include

  • auxiliary/scanner/snmp/snmp_login
  • auxiliary/gather/enum_dns
  • auxiliary/scanner/ntp/timeroast

Test Evidence

msf auxiliary(gather/enum_dns) > use auxiliary/scanner/snmp/snmp_login 
msf auxiliary(scanner/snmp/snmp_login) > set RHOSTS 192.168.250.0/24
RHOSTS => 192.168.250.0/24
msf auxiliary(scanner/snmp/snmp_login) > set THREADS 10
THREADS => 10
msf auxiliary(scanner/snmp/snmp_login) > run
[+] 192.168.250.7:161 - Login Successful: internal (Access level: read-write); Proof (sysDescr.0): Brother NC-8800w, Firmware Ver.Z  ,MID 8C5-K8JFID 2
[+] 192.168.250.7:161 - Login Successful: public (Access level: read-write); Proof (sysDescr.0): Brother NC-8800w, Firmware Ver.Z  ,MID 8C5-K8JFID 2
[*] Scanned  29 of 256 hosts (11% complete)
[*] Scanned  52 of 256 hosts (20% complete)
[*] Scanned  77 of 256 hosts (30% complete)
[*] Scanned 103 of 256 hosts (40% complete)
[*] Error: 192.168.250.119: Errno::ECONNREFUSED Connection refused - recvfrom(2)
[*] Scanned 128 of 256 hosts (50% complete)
[*] Scanned 154 of 256 hosts (60% complete)
[*] Scanned 181 of 256 hosts (70% complete)
[*] Scanned 205 of 256 hosts (80% complete)
[*] Scanned 232 of 256 hosts (90% complete)
[*] Scanned 256 of 256 hosts (100% complete)
[*] Auxiliary module execution completed
msf auxiliary(scanner/snmp/snmp_login) > use auxiliary/gather/enum_dns 
msf auxiliary(gather/enum_dns) > show options 

Module options (auxiliary/gather/enum_dns):

   Name         Current Setting                                                            Required  Description
   ----         ---------------                                                            --------  -----------
   DOMAIN       home.lan                                                                   yes       The target domain
   ENUM_A       true                                                                       yes       Enumerate DNS A record
   ENUM_AXFR    true                                                                       yes       Initiate a zone transfer against each NS record
   ENUM_BRT     false                                                                      yes       Brute force subdomains and hostnames via the supplied wordlist
   ENUM_CNAME   true                                                                       yes       Enumerate DNS CNAME record
   ENUM_MX      true                                                                       yes       Enumerate DNS MX record
   ENUM_NS      true                                                                       yes       Enumerate DNS NS record
   ENUM_RVL     false                                                                      yes       Reverse lookup a range of IP addresses
   ENUM_SOA     true                                                                       yes       Enumerate DNS SOA record
   ENUM_SRV     true                                                                       yes       Enumerate the most common SRV records
   ENUM_TLD     false                                                                      yes       Perform a TLD expansion by replacing the TLD with the IANA TLD list
   ENUM_TXT     true                                                                       yes       Enumerate DNS TXT record
   IPRANGE                                                                                 no        The target address range or CIDR identifier
   NS           192.168.250.4                                                              no        Specify the nameservers to use for queries, space separated
   Proxies                                                                                 no        A proxy chain of format type:host:port[,type:host:port][...]. Supported proxies: http, sapni, socks4, socks5, socks5h
   RPORT        53                                                                         yes       The target port (TCP)
   SEARCHLIST                                                                              no        DNS domain search list, comma separated
   STOP_WLDCRD  false                                                                      yes       Stops bruteforce enumeration if wildcard resolution is detected
   THREADS      1                                                                          no        Threads for ENUM_BRT
   WORDLIST     /home/smcintyre/Projects/metasploit-framework/data/wordlists/namelist.txt  no        Wordlist of subdomains


View the full module info with the info, or info -d command.

msf auxiliary(gather/enum_dns) > run
[*] Attempting DNS AXFR for home.lan from 192.168.250.4
^C[-] Stopping running against current target...
[*] Control-C again to force quit all targets.
^C[-] Auxiliary interrupted by the console user
[*] Auxiliary module execution completed
msf auxiliary(gather/enum_dns) > est ENUM_AXFR false
[-] Unknown command: est. Run the help command for more details.
msf auxiliary(gather/enum_dns) > set ENUM_AXFR false
ENUM_AXFR => false
msf auxiliary(gather/enum_dns) > run
[*] Querying DNS CNAME records for home.lan
[*] Querying DNS NS records for home.lan
[+] home.lan NS: dns-aux.home.lan
[+] home.lan NS: dns-pri.home.lan
[*] Querying DNS MX records for home.lan
[*] Querying DNS SOA records for home.lan
[+] home.lan SOA: dns.home.lan
[*] Querying DNS TXT records for home.lan
[*] Querying DNS SRV records for home.lan
[*] Auxiliary module execution completed
msf auxiliary(gather/enum_dns) > use auxiliary/scanner/ntp/timeroast 
msf auxiliary(scanner/ntp/timeroast) > show options 

Module options (auxiliary/scanner/ntp/timeroast):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   DELAY    20               yes       The delay in milliseconds between attempts.
   RHOSTS                    yes       The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html
   RIDS                      yes       The RIDs to enumerate (e.g. 1000-2000).
   RPORT    123              yes       The target port (UDP)
   THREADS  1                yes       The number of concurrent threads (max one per host)
   TIMEOUT  5                yes       The timeout in seconds to wait at the end for replies.


View the full module info with the info, or info -d command.

msf auxiliary(scanner/ntp/timeroast) > set RHOSTS 192.168.159.10
RHOSTS => 192.168.159.10
msf auxiliary(scanner/ntp/timeroast) > set RIDS 1000-2000
RIDS => 1000-2000
msf auxiliary(scanner/ntp/timeroast) > run
[+] Hash for RID: 1001 - 1001:$sntp-ms$2ce861b855afa3d3e7a1954e4806da26$1c0100e900000000000a00264c4f434ceddaa204c19641f60000000000000000eddaa237ad9e3864eddaa237ad9e8fa2

AI Usage Disclosure

I was assisted by Claude Opus during this development.

Pre-Submission Checklist

  • Ran rubocop on new files with no new offenses (net new files only)
  • Ran msftidy on changed module files with no new offenses (modules only)
  • Ran msftidy_docs on changed documentation files with no new offenses (documentation files only)
  • Included a corresponding documentation markdown file in documentation/modules (new modules only)
  • No sensitive information (IP addresses, credentials, API keys, hashes) in code or documentation
  • Tested on the target environment specified in the Environment section above
  • Included RSpec tests for library changes (encouraged for lib/ changes)
  • Read the CONTRIBUTING.md and module acceptance guidelines

@github-actions

Copy link
Copy Markdown

Thanks for your pull request! As part of our landing process, we manually verify that all modules work as expected.

We've added the additional-testing-required label to indicate that additional testing is required before this pull request can be merged.
For maintainers, this means visiting here.

zeroSteiner and others added 3 commits June 11, 2026 12:12
Temporarily source rex-socket from the fix/udp/recvfrom-api branch so the
framework picks up the stdlib-aligned #recvfrom and the new #timed_recvfrom.
Revert this commit once rex-socket is released to rubygems.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This pulls in changes from rapid7/rex-socket#83 which aligns #recvfrom
to match the signature and behavior of the standard library in regards
to it's arguments, return type and how it handles timeouts. The
historical usage of #recvfrom was a timed read and can now be replaced
with #timed_recvfrom.
@zeroSteiner zeroSteiner force-pushed the fix/udp/recvfrom-stdlib branch 5 times, most recently from f254716 to 22ba2eb Compare June 11, 2026 19:16
@zeroSteiner zeroSteiner force-pushed the fix/udp/recvfrom-stdlib branch from a050b7f to e707971 Compare June 11, 2026 21:02
@smcintyre-r7 smcintyre-r7 marked this pull request as ready for review June 15, 2026 15:36
def recvfrom_nonblock(length, flags = 0)
data = super(length, flags)[0]
sockaddr = super(length, flags)[0]
sockaddr = super(MAX_SOCKADDR_LENGTH, flags)[0]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes a different bug. What was going on here is that the socket address was being read from the peer (the other end of the socket pair), and the length argument was used for it, which caused a failure when the length wasn't sufficient for the address. The second read should always be for enough data to get the whole address.

@smcintyre-r7 smcintyre-r7 moved this from Todo to Ready in Metasploit Kanban Jun 15, 2026
@jenkins-eks-metasploit

Copy link
Copy Markdown

Additional test pipeline started ⌛
Note: build results only accessible to maintainers.

@jenkins-eks-metasploit

Copy link
Copy Markdown

Pipeline results available

Slice summary:

  • Test slice 1 - 🟢
  • Test slice 2 - 🔴
  • Test slice 3 - 🟢
  • Test slice 4 - 🟢

Note: build results only accessible to maintainers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

3 participants