mirror of
https://github.com/soypat/lneto.git
synced 2026-09-01 04:19:05 +00:00
add ipv6 to xnet.StackAsync (#107)
* add ipv6 to xnet.StackAsync * dns improvements * improve DNS workings of StackAsync * add tentative ICMPv6 * work on prefixes and fix some small bugs, plan UDP/TCP6 * fix bugs in StackAsync and ipv4.Prefix.Contains * update arpsubtable * completely remove legacy internet.StackIP for StackIPv4/v6 * ipv4/ipv6 tcp/udp * add TCP6/UDP6 dialing APIs * add xnet.Stack6 interface * more ipv6 integration into StackAsync; various tweaks to lneto and documentation+TODOs * add stack6 tests * replace netip.Prefix with ipv4.Prefix where it makes sense
This commit is contained in:
+14
-5
@@ -4,6 +4,7 @@ import (
|
||||
"log/slog"
|
||||
"math"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/internal"
|
||||
@@ -104,7 +105,7 @@ func (c *Client) isClosed() bool {
|
||||
return c.state == CQueryIdle || c.state == CQueryAborted
|
||||
}
|
||||
|
||||
func (c *Client) MessageCopyTo(dst *Message) (done bool, err error) {
|
||||
func (c *Client) ResponseCopyTo(dst *Message) (done bool, err error) {
|
||||
if !c.respFlags.IsResponse() {
|
||||
return false, nil
|
||||
}
|
||||
@@ -116,11 +117,19 @@ func (c *Client) MessageCopyTo(dst *Message) (done bool, err error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c *Client) Answers() []Resource {
|
||||
if c.state != CQueryDone {
|
||||
return nil
|
||||
func (c *Client) ResponseAnswerLookup(dst []netip.Addr, host string) (uint16, error) {
|
||||
if !c.respFlags.IsResponse() {
|
||||
return 0, nil
|
||||
}
|
||||
return c.msg.Answers
|
||||
rcode := c.respFlags.ResponseCode()
|
||||
if rcode != 0 {
|
||||
return 0, rcode
|
||||
}
|
||||
return c.msg.WriteAnswers(dst, host)
|
||||
}
|
||||
|
||||
func (c *Client) ResponseFlags() (HeaderFlags, bool) {
|
||||
return c.respFlags, c.respFlags.IsResponse()
|
||||
}
|
||||
|
||||
func (c *Client) Abort() {
|
||||
|
||||
+50
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"math"
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -59,10 +60,38 @@ type ResourceHeader struct {
|
||||
Length uint16
|
||||
}
|
||||
|
||||
// Name is a wire representation of a DNS name.
|
||||
type Name struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// EqualString checks if the name receiver matches the strname string (non-wire formatted) name.
|
||||
func (n Name) EqualString(strname string) bool {
|
||||
data := n.data
|
||||
for len(data) > 0 {
|
||||
labelLen := int(data[0])
|
||||
if labelLen == 0 {
|
||||
return strname == "" || strname == "."
|
||||
}
|
||||
if len(data) < 1+labelLen {
|
||||
return false
|
||||
}
|
||||
label := data[1 : 1+labelLen]
|
||||
var seg string
|
||||
idx := strings.IndexByte(strname, '.')
|
||||
if idx < 0 {
|
||||
seg, strname = strname, ""
|
||||
} else {
|
||||
seg, strname = strname[:idx], strname[idx+1:]
|
||||
}
|
||||
if len(seg) != len(label) || seg != string(label) {
|
||||
return false
|
||||
}
|
||||
data = data[1+labelLen:]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NamesEqual reports whether two DNS names are equal by comparing
|
||||
// their wire-format representations directly. This is case-sensitive;
|
||||
// for case-insensitive comparison use [NamesEqualFold].
|
||||
@@ -270,6 +299,27 @@ func (m *Message) AppendTo(buf []byte, txid uint16, flags HeaderFlags) (_ []byte
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (m *Message) WriteAnswers(dst []netip.Addr, host string) (n uint16, err error) {
|
||||
for i := range m.Answers {
|
||||
if int(n) >= len(dst) {
|
||||
return n, lneto.ErrExhausted
|
||||
}
|
||||
ans := &m.Answers[i]
|
||||
hdr := ans.Header()
|
||||
if !hdr.Name.EqualString(host) {
|
||||
continue
|
||||
}
|
||||
var ok bool
|
||||
dst[n], ok = netip.AddrFromSlice(ans.RawData())
|
||||
if !ok {
|
||||
err = lneto.ErrInvalidAddr
|
||||
} else {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (m *Message) Len() uint16 {
|
||||
return SizeHeader + m.lenResources()
|
||||
}
|
||||
|
||||
+11
-10
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -288,23 +289,23 @@ func TestClient_ReceivesDNSResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check the client received the answer.
|
||||
answers := client.Answers()
|
||||
if len(answers) != 1 {
|
||||
t.Fatalf("expected 1 answer, got %d", len(answers))
|
||||
var addrs [4]netip.Addr
|
||||
answers, err := client.ResponseAnswerLookup(addrs[:], hostname)
|
||||
if answers != 1 {
|
||||
t.Fatalf("expected 1 answer, got %d", answers)
|
||||
}
|
||||
|
||||
data := answers[0].RawData()
|
||||
if len(data) != 4 {
|
||||
t.Fatalf("expected 4 bytes in answer, got %d", len(data))
|
||||
addr := addrs[0]
|
||||
if !addr.Is4() {
|
||||
t.Fatalf("expected 4 bytes in answer, got %d", addr.BitLen()/8)
|
||||
}
|
||||
if [4]byte(data) != wantIP {
|
||||
t.Errorf("expected IP %v, got %v", wantIP, data)
|
||||
if addr.As4() != wantIP {
|
||||
t.Errorf("expected IP %v, got %v", wantIP, addr.String())
|
||||
}
|
||||
|
||||
// Test MessageCopyTo as well.
|
||||
var lookup Message
|
||||
lookup.LimitResourceDecoding(1, 1, 0, 0)
|
||||
done, err := client.MessageCopyTo(&lookup)
|
||||
done, err := client.ResponseCopyTo(&lookup)
|
||||
if err != nil {
|
||||
t.Fatal("MessageCopyTo error:", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user