mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-12-23 16:37:31 +00:00
92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package tuntap
|
|
|
|
// The ICMPv6 module implements functions to easily create ICMPv6
|
|
// packets. These functions, when mixed with the built-in Go IPv6
|
|
// and ICMP libraries, can be used to send control messages back
|
|
// to the host. Examples include:
|
|
// - NDP messages, when running in TAP mode
|
|
// - Packet Too Big messages, when packets exceed the session MTU
|
|
// - Destination Unreachable messages, when a session prohibits
|
|
// incoming traffic
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net"
|
|
|
|
"golang.org/x/net/icmp"
|
|
"golang.org/x/net/ipv6"
|
|
)
|
|
|
|
const len_ETHER = 14
|
|
|
|
type ICMPv6 struct {
|
|
tun *TunAdapter
|
|
}
|
|
|
|
// Marshal returns the binary encoding of h.
|
|
func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
|
|
b := make([]byte, 40)
|
|
b[0] |= byte(h.Version) << 4
|
|
b[0] |= byte(h.TrafficClass) >> 4
|
|
b[1] |= byte(h.TrafficClass) << 4
|
|
b[1] |= byte(h.FlowLabel >> 16)
|
|
b[2] = byte(h.FlowLabel >> 8)
|
|
b[3] = byte(h.FlowLabel)
|
|
binary.BigEndian.PutUint16(b[4:6], uint16(h.PayloadLen))
|
|
b[6] = byte(h.NextHeader)
|
|
b[7] = byte(h.HopLimit)
|
|
copy(b[8:24], h.Src)
|
|
copy(b[24:40], h.Dst)
|
|
return b, nil
|
|
}
|
|
|
|
// Initialises the ICMPv6 module by assigning our link-local IPv6 address and
|
|
// our MAC address. ICMPv6 messages will always appear to originate from these
|
|
// addresses.
|
|
func (i *ICMPv6) Init(t *TunAdapter) {
|
|
i.tun = t
|
|
}
|
|
|
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
|
// parameters, complete with IP headers only, which can be written directly to
|
|
// a TUN adapter, or called directly by the CreateICMPv6L2 function when
|
|
// generating a message for TAP adapters.
|
|
func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
|
// Create the ICMPv6 message
|
|
icmpMessage := icmp.Message{
|
|
Type: mtype,
|
|
Code: mcode,
|
|
Body: mbody,
|
|
}
|
|
|
|
// Convert the ICMPv6 message into []byte
|
|
icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(src, dst))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create the IPv6 header
|
|
ipv6Header := ipv6.Header{
|
|
Version: ipv6.Version,
|
|
NextHeader: 58,
|
|
PayloadLen: len(icmpMessageBuf),
|
|
HopLimit: 255,
|
|
Src: src,
|
|
Dst: dst,
|
|
}
|
|
|
|
// Convert the IPv6 header into []byte
|
|
ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Construct the packet
|
|
responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen)
|
|
copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf)
|
|
copy(responsePacket[ipv6.HeaderLen:], icmpMessageBuf)
|
|
|
|
// Send it back
|
|
return responsePacket, nil
|
|
}
|