DNS working!

This commit is contained in:
soypat
2025-07-12 12:34:20 -03:00
parent a257becf15
commit 68c4d1ea71
5 changed files with 96 additions and 42 deletions
+16 -5
View File
@@ -12,6 +12,7 @@ import (
type Client struct { type Client struct {
connID uint64 connID uint64
txid uint16 txid uint16
lport uint16
msg Message msg Message
respFlags HeaderFlags respFlags HeaderFlags
state clientState state clientState
@@ -20,23 +21,25 @@ type Client struct {
type ResolveConfig struct { type ResolveConfig struct {
Questions []Question Questions []Question
Additional []Resource
EnableRecursion bool EnableRecursion bool
} }
func (sudp *Client) Protocol() uint64 { return uint64(lneto.IPProtoUDP) } func (sudp *Client) Protocol() uint64 { return uint64(lneto.IPProtoUDP) }
func (sudp *Client) LocalPort() uint16 { return ClientPort } func (sudp *Client) LocalPort() uint16 { return sudp.lport }
func (sudp *Client) ConnectionID() *uint64 { return &sudp.connID } func (sudp *Client) ConnectionID() *uint64 { return &sudp.connID }
func (c *Client) StartResolve(txid uint16, cfg ResolveConfig) error { func (c *Client) StartResolve(localPort, txid uint16, cfg ResolveConfig) error {
nd := len(cfg.Questions) nd := len(cfg.Questions)
if nd > math.MaxUint16 { if nd > math.MaxUint16 {
return errors.New("overflow uint16 in DNS questions") return errors.New("overflow uint16 in DNS questions")
} }
c.reset(txid, dnsSendQuery, cfg.EnableRecursion) c.reset(localPort, txid, dnsSendQuery, cfg.EnableRecursion)
c.msg.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0) c.msg.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0)
c.msg.AddQuestions(cfg.Questions) c.msg.AddQuestions(cfg.Questions)
c.msg.AddAdditionals(cfg.Additional)
return nil return nil
} }
@@ -61,6 +64,13 @@ func (c *Client) Encapsulate(carrierData []byte, frameOffset int) (int, error) {
return 0, fmt.Errorf("unexpected write %d v %d", len(data), msglen) return 0, fmt.Errorf("unexpected write %d v %d", len(data), msglen)
} }
c.state = dnsAwaitResponse c.state = dnsAwaitResponse
// Unset don't frag since DNS requests go through LOTS of nodes.
if frameOffset >= 28 {
version := carrierData[0] >> 4
if version == 4 {
carrierData[6], carrierData[7] = 0, 0 // unset IP Flags.
}
}
return len(data), nil return len(data), nil
} }
@@ -113,12 +123,13 @@ func (c *Client) Answers() []Resource {
} }
func (c *Client) Abort() { func (c *Client) Abort() {
c.reset(0, 0, false) c.reset(0, 0, 0, false)
} }
func (c *Client) reset(txid uint16, state clientState, enableRecursion bool) { func (c *Client) reset(lport, txid uint16, state clientState, enableRecursion bool) {
*c = Client{ *c = Client{
connID: c.connID + 1, connID: c.connID + 1,
lport: lport,
txid: txid, txid: txid,
msg: c.msg, msg: c.msg,
state: state, state: state,
+57 -21
View File
@@ -37,7 +37,7 @@ type Question struct {
} }
type Resource struct { type Resource struct {
Header ResourceHeader header ResourceHeader
data []byte data []byte
} }
@@ -55,6 +55,35 @@ type Name struct {
data []byte data []byte
} }
type ZFlags uint16
func NewResource(name Name, typ Type, class Class, ttl uint32, data []byte) Resource {
return Resource{
header: ResourceHeader{
Name: name,
Type: typ,
Class: class,
TTL: ttl,
Length: uint16(len(data)),
},
data: data,
}
}
func (r *Resource) SetEDNS0(UDPlength uint16, rcode RCode, zflags ZFlags, data []byte) {
if len(data) > math.MaxUint16-2 || len(data)+8+2*SizeHeader > int(UDPlength) {
panic("too large data")
}
r.header = ResourceHeader{
Name: Name{data: rootDomain},
Type: TypeOPT,
Class: Class(UDPlength),
TTL: uint32(rcode)<<24 | 0<<16 | uint32(zflags),
Length: uint16(len(data)),
}
r.data = append(r.data[:0], data...)
}
// Decode decodes the DNS message in b into m. It returns the number of bytes // Decode decodes the DNS message in b into m. It returns the number of bytes
// consumed from b (0 if no bytes were consumed) and any error encountered. // consumed from b (0 if no bytes were consumed) and any error encountered.
// If the message was not completely parsed due to LimitResourceDecoding, // If the message was not completely parsed due to LimitResourceDecoding,
@@ -98,7 +127,8 @@ func (m *Message) Decode(msg []byte) (_ uint16, incompleteButOK bool, err error)
} }
} }
// Skip undecoded questions. // Skip undecoded questions.
for i := 0; i < int(hdr.QDCount())-nq; i++ { qd := hdr.QDCount()
for i := 0; i < int(qd)-nq; i++ {
off, err = skipQuestion(msg, off) off, err = skipQuestion(msg, off)
if err != nil { if err != nil {
return off, false, err return off, false, err
@@ -245,9 +275,16 @@ func (m *Message) AddQuestions(questions []Question) {
m.Questions = slices.Grow(m.Questions, len(questions)) m.Questions = slices.Grow(m.Questions, len(questions))
m.Questions = m.Questions[:qoff+len(questions)] m.Questions = m.Questions[:qoff+len(questions)]
for i := range questions { for i := range questions {
m.Questions[qoff+i].Name.CopyFrom(questions[i].Name) m.Questions[qoff+i].CopyFrom(questions[i])
m.Questions[qoff+i].Type = questions[i].Type }
m.Questions[qoff+i].Class = questions[i].Class }
func (m *Message) AddAdditionals(rsc []Resource) {
aoff := len(m.Additionals)
m.Additionals = slices.Grow(m.Additionals, len(rsc))
m.Additionals = m.Additionals[:aoff+len(rsc)]
for i := range rsc {
m.Additionals[aoff+i].CopyFrom(rsc[i])
} }
} }
@@ -272,16 +309,12 @@ func (h *ResourceHeader) String() string {
} }
func (r *Resource) Reset() { func (r *Resource) Reset() {
r.Header.Reset() r.header.Reset()
r.data = r.data[:0] r.data = r.data[:0]
} }
func (r *Resource) Len() uint16 {
return r.Header.Name.Len() + 10 + uint16(len(r.data))
}
func (r *Resource) RawData() []byte { func (r *Resource) RawData() []byte {
length := r.Header.Length length := r.header.Length
if int(length) > len(r.data) { if int(length) > len(r.data) {
length = uint16(len(r.data)) length = uint16(len(r.data))
} }
@@ -330,20 +363,19 @@ func (q *Question) String() string {
} }
func (r *Resource) Decode(b []byte, off uint16) (uint16, error) { func (r *Resource) Decode(b []byte, off uint16) (uint16, error) {
off, err := r.Header.Decode(b, off) off, err := r.header.Decode(b, off)
if err != nil { if err != nil {
return off, err return off, err
} }
if r.Header.Length > uint16(len(b[off:])) { if r.header.Length > uint16(len(b[off:])) {
return off, errResourceLen return off, errResourceLen
} }
r.data = append(r.data[:0], b[off:off+r.Header.Length]...) r.data = append(r.data[:0], b[off:off+r.header.Length]...)
return off + r.Header.Length, nil return off + r.header.Length, nil
} }
func (r *Resource) appendTo(buf []byte) (_ []byte, err error) { func (r *Resource) appendTo(buf []byte) (_ []byte, err error) {
r.Header.Length = uint16(len(r.data)) buf, err = r.header.appendTo(buf)
buf, err = r.Header.appendTo(buf)
if err != nil { if err != nil {
return buf, err return buf, err
} }
@@ -351,6 +383,10 @@ func (r *Resource) appendTo(buf []byte) (_ []byte, err error) {
return buf, nil return buf, nil
} }
func (r *Resource) Len() uint16 {
return r.header.Name.Len() + 10 + uint16(len(r.data))
}
func (rhdr *ResourceHeader) Decode(msg []byte, off uint16) (uint16, error) { func (rhdr *ResourceHeader) Decode(msg []byte, off uint16) (uint16, error) {
off, err := rhdr.Name.Decode(msg, off) off, err := rhdr.Name.Decode(msg, off)
if err != nil { if err != nil {
@@ -386,7 +422,7 @@ func MustNewName(s string) Name {
return name return name
} }
var emptyDomain = []byte{0} var rootDomain = []byte{0}
// NewName parses a domain name and returns a new Name. // NewName parses a domain name and returns a new Name.
func NewName(domain string) (Name, error) { func NewName(domain string) (Name, error) {
@@ -394,7 +430,7 @@ func NewName(domain string) (Name, error) {
return Name{}, errEmptyDomainName return Name{}, errEmptyDomainName
} }
if len(domain) == 1 && domain[0] == '.' { if len(domain) == 1 && domain[0] == '.' {
return Name{data: emptyDomain}, nil return Name{data: append([]byte{}, rootDomain...)}, nil
} }
var name Name var name Name
for len(domain) > 0 { for len(domain) > 0 {
@@ -462,7 +498,7 @@ func (n *Name) Decode(b []byte, off uint16) (uint16, error) {
return off, nil return off, nil
} }
// Reset resets the Name labels to be empty and reuses buffer. // Reset resets the Name labels to be empty andatad reuses buffer.
func (n *Name) Reset() { n.data = n.data[:0] } func (n *Name) Reset() { n.data = n.data[:0] }
// CanAddLabel reports whether the label can be added to the name. // CanAddLabel reports whether the label can be added to the name.
@@ -605,7 +641,7 @@ func (dst *Question) CopyFrom(q Question) {
} }
func (dst *Resource) CopyFrom(r Resource) { func (dst *Resource) CopyFrom(r Resource) {
dst.Header.CopyFrom(r.Header) dst.header.CopyFrom(r.header)
dst.data = append(dst.data[:0], r.data...) dst.data = append(dst.data[:0], r.data...)
} }
+3 -3
View File
@@ -97,7 +97,7 @@ func TestMessageAppendEncode(t *testing.T) {
}, },
Answers: []Resource{ Answers: []Resource{
{ {
Header: ResourceHeader{ header: ResourceHeader{
Name: MustNewName("."), Name: MustNewName("."),
Type: TypeA, Type: TypeA,
Class: ClassINET, Class: ClassINET,
@@ -147,7 +147,7 @@ func TestMessageAppendEncodeIncompleteOK(t *testing.T) {
}, },
Answers: []Resource{ Answers: []Resource{
{ {
Header: ResourceHeader{ header: ResourceHeader{
Name: MustNewName("."), Name: MustNewName("."),
Type: TypeA, Type: TypeA,
Class: ClassINET, Class: ClassINET,
@@ -157,7 +157,7 @@ func TestMessageAppendEncodeIncompleteOK(t *testing.T) {
data: []byte{1, 2, 3}, data: []byte{1, 2, 3},
}, },
{ {
Header: ResourceHeader{ header: ResourceHeader{
Name: MustNewName("."), Name: MustNewName("."),
Type: TypeA, Type: TypeA,
Class: ClassINET, Class: ClassINET,
+19 -12
View File
@@ -179,13 +179,14 @@ func run() (err error) {
} }
type Stack struct { type Stack struct {
link internet.StackEthernet link internet.StackEthernet
ip internet.StackIP ip internet.StackIP
arp internet.NodeARP arp internet.NodeARP
udps internet.StackPorts udps internet.StackPorts
dhcp dhcpv4.Client dhcp dhcpv4.Client
dns dns.Client dns dns.Client
lookup dns.Message ednsopt dns.Resource
lookup dns.Message
// Packet capture and top level filtering. // Packet capture and top level filtering.
shark pcap.PacketBreakdown shark pcap.PacketBreakdown
@@ -194,10 +195,10 @@ type Stack struct {
func (s *Stack) Demux(b []byte, _ int) (err error) { func (s *Stack) Demux(b []byte, _ int) (err error) {
s.aux, err = s.shark.CaptureEthernet(s.aux[:0], b, 0) s.aux, err = s.shark.CaptureEthernet(s.aux[:0], b, 0)
baseFrame := s.aux[len(s.aux)-1] topFrame := s.aux[len(s.aux)-1]
isOK := baseFrame.Protocol == "DHCPv4" || isOK := topFrame.Protocol == "DHCPv4" || // Allow DHCP responses.
(baseFrame.Protocol == lneto.IPProtoUDP && getField(baseFrame, b, pcap.FieldClassDst) == 53) || (topFrame.Protocol == lneto.IPProtoUDP && getField(topFrame, b, pcap.FieldClassSrc) == 53) || // Allow DNS responses.
baseFrame.Protocol == ethernet.TypeARP topFrame.Protocol == ethernet.TypeARP // Allow ARP responses.
if !isOK { if !isOK {
return nil return nil
} }
@@ -278,7 +279,10 @@ func (s *Stack) StartLookupIP(host string) error {
if err != nil { if err != nil {
return err return err
} }
err = s.dns.StartResolve(uint16(softRand), dns.ResolveConfig{ s.link.SetHardwareAddr6([6]byte{0xd8, 0x5e, 0xd3, 0x43, 0x03, 0xeb})
s.ip.SetAddr(netip.AddrFrom4([4]byte{192, 168, 1, 53}))
s.ednsopt.SetEDNS0(uint16(s.link.MTU())-100, 0, 0, nil)
err = s.dns.StartResolve(uint16(softRand>>1)+1024, uint16(softRand), dns.ResolveConfig{
Questions: []dns.Question{ Questions: []dns.Question{
{ {
Name: name, Name: name,
@@ -286,6 +290,9 @@ func (s *Stack) StartLookupIP(host string) error {
Class: dns.ClassINET, Class: dns.ClassINET,
}, },
}, },
Additional: []dns.Resource{
s.ednsopt,
},
EnableRecursion: true, EnableRecursion: true,
}) })
if err != nil { if err != nil {
+1 -1
View File
@@ -148,6 +148,7 @@ func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error)
id := internal.Prand16(seed) id := internal.Prand16(seed)
ifrm.SetID(id) ifrm.SetID(id)
ifrm.SetFlags(dontFrag) ifrm.SetFlags(dontFrag)
ifrm.SetTTL(64)
*ifrm.SourceAddr() = sb.ip *ifrm.SourceAddr() = sb.ip
sb.ipID = id sb.ipID = id
for i := range sb.handlers { for i := range sb.handlers {
@@ -166,7 +167,6 @@ func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error)
} }
totalLen := n + headerlen totalLen := n + headerlen
ifrm.SetTotalLength(uint16(totalLen)) ifrm.SetTotalLength(uint16(totalLen))
ifrm.SetTTL(64)
ifrm.SetProtocol(proto) ifrm.SetProtocol(proto)
ifrm.SetCRC(ifrm.CalculateHeaderCRC()) ifrm.SetCRC(ifrm.CalculateHeaderCRC())
// Calculate CRC for our newly generated packet. // Calculate CRC for our newly generated packet.