Skip to content

Commit b73f3ec

Browse files
authored
server: Parse IPs properly for getRemoteAddr (#3790)
This supports IPv6 addresses which have multiple colons like [::1]:57579
1 parent 9c49266 commit b73f3ec

File tree

2 files changed

+57
-1
lines changed

2 files changed

+57
-1
lines changed

server/mediaserver.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"io/ioutil"
1414
"math/big"
1515
"mime/multipart"
16+
"net"
1617
"net/http"
1718
"net/textproto"
1819
"net/url"
@@ -1660,7 +1661,16 @@ func getRemoteAddr(r *http.Request) string {
16601661
if proxiedAddr := r.Header.Get("X-Forwarded-For"); proxiedAddr != "" {
16611662
addr = strings.Split(proxiedAddr, ",")[0]
16621663
}
1663-
return strings.Split(addr, ":")[0]
1664+
1665+
// addr is typically in the format "ip:port"
1666+
// Need to extract just the IP. Handle IPv6 too.
1667+
host, _, err := net.SplitHostPort(strings.TrimSpace(addr))
1668+
if err != nil {
1669+
// probably not a real IP
1670+
return addr
1671+
}
1672+
1673+
return host
16641674
}
16651675

16661676
func mediaCompatible(a, b ffmpeg.MediaFormatInfo) bool {

server/mediaserver_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,3 +1577,49 @@ func mustParseUrl(t *testing.T, str string) *url.URL {
15771577
}
15781578
return url
15791579
}
1580+
1581+
func TestGetRemoteAddr(t *testing.T) {
1582+
type tc struct {
1583+
name string
1584+
remoteAddr string // r.RemoteAddr
1585+
xff string // "" = header not present
1586+
want string
1587+
}
1588+
1589+
cases := []tc{
1590+
// --- No X-Forwarded-For (uses RemoteAddr) ---
1591+
{"remote IPv4 with port", "203.0.113.9:54321", "", "203.0.113.9"},
1592+
{"remote hostname with port", "example.com:80", "", "example.com"},
1593+
{"remote bracketed IPv6 with port", "[2001:db8::1]:443", "", "2001:db8::1"},
1594+
{"remote IPv6 with zone", "[fe80::1%lo0]:1234", "", "fe80::1%lo0"},
1595+
{"remote IPv4 no port (SplitHostPort error)", "192.0.2.10", "", "192.0.2.10"},
1596+
{"remote bare IPv6 no port (SplitHostPort error)", "2001:db8::2", "", "2001:db8::2"},
1597+
{"remote empty string", "", "", ""},
1598+
{"remote malformed string", "1.2.3.4, nonsense", "", "1.2.3.4, nonsense"},
1599+
1600+
// --- X-Forwarded-For present (takes first comma-delimited token) ---
1601+
{"xff single IPv4 no port", "203.0.113.9:54321", "198.51.100.7", "198.51.100.7"},
1602+
{"xff single IPv4 with port", "203.0.113.9:54321", "198.51.100.7:8080", "198.51.100.7"},
1603+
{"xff single hostname with port", "203.0.113.9:54321", "edge.example.net:8443", "edge.example.net"},
1604+
{"xff single bracketed IPv6 with port", "203.0.113.9:54321", "[2001:db8::7]:9443", "2001:db8::7"},
1605+
{"xff IPv4-mapped IPv6 with port", "203.0.113.9:54321", "[::ffff:192.0.2.128]:12345", "::ffff:192.0.2.128"},
1606+
{"xff multiple entries with port", "203.0.113.9:54321", "198.51.100.7:8080, 10.0.0.1:80", "198.51.100.7"},
1607+
{"xff multiple entries no port", "203.0.113.9:54321", "198.51.100.7, 10.0.0.1", "198.51.100.7"},
1608+
{"xff first entry empty", "203.0.113.9:54321", ", 198.51.100.7", ""},
1609+
{"xff first entry has spaces", "203.0.113.9:54321", " \t\r198.51.100.7:8080 ", "198.51.100.7"},
1610+
}
1611+
1612+
for _, tt := range cases {
1613+
t.Run(tt.name, func(t *testing.T) {
1614+
r := &http.Request{
1615+
RemoteAddr: tt.remoteAddr,
1616+
Header: make(http.Header),
1617+
}
1618+
if tt.xff != "" {
1619+
r.Header.Set("X-Forwarded-For", tt.xff)
1620+
}
1621+
got := getRemoteAddr(r)
1622+
assert.Equal(t, tt.want, got)
1623+
})
1624+
}
1625+
}

0 commit comments

Comments
 (0)