Changes to be committed:
modified: cmd/pmomusic/main.go new file: internal/netutils/ip_detect.go new file: internal/netutils/list_all_ip.go modified: internal/soap/soap.go modified: internal/ssdp/responder.go modified: internal/ssdp/ssdp.go modified: internal/upnp/http.go new file: internal/upnp/server.go new file: internal/upnp/xml/AVTransport.xml new file: internal/upnp/xml/ConnectionManager.xml new file: internal/upnp/xml/RenderingControl.xml
This commit is contained in:
92
internal/netutils/ip_detect.go
Normal file
92
internal/netutils/ip_detect.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GuessLocalIP returns the best-guess local IP address usable for UPnP location,
|
||||
// in order of preference: eth0 > en* > wl* > any private, non-loopback IP.
|
||||
func GuessLocalIP() (string, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
type scoredIP struct {
|
||||
ip net.IP
|
||||
score int
|
||||
}
|
||||
|
||||
var candidates []scoredIP
|
||||
|
||||
for _, iface := range ifaces {
|
||||
// Skip interfaces that are down or loopback
|
||||
if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
// Skip non-IPv4 or non-private addresses
|
||||
if ip == nil || ip.IsLoopback() || ip.To4() == nil || !isPrivateIPv4(ip) {
|
||||
continue
|
||||
}
|
||||
|
||||
score := scoreInterfaceName(iface.Name)
|
||||
candidates = append(candidates, scoredIP{ip: ip, score: score})
|
||||
}
|
||||
}
|
||||
|
||||
if len(candidates) == 0 {
|
||||
return "", errors.New("no suitable local IP found")
|
||||
}
|
||||
|
||||
// Prefer interfaces with higher score
|
||||
sort.SliceStable(candidates, func(i, j int) bool {
|
||||
return candidates[i].score > candidates[j].score
|
||||
})
|
||||
|
||||
return candidates[0].ip.String(), nil
|
||||
}
|
||||
|
||||
func isPrivateIPv4(ip net.IP) bool {
|
||||
private := []string{
|
||||
"10.", "172.16.", "172.17.", "172.18.", "172.19.", "172.2", "192.168.",
|
||||
}
|
||||
ipStr := ip.String()
|
||||
for _, p := range private {
|
||||
if strings.HasPrefix(ipStr, p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func scoreInterfaceName(name string) int {
|
||||
switch {
|
||||
case name == "eth0":
|
||||
return 100
|
||||
case strings.HasPrefix(name, "en"):
|
||||
return 80
|
||||
case name == "wlan0" || strings.HasPrefix(name, "wl"):
|
||||
return 60
|
||||
default:
|
||||
return 10
|
||||
}
|
||||
}
|
||||
49
internal/netutils/list_all_ip.go
Normal file
49
internal/netutils/list_all_ip.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// ListAllIPs returns a map of interface names to their associated IPv4 addresses.
|
||||
func ListAllIPs() map[string][]string {
|
||||
result := make(map[string][]string)
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
result["error"] = []string{err.Error()}
|
||||
return result
|
||||
}
|
||||
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // Ignore down interfaces
|
||||
}
|
||||
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var ips []string
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
if ip == nil || ip.To4() == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ips = append(ips, ip.String())
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
result[iface.Name] = ips
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user