github.com/yggdrasil-network/yggdrasil-go@v0.5.6/src/ipv6rwc/icmpv6.go (about)

     1  package ipv6rwc
     2  
     3  // The ICMPv6 module implements functions to easily create ICMPv6
     4  // packets. These functions, when mixed with the built-in Go IPv6
     5  // and ICMP libraries, can be used to send control messages back
     6  // to the host. Examples include:
     7  // - NDP messages, when running in TAP mode
     8  // - Packet Too Big messages, when packets exceed the session MTU
     9  // - Destination Unreachable messages, when a session prohibits
    10  //   incoming traffic
    11  
    12  import (
    13  	"encoding/binary"
    14  	"net"
    15  
    16  	"golang.org/x/net/icmp"
    17  	"golang.org/x/net/ipv6"
    18  )
    19  
    20  type ICMPv6 struct{}
    21  
    22  // Marshal returns the binary encoding of h.
    23  func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
    24  	b := make([]byte, 40)
    25  	b[0] |= byte(h.Version) << 4
    26  	b[0] |= byte(h.TrafficClass) >> 4
    27  	b[1] |= byte(h.TrafficClass) << 4
    28  	b[1] |= byte(h.FlowLabel >> 16)
    29  	b[2] = byte(h.FlowLabel >> 8)
    30  	b[3] = byte(h.FlowLabel)
    31  	binary.BigEndian.PutUint16(b[4:6], uint16(h.PayloadLen))
    32  	b[6] = byte(h.NextHeader)
    33  	b[7] = byte(h.HopLimit)
    34  	copy(b[8:24], h.Src)
    35  	copy(b[24:40], h.Dst)
    36  	return b, nil
    37  }
    38  
    39  // Creates an ICMPv6 packet based on the given icmp.MessageBody and other
    40  // parameters, complete with IP headers only, which can be written directly to
    41  // a TUN adapter, or called directly by the CreateICMPv6L2 function when
    42  // generating a message for TAP adapters.
    43  func CreateICMPv6(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
    44  	// Create the ICMPv6 message
    45  	icmpMessage := icmp.Message{
    46  		Type: mtype,
    47  		Code: mcode,
    48  		Body: mbody,
    49  	}
    50  
    51  	// Convert the ICMPv6 message into []byte
    52  	icmpMessageBuf, err := icmpMessage.Marshal(icmp.IPv6PseudoHeader(src, dst))
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	// Create the IPv6 header
    58  	ipv6Header := ipv6.Header{
    59  		Version:    ipv6.Version,
    60  		NextHeader: 58,
    61  		PayloadLen: len(icmpMessageBuf),
    62  		HopLimit:   255,
    63  		Src:        src,
    64  		Dst:        dst,
    65  	}
    66  
    67  	// Convert the IPv6 header into []byte
    68  	ipv6HeaderBuf, err := ipv6Header_Marshal(&ipv6Header)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	// Construct the packet
    74  	responsePacket := make([]byte, ipv6.HeaderLen+ipv6Header.PayloadLen)
    75  	copy(responsePacket[:ipv6.HeaderLen], ipv6HeaderBuf)
    76  	copy(responsePacket[ipv6.HeaderLen:], icmpMessageBuf)
    77  
    78  	// Send it back
    79  	return responsePacket, nil
    80  }