Files
lneto/ipv6/icmpv6/icmpv6.go
T
Pat Whittingslow 7d5830d7ab V2 Netbird integration - UDP MIMO/SIMO, ICMPv6, DHCPv6 implementations (#106)
* begin adding udp.MuxHandler

* add udp MuxHandlerSIMO/MIMO

* add tcp rx shutdown

* icmpv6 client

* icmpv6 Client shared NDP/Echo preparation

* icmpv6 client ndp/echo split

* icmpv6 client ndp/echo split done

* icmpv6 adjustments

* add dhcpv6 stubs

* dhcpv4 preliminary revision

* add dns.NextLabel

* dns label name tweaks

* dns begin work on TCP client

* add dnstcp package

* apply gofmt changes

* add udp mux tests

* clean up, remove StackBig for now

* remove dnstcp so as to merged confident parts and we continue dnstcp work elsewhere
2026-05-10 12:16:30 -03:00

224 lines
6.2 KiB
Go

package icmpv6
import (
"encoding/binary"
"github.com/soypat/lneto"
)
//go:generate stringer -type=Type,CodeDestinationUnreachable,CodeParameterProblem -linecomment -output stringers.go
const (
sizeHeader = 8
sizeNDPBase = sizeHeader + 16 // 24: ICMPv6 header + 16-byte target address
sizeNDPOption = 8 // 1 type + 1 len + 6 MAC (Ethernet link-layer option, RFC 4861 §4.6.1)
sizeNDP = sizeNDPBase + sizeNDPOption
)
type Type uint8
const (
TypeDestinationUnreachable Type = 1 // destination unreachable
TypePacketTooBig Type = 2 // packet too big
TypeTimeExceeded Type = 3 // time exceeded
TypeParameterProblem Type = 4 // parameter problem
TypeEchoRequest Type = 128 // echo request
TypeEchoReply Type = 129 // echo reply
TypeRouterSolicitation Type = 133 // router solicitation
TypeRouterAdvertisement Type = 134 // router advertisement
TypeNeighborSolicitation Type = 135 // neighbor solicitation
TypeNeighborAdvertisement Type = 136 // neighbor advertisement
TypeRedirectMessage Type = 137 // redirect message
)
type CodeTimeExceeded uint8
const (
CodeHopLimitExceeded CodeTimeExceeded = iota // hop limit exceeded in transit
CodeFragmentReassembly // fragment reassembly time exceeded
)
type CodeDestinationUnreachable uint8
const (
CodeNoRoute CodeDestinationUnreachable = iota // no route to destination
CodeAdminProhibited // communication administratively prohibited
CodeBeyondScope // beyond scope of source address
CodeAddressUnreachable // address unreachable
CodePortUnreachable // port unreachable
CodeIngressEgressPolicy // source address failed ingress/egress policy
CodeRejectRoute // reject route to destination
)
type CodeParameterProblem uint8
const (
CodeErroneousHeaderField CodeParameterProblem = iota // erroneous header field encountered
CodeUnrecognizedNextHeader // unrecognized next header type encountered
CodeUnrecognizedIPv6Option // unrecognized IPv6 option encountered
)
func NewFrame(buf []byte) (Frame, error) {
if len(buf) < sizeHeader {
return Frame{}, lneto.ErrTruncatedFrame
}
return Frame{buf: buf}, nil
}
type Frame struct {
buf []byte
}
func (frm Frame) Type() Type { return Type(frm.buf[0]) }
func (frm Frame) SetType(t Type) { frm.buf[0] = uint8(t) }
func (frm Frame) Code() uint8 { return frm.buf[1] }
func (frm Frame) SetCode(code uint8) { frm.buf[1] = code }
// CRC returns the checksum field of the frame.
func (frm Frame) CRC() uint16 {
return binary.BigEndian.Uint16(frm.buf[2:4])
}
// SetCRC sets the checksum field of the frame.
func (frm Frame) SetCRC(crc uint16) {
binary.BigEndian.PutUint16(frm.buf[2:4], crc)
}
func (frm Frame) payload() []byte {
return frm.buf[4:]
}
type FrameDestinationUnreachable struct {
Frame
}
func (frm FrameDestinationUnreachable) Code() CodeDestinationUnreachable {
return CodeDestinationUnreachable(frm.Frame.Code())
}
func (frm FrameDestinationUnreachable) SetCode(code CodeDestinationUnreachable) {
frm.Frame.SetCode(uint8(code))
}
type FramePacketTooBig struct {
Frame
}
func (frm FramePacketTooBig) MTU() uint32 {
return binary.BigEndian.Uint32(frm.buf[4:8])
}
func (frm FramePacketTooBig) SetMTU(mtu uint32) {
binary.BigEndian.PutUint32(frm.buf[4:8], mtu)
}
type FrameParameterProblem struct {
Frame
}
func (frm FrameParameterProblem) Code() CodeParameterProblem {
return CodeParameterProblem(frm.Frame.Code())
}
func (frm FrameParameterProblem) SetCode(code CodeParameterProblem) {
frm.Frame.SetCode(uint8(code))
}
// Pointer identifies the octet offset within the invoking packet where the error was detected.
func (frm FrameParameterProblem) Pointer() uint32 {
return binary.BigEndian.Uint32(frm.buf[4:8])
}
func (frm FrameParameterProblem) SetPointer(ptr uint32) {
binary.BigEndian.PutUint32(frm.buf[4:8], ptr)
}
type FrameEcho struct {
Frame
}
func (frm FrameEcho) Identifier() uint16 {
return binary.BigEndian.Uint16(frm.buf[4:6])
}
func (frm FrameEcho) SetIdentifier(id uint16) {
binary.BigEndian.PutUint16(frm.buf[4:6], id)
}
func (frm FrameEcho) SequenceNumber() uint16 {
return binary.BigEndian.Uint16(frm.buf[6:8])
}
func (frm FrameEcho) SetSequenceNumber(seq uint16) {
binary.BigEndian.PutUint16(frm.buf[6:8], seq)
}
func (frm FrameEcho) Data() []byte {
return frm.buf[8:]
}
func (frm FrameEcho) RawData() []byte {
return frm.buf
}
// FrameNeighborSolicitation accesses a Neighbor Solicitation message (RFC 4861 §4.3).
// Layout after ICMPv6 base header: Reserved(4B) | TargetAddr(16B) | Options.
type FrameNeighborSolicitation struct {
Frame
}
// TargetAddr returns the IPv6 address being queried.
func (frm FrameNeighborSolicitation) TargetAddr() *[16]byte {
return (*[16]byte)(frm.buf[8:24])
}
// Options returns the bytes following the fixed header for parsing NDP options.
func (frm FrameNeighborSolicitation) Options() []byte {
return frm.buf[24:]
}
// FrameNeighborAdvertisement accesses a Neighbor Advertisement message (RFC 4861 §4.4).
// Layout after ICMPv6 base header: R|S|O|Reserved(4B) | TargetAddr(16B) | Options.
type FrameNeighborAdvertisement struct {
Frame
}
// Flags returns the R (router), S (solicited), O (override) flag bits.
func (frm FrameNeighborAdvertisement) Flags() (router, solicited, override bool) {
b := frm.buf[4]
return b&0x80 != 0, b&0x40 != 0, b&0x20 != 0
}
// SetFlags sets the R, S, O flags and zeroes the reserved bits.
func (frm FrameNeighborAdvertisement) SetFlags(router, solicited, override bool) {
var b byte
if router {
b |= 0x80
}
if solicited {
b |= 0x40
}
if override {
b |= 0x20
}
frm.buf[4] = b
frm.buf[5] = 0
frm.buf[6] = 0
frm.buf[7] = 0
}
// TargetAddr returns the IPv6 address being announced.
func (frm FrameNeighborAdvertisement) TargetAddr() *[16]byte {
return (*[16]byte)(frm.buf[8:24])
}
// Options returns the bytes following the fixed header for parsing NDP options.
func (frm FrameNeighborAdvertisement) Options() []byte {
return frm.buf[24:]
}