mirror of https://github.com/jackc/pgx.git
Do not send IPv4 networks as IPv4-mapped IPv6
Previously if we provided a parameter that was an array of strings such as []string{"0.0.0.0/8"}, we would encode this when sending to Postgres as ::ffff:0.0.0.0/8. From what I can tell, this is because when parsing the IP/network using net functions, we get a byte array that is 16 bytes long, even if it is an IPv4 network. In Inet.EncodeBinary(), we look at the length of the IP to determine what family the input is, and saw it as IPv6 because of this. We now always normalize IPv4 addresses using To4().pull/1281/head
parent
6fc738ea05
commit
1e485c1c3b
19
inet.go
19
inet.go
|
@ -47,17 +47,26 @@ func (dst *Inet) Set(src interface{}) error {
|
|||
case string:
|
||||
ip, ipnet, err := net.ParseCIDR(value)
|
||||
if err != nil {
|
||||
ip = net.ParseIP(value)
|
||||
ip := net.ParseIP(value)
|
||||
if ip == nil {
|
||||
return fmt.Errorf("unable to parse inet address: %s", value)
|
||||
}
|
||||
ipnet = &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}
|
||||
|
||||
if ipv4 := ip.To4(); ipv4 != nil {
|
||||
ip = ipv4
|
||||
ipnet.Mask = net.CIDRMask(32, 32)
|
||||
ipnet = &net.IPNet{IP: ipv4, Mask: net.CIDRMask(32, 32)}
|
||||
} else {
|
||||
ipnet = &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}
|
||||
}
|
||||
} else {
|
||||
ipnet.IP = ip
|
||||
if ipv4 := ipnet.IP.To4(); ipv4 != nil {
|
||||
ipnet.IP = ipv4
|
||||
if len(ipnet.Mask) == 16 {
|
||||
ipnet.Mask = ipnet.Mask[12:] // Needed if input is IPv4-mapped IPv6.
|
||||
}
|
||||
}
|
||||
}
|
||||
ipnet.IP = ip
|
||||
|
||||
*dst = Inet{IPNet: ipnet, Status: Present}
|
||||
case *net.IPNet:
|
||||
if value == nil {
|
||||
|
|
|
@ -52,10 +52,12 @@ func TestInetSet(t *testing.T) {
|
|||
{source: mustParseCIDR(t, "127.0.0.1/32"), result: pgtype.Inet{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
|
||||
{source: mustParseCIDR(t, "127.0.0.1/32").IP, result: pgtype.Inet{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
|
||||
{source: "127.0.0.1/32", result: pgtype.Inet{IPNet: mustParseCIDR(t, "127.0.0.1/32"), Status: pgtype.Present}},
|
||||
{source: "1.2.3.4/24", result: pgtype.Inet{IPNet: &net.IPNet{IP: net.ParseIP("1.2.3.4"), Mask: net.CIDRMask(24, 32)}, Status: pgtype.Present}},
|
||||
{source: "1.2.3.4/24", result: pgtype.Inet{IPNet: &net.IPNet{IP: net.ParseIP("1.2.3.4").To4(), Mask: net.CIDRMask(24, 32)}, Status: pgtype.Present}},
|
||||
{source: "10.0.0.1", result: pgtype.Inet{IPNet: mustParseInet(t, "10.0.0.1"), Status: pgtype.Present}},
|
||||
{source: "2607:f8b0:4009:80b::200e", result: pgtype.Inet{IPNet: mustParseInet(t, "2607:f8b0:4009:80b::200e"), Status: pgtype.Present}},
|
||||
{source: net.ParseIP(""), result: pgtype.Inet{Status: pgtype.Null}},
|
||||
{source: "0.0.0.0/8", result: pgtype.Inet{IPNet: mustParseInet(t, "0.0.0.0/8"), Status: pgtype.Present}},
|
||||
{source: "::ffff:0.0.0.0/104", result: pgtype.Inet{IPNet: &net.IPNet{IP: net.ParseIP("0.0.0.0").To4(), Mask: net.CIDRMask(8, 32)}, Status: pgtype.Present}},
|
||||
}
|
||||
|
||||
for i, tt := range successfulTests {
|
||||
|
@ -70,6 +72,7 @@ func TestInetSet(t *testing.T) {
|
|||
if tt.result.Status == pgtype.Present {
|
||||
assert.Equalf(t, tt.result.IPNet.Mask, r.IPNet.Mask, "%d: Mask", i)
|
||||
assert.Truef(t, tt.result.IPNet.IP.Equal(r.IPNet.IP), "%d: IP", i)
|
||||
assert.Equalf(t, len(tt.result.IPNet.IP), len(r.IPNet.IP), "%d: IP length", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue