(*Msg).Pack panics when packing an A record whose address is the netip.Addr zero value.
The panic is reachable by packing a Msg that was unpacked from malformed bytes:
https://go.dev/play/p/Q95WZQjd9ki
packagemainimport("log""codeberg.org/miekg/dns")funcmain(){// header ANCOUNT=1// answer NAME=. TYPE=A CLASS=IN TTL=0 RDLENGTH=0m:=&dns.Msg{Data:[]byte{0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0}}iferr:=m.Unpack();err!=nil{log.Fatalf("Unpack: %v",err)}_=m.Pack()// panic: As4 called on IP zero value}
panic: As4 called on IP zero value
goroutine 1 [running]:
net/netip.Addr.As4(...)
/usr/local/go-faketime/src/net/netip/netip.go:718
codeberg.org/miekg/dns/internal/pack.A({{0x5de2b8?, 0x0?}, {0x0?}}, {0x13196d08100?, 0x767a78?, 0x13196c6eba8?}, 0x47c68f?)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/internal/pack/pack.go:152 +0x145
codeberg.org/miekg/dns.(*A).pack(...)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/zmsg.go:645
codeberg.org/miekg/dns.zpack({0x5e41e0?, 0x13196c04ed0?}, {0x13196d08100?, 0x1c, 0x13196d08100?}, 0x1c?, 0x1c?)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/zpack.go:32 +0x545
codeberg.org/miekg/dns.packRR({0x5e41e0, 0x13196c04ed0}, {0x13196d08100, 0x1c, 0x1c}, 0xc, 0x13196c6edd0)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/msg.go:105 +0xf1
codeberg.org/miekg/dns.(*Msg).Pack(0x13196c6ee68)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/msg.go:230 +0x749
main.main()
/tmp/sandbox2102939842/prog.go:16 +0xda
Program exited.
This PR adds two fixes:
- Guard
internal/pack.A with netip.Addr.Is4().
- Add a regression test.
I wasn't sure if (*Msg).Unpack should reject the message above, so I left (*Msg).Unpack untouched. If we do want to reject it, I think removing if rdlength == 0 { return rr, nil } in unpackRR could work, but that might hurt performance.
`(*Msg).Pack` panics when packing an A record whose address is the `netip.Addr` zero value.
The panic is reachable by packing a `Msg` that was unpacked from malformed bytes:
https://go.dev/play/p/Q95WZQjd9ki
```go
package main
import (
"log"
"codeberg.org/miekg/dns"
)
func main() {
// header ANCOUNT=1
// answer NAME=. TYPE=A CLASS=IN TTL=0 RDLENGTH=0
m := &dns.Msg{Data: []byte{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0}}
if err := m.Unpack(); err != nil {
log.Fatalf("Unpack: %v", err)
}
_ = m.Pack() // panic: As4 called on IP zero value
}
```
```plaintext
panic: As4 called on IP zero value
goroutine 1 [running]:
net/netip.Addr.As4(...)
/usr/local/go-faketime/src/net/netip/netip.go:718
codeberg.org/miekg/dns/internal/pack.A({{0x5de2b8?, 0x0?}, {0x0?}}, {0x13196d08100?, 0x767a78?, 0x13196c6eba8?}, 0x47c68f?)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/internal/pack/pack.go:152 +0x145
codeberg.org/miekg/dns.(*A).pack(...)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/zmsg.go:645
codeberg.org/miekg/dns.zpack({0x5e41e0?, 0x13196c04ed0?}, {0x13196d08100?, 0x1c, 0x13196d08100?}, 0x1c?, 0x1c?)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/zpack.go:32 +0x545
codeberg.org/miekg/dns.packRR({0x5e41e0, 0x13196c04ed0}, {0x13196d08100, 0x1c, 0x1c}, 0xc, 0x13196c6edd0)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/msg.go:105 +0xf1
codeberg.org/miekg/dns.(*Msg).Pack(0x13196c6ee68)
/tmp/gopath3234477451/pkg/mod/codeberg.org/miekg/dns@v0.6.83/msg.go:230 +0x749
main.main()
/tmp/sandbox2102939842/prog.go:16 +0xda
Program exited.
```
This PR adds two fixes:
1. Guard `internal/pack.A` with `netip.Addr.Is4()`.
2. Add a regression test.
I wasn't sure if `(*Msg).Unpack` should reject the message above, so I left `(*Msg).Unpack` untouched. If we do want to reject it, I think removing `if rdlength == 0 { return rr, nil }` in `unpackRR` could work, but that might hurt performance.