From 91c6755bb16747f88f23ac3fcb79d033deef5c93 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Mon, 3 Aug 2026 16:48:29 +0200 Subject: [PATCH] network detection better. --- info.rkt | 2 +- network.rkt | 69 +++++++++++++++++++++++++++++++++--------- scribblings/main.scrbl | 8 ++--- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/info.rkt b/info.rkt index abeed9d..2c40b67 100644 --- a/info.rkt +++ b/info.rkt @@ -1,7 +1,7 @@ #lang info (define pkg-authors '(hnmdijkema)) -(define version "0.1.6") +(define version "0.1.7") (define license 'MIT) (define collection "racket-upnp") (define pkg-desc "racket-upnp - UpnP and DLNA for racket") diff --git a/network.rkt b/network.rkt index a6f20fe..cb57be8 100644 --- a/network.rkt +++ b/network.rkt @@ -2,32 +2,73 @@ ;; Network helpers used by UPnP and SSDP. -(require racket/udp +(require racket/list + racket/string + racket/udp simple-log) (provide upnp-default-ipv4-address) (sl-def-log upnp-network) -(define ssdp-multicast-address "239.255.255.250") -(define ssdp-multicast-port 1900) +;; These destinations are only used to make the operating system select its +;; normal outbound IPv4 route. UDP connect does not transmit a datagram. +(define route-probes + '(("1.1.1.1" 53) + ("8.8.8.8" 53))) -;; Return the local IPv4 address selected by the operating system for traffic -;; to the SSDP multicast destination. No datagram is transmitted. -(define (upnp-default-ipv4-address) - (let ([socket (udp-open-socket ssdp-multicast-address - ssdp-multicast-port)]) +(define (loopback-ipv4-address? address) + (string-prefix? address "127.")) + +(define (usable-ipv4-address? address) + (and (string? address) + (not (string=? address "0.0.0.0")) + (not (loopback-ipv4-address? address)))) + +(define (local-address-for destination port) + (let ([socket (udp-open-socket destination port)]) (dynamic-wind void (lambda () - (udp-connect! socket ssdp-multicast-address ssdp-multicast-port) + (udp-connect! socket destination port) (define-values (local-address local-port remote-address remote-port) (udp-addresses socket #t)) - (dbg-upnp-network - "Selected UPnP IPv4 address ~a for SSDP destination ~a:~a" - local-address - ssdp-multicast-address - ssdp-multicast-port) local-address) (lambda () (udp-close socket))))) + +;; Return the local non-loopback IPv4 address selected by the operating system +;; for normal outbound traffic. This is also the interface normally suitable +;; for SSDP multicast. No datagram is transmitted. +(define (upnp-default-ipv4-address) + (or + (for/or ([probe (in-list route-probes)]) + (define destination (first probe)) + (define port (second probe)) + (with-handlers + ([exn:fail? + (lambda (exception) + (dbg-upnp-network + "Could not determine local IPv4 address using route to ~a:~a: ~a" + destination + port + (exn-message exception)) + #f)]) + (define address (local-address-for destination port)) + (cond + [(usable-ipv4-address? address) + (dbg-upnp-network + "Selected UPnP IPv4 address ~a using route to ~a:~a" + address + destination + port) + address] + [else + (dbg-upnp-network + "Rejected unusable local IPv4 address ~a selected for route to ~a:~a" + address + destination + port) + #f]))) + (error 'upnp-default-ipv4-address + "could not determine a non-loopback IPv4 address"))) diff --git a/scribblings/main.scrbl b/scribblings/main.scrbl index 837f717..243aeb4 100644 --- a/scribblings/main.scrbl +++ b/scribblings/main.scrbl @@ -14,10 +14,10 @@ interface. @section{Discovering devices} @defproc[(upnp-default-ipv4-address) string?]{ -Returns the local IPv4 address selected by the operating system for traffic to -the SSDP multicast destination @tt{239.255.255.250:1900}. No datagram is sent. -This is normally the interface through which UPnP devices on the local network -can be reached. +Returns a non-loopback local IPv4 address selected by the operating system for +normal outbound IPv4 traffic. No datagram is sent. The selected address is +normally also the interface through which SSDP multicast should be sent. +Loopback and wildcard addresses are rejected. }