mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Remove ndp.go and add icmpv6.go
This commit is contained in:
		
							parent
							
								
									38567fffef
								
							
						
					
					
						commit
						be0d6feeba
					
				
					 3 changed files with 221 additions and 180 deletions
				
			
		
							
								
								
									
										203
									
								
								src/yggdrasil/icmpv6.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/yggdrasil/icmpv6.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,203 @@
 | 
			
		|||
package yggdrasil
 | 
			
		||||
 | 
			
		||||
// The NDP functions are needed when you are running with a
 | 
			
		||||
// TAP adapter - as the operating system expects neighbor solicitations
 | 
			
		||||
// for on-link traffic, this goroutine provides them
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/net/icmp"
 | 
			
		||||
import "encoding/binary"
 | 
			
		||||
import "unsafe" // TODO investigate if this can be done without resorting to unsafe
 | 
			
		||||
 | 
			
		||||
type macAddress [6]byte
 | 
			
		||||
type ipv6Address [16]byte
 | 
			
		||||
 | 
			
		||||
const ETHER = 14
 | 
			
		||||
const IPV6 = 40
 | 
			
		||||
 | 
			
		||||
type icmpv6 struct {
 | 
			
		||||
	tun        *tunDevice
 | 
			
		||||
	peermac    macAddress
 | 
			
		||||
	peerlladdr ipv6Address
 | 
			
		||||
	mymac      macAddress
 | 
			
		||||
	mylladdr   ipv6Address
 | 
			
		||||
	recv       chan []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type etherHeader struct {
 | 
			
		||||
	destination macAddress
 | 
			
		||||
	source      macAddress
 | 
			
		||||
	ethertype   [2]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ipv6Header struct {
 | 
			
		||||
	preamble    [4]byte
 | 
			
		||||
	length      [2]byte
 | 
			
		||||
	nextheader  byte
 | 
			
		||||
	hoplimit    byte
 | 
			
		||||
	source      ipv6Address
 | 
			
		||||
	destination ipv6Address
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Header struct {
 | 
			
		||||
	messagetype byte
 | 
			
		||||
	code        byte
 | 
			
		||||
	checksum    uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6PseudoHeader struct {
 | 
			
		||||
	source      ipv6Address
 | 
			
		||||
	destination ipv6Address
 | 
			
		||||
	length      [4]byte
 | 
			
		||||
	zero        [3]byte
 | 
			
		||||
	nextheader  byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Payload struct {
 | 
			
		||||
	ether            etherHeader
 | 
			
		||||
	ipv6             ipv6Header
 | 
			
		||||
	icmpv6           icmpv6Header
 | 
			
		||||
	flags            [4]byte
 | 
			
		||||
	targetaddress    ipv6Address
 | 
			
		||||
	optiontype       byte
 | 
			
		||||
	optionlength     byte
 | 
			
		||||
	linklayeraddress macAddress
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Packet struct {
 | 
			
		||||
	ipv6    ipv6Header
 | 
			
		||||
	payload icmpv6Payload
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Frame struct {
 | 
			
		||||
	ether  etherHeader
 | 
			
		||||
	packet icmpv6Packet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) init(t *tunDevice) {
 | 
			
		||||
	i.tun = t
 | 
			
		||||
	i.recv = make(chan []byte)
 | 
			
		||||
	copy(i.mymac[:], []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x02})
 | 
			
		||||
	copy(i.mylladdr[:], []byte{
 | 
			
		||||
		0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE})
 | 
			
		||||
	go i.listen()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) listen() {
 | 
			
		||||
	for {
 | 
			
		||||
		datain := <-i.recv
 | 
			
		||||
 | 
			
		||||
		if i.tun.iface.IsTAP() {
 | 
			
		||||
			// TAP mode
 | 
			
		||||
			dataout := make([]byte, ETHER+IPV6+32)
 | 
			
		||||
			i.read_tap(datain, dataout)
 | 
			
		||||
			i.tun.iface.Write(dataout)
 | 
			
		||||
		} else {
 | 
			
		||||
			// TUN mode
 | 
			
		||||
			dataout := make([]byte, IPV6+32)
 | 
			
		||||
			i.read_tun(datain, dataout)
 | 
			
		||||
			i.tun.iface.Write(dataout)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) read_tap(datain []byte, dataout []byte) {
 | 
			
		||||
	// Set up
 | 
			
		||||
	in := (*icmpv6Frame)(unsafe.Pointer(&datain[0]))
 | 
			
		||||
	out := (*icmpv6Frame)(unsafe.Pointer(&dataout[0]))
 | 
			
		||||
 | 
			
		||||
	// Store the peer MAC address
 | 
			
		||||
	copy(i.peermac[:6], in.ether.source[:6])
 | 
			
		||||
 | 
			
		||||
	// Ignore non-IPv6 frames
 | 
			
		||||
	if binary.BigEndian.Uint16(in.ether.ethertype[:]) != uint16(0x86DD) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Populate the out ethernet headers
 | 
			
		||||
	copy(out.ether.destination[:], in.ether.destination[:])
 | 
			
		||||
	copy(out.ether.source[:], i.mymac[:])
 | 
			
		||||
	binary.BigEndian.PutUint16(out.ether.ethertype[:], uint16(0x86DD))
 | 
			
		||||
 | 
			
		||||
	// And for now just copy the rest of the packet we were sent
 | 
			
		||||
	copy(dataout[ETHER:ETHER+IPV6], datain[ETHER:ETHER+IPV6])
 | 
			
		||||
 | 
			
		||||
	// Then pass the IP packet onto the next function
 | 
			
		||||
	i.read_tun(datain[ETHER:], dataout[ETHER:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) read_tun(datain []byte, dataout []byte) {
 | 
			
		||||
	// Set up
 | 
			
		||||
	in := (*icmpv6Packet)(unsafe.Pointer(&datain[0]))
 | 
			
		||||
	out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0]))
 | 
			
		||||
 | 
			
		||||
	// Store the peer link-local address
 | 
			
		||||
	copy(i.peerlladdr[:16], in.ipv6.source[:16])
 | 
			
		||||
 | 
			
		||||
	// Ignore non-ICMPv6 packets
 | 
			
		||||
	if in.ipv6.nextheader != uint8(0x3A) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// What is the ICMPv6 message type?
 | 
			
		||||
	switch in.payload.icmpv6.messagetype {
 | 
			
		||||
	case uint8(135):
 | 
			
		||||
		i.handle_ndp(&in.payload, &out.payload)
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update the source and destination addresses in the IPv6 header
 | 
			
		||||
	copy(out.ipv6.destination[:], in.ipv6.source[:])
 | 
			
		||||
	copy(out.ipv6.source[:], i.mylladdr[:])
 | 
			
		||||
	binary.BigEndian.PutUint16(out.ipv6.length[:], uint16(32))
 | 
			
		||||
 | 
			
		||||
	// Copy the payload
 | 
			
		||||
	copy(dataout[IPV6:], datain[IPV6:])
 | 
			
		||||
 | 
			
		||||
	// Calculate the checksum
 | 
			
		||||
	i.calculate_checksum(dataout)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) calculate_checksum(dataout []byte) {
 | 
			
		||||
	// Set up
 | 
			
		||||
	out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0]))
 | 
			
		||||
 | 
			
		||||
	// Generate the pseudo-header for the checksum
 | 
			
		||||
	ps := make([]byte, 44)
 | 
			
		||||
	pseudo := (*icmpv6PseudoHeader)(unsafe.Pointer(&ps[0]))
 | 
			
		||||
	copy(pseudo.destination[:], out.ipv6.destination[:])
 | 
			
		||||
	copy(pseudo.source[:], out.ipv6.source[:])
 | 
			
		||||
	binary.BigEndian.PutUint32(pseudo.length[:], uint32(binary.BigEndian.Uint16(out.ipv6.length[:])))
 | 
			
		||||
	pseudo.nextheader = out.ipv6.nextheader
 | 
			
		||||
 | 
			
		||||
	// Lazy-man's checksum using the icmp library
 | 
			
		||||
	icmpv6, err := icmp.ParseMessage(0x3A, dataout[IPV6:])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// And copy the payload
 | 
			
		||||
	payload, err := icmpv6.Marshal(ps)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	copy(dataout[IPV6:], payload)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (i *icmpv6) handle_ndp(in *icmpv6Payload, out *icmpv6Payload) {
 | 
			
		||||
	// Ignore NDP requests for anything outside of fd00::/8
 | 
			
		||||
	if in.targetaddress[0] != 0xFD {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update the ICMPv6 headers
 | 
			
		||||
	out.icmpv6.messagetype = uint8(136)
 | 
			
		||||
	out.icmpv6.code = uint8(0)
 | 
			
		||||
 | 
			
		||||
	// Update the ICMPv6 payload
 | 
			
		||||
	copy(out.targetaddress[:], in.targetaddress[:])
 | 
			
		||||
	out.optiontype = uint8(2)
 | 
			
		||||
	out.optionlength = uint8(1)
 | 
			
		||||
	copy(out.linklayeraddress[:], i.mymac[:])
 | 
			
		||||
	binary.BigEndian.PutUint32(out.flags[:], uint32(0x20000000))
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,165 +0,0 @@
 | 
			
		|||
package yggdrasil
 | 
			
		||||
 | 
			
		||||
// The NDP functions are needed when you are running with a
 | 
			
		||||
// TAP adapter - as the operating system expects neighbor solicitations
 | 
			
		||||
// for on-link traffic, this goroutine provides them
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/net/icmp"
 | 
			
		||||
import "encoding/binary"
 | 
			
		||||
import "unsafe" // TODO investigate if this can be done without resorting to unsafe
 | 
			
		||||
 | 
			
		||||
type macAddress [6]byte
 | 
			
		||||
type ipv6Address [16]byte
 | 
			
		||||
 | 
			
		||||
const ETHER = 14
 | 
			
		||||
const IPV6 = 40
 | 
			
		||||
 | 
			
		||||
type ndp struct {
 | 
			
		||||
	tun        *tunDevice
 | 
			
		||||
	peermac    macAddress
 | 
			
		||||
	peerlladdr ipv6Address
 | 
			
		||||
	mymac      macAddress
 | 
			
		||||
	mylladdr   ipv6Address
 | 
			
		||||
	recv       chan []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type etherHeader struct {
 | 
			
		||||
	destination macAddress
 | 
			
		||||
	source      macAddress
 | 
			
		||||
	ethertype   [2]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ipv6Header struct {
 | 
			
		||||
	preamble    [4]byte
 | 
			
		||||
	length      [2]byte
 | 
			
		||||
	nextheader  byte
 | 
			
		||||
	hoplimit    byte
 | 
			
		||||
	source      ipv6Address
 | 
			
		||||
	destination ipv6Address
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Header struct {
 | 
			
		||||
	messagetype byte
 | 
			
		||||
	code        byte
 | 
			
		||||
	checksum    uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6PseudoHeader struct {
 | 
			
		||||
	source      ipv6Address
 | 
			
		||||
	destination ipv6Address
 | 
			
		||||
	length      [4]byte
 | 
			
		||||
	zero        [3]byte
 | 
			
		||||
	nextheader  byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type icmpv6Packet struct {
 | 
			
		||||
	ether            etherHeader
 | 
			
		||||
	ipv6             ipv6Header
 | 
			
		||||
	icmpv6           icmpv6Header
 | 
			
		||||
	flags            [4]byte
 | 
			
		||||
	targetaddress    ipv6Address
 | 
			
		||||
	optiontype       byte
 | 
			
		||||
	optionlength     byte
 | 
			
		||||
	linklayeraddress macAddress
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *ndp) init(t *tunDevice) {
 | 
			
		||||
	n.tun = t
 | 
			
		||||
	n.recv = make(chan []byte)
 | 
			
		||||
	copy(n.mymac[:], []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x02})
 | 
			
		||||
	copy(n.mylladdr[:], []byte{
 | 
			
		||||
		0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE})
 | 
			
		||||
	go n.listen()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *ndp) listen() {
 | 
			
		||||
	for {
 | 
			
		||||
		// Receive from the channel and check if we're using TAP instead
 | 
			
		||||
		// of TUN mode - NDP is only relevant for TAP
 | 
			
		||||
		datain := <-n.recv
 | 
			
		||||
		if !n.tun.iface.IsTAP() {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Create our return frame buffer and also the unsafe pointers to
 | 
			
		||||
		// map them to the structs
 | 
			
		||||
		dataout := make([]byte, ETHER+IPV6+32)
 | 
			
		||||
		in := (*icmpv6Packet)(unsafe.Pointer(&datain[0]))
 | 
			
		||||
		out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0]))
 | 
			
		||||
 | 
			
		||||
		// Store peer MAC address and link-local IP address -
 | 
			
		||||
		// these will be used later by tun.go
 | 
			
		||||
		copy(n.peermac[:6], in.ether.source[:6])
 | 
			
		||||
		copy(n.peerlladdr[:16], in.ipv6.source[:16])
 | 
			
		||||
 | 
			
		||||
		// Ignore non-IPv6 packets
 | 
			
		||||
		if binary.BigEndian.Uint16(in.ether.ethertype[:]) != uint16(0x86DD) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Ignore non-ICMPv6 packets
 | 
			
		||||
		if in.ipv6.nextheader != uint8(0x3A) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Ignore non-NDP Solicitation packets
 | 
			
		||||
		if in.icmpv6.messagetype != uint8(135) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Ignore NDP requests for anything outside of fd00::/8
 | 
			
		||||
		if in.targetaddress[0] != 0xFD {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Populate the out ethernet headers
 | 
			
		||||
		copy(out.ether.destination[:], in.ether.destination[:])
 | 
			
		||||
		copy(out.ether.source[:], n.mymac[:])
 | 
			
		||||
		binary.BigEndian.PutUint16(out.ether.ethertype[:], uint16(0x86DD))
 | 
			
		||||
 | 
			
		||||
		// And for now just copy the rest of the packet we were sent
 | 
			
		||||
		copy(dataout[ETHER:ETHER+IPV6], datain[ETHER:ETHER+IPV6])
 | 
			
		||||
 | 
			
		||||
		// Update the source and destination addresses in the IPv6 header
 | 
			
		||||
		copy(out.ipv6.destination[:], in.ipv6.source[:])
 | 
			
		||||
		copy(out.ipv6.source[:], n.mylladdr[:])
 | 
			
		||||
		binary.BigEndian.PutUint16(out.ipv6.length[:], uint16(32))
 | 
			
		||||
 | 
			
		||||
		// Copy the payload
 | 
			
		||||
		copy(dataout[ETHER+IPV6:], datain[ETHER+IPV6:])
 | 
			
		||||
 | 
			
		||||
		// Update the ICMPv6 headers
 | 
			
		||||
		out.icmpv6.messagetype = uint8(136)
 | 
			
		||||
		out.icmpv6.code = uint8(0)
 | 
			
		||||
 | 
			
		||||
		// Update the ICMPv6 payload
 | 
			
		||||
		copy(out.targetaddress[:], in.targetaddress[:])
 | 
			
		||||
		out.optiontype = uint8(2)
 | 
			
		||||
		out.optionlength = uint8(1)
 | 
			
		||||
		copy(out.linklayeraddress[:], n.mymac[:])
 | 
			
		||||
		binary.BigEndian.PutUint32(out.flags[:], uint32(0x20000000))
 | 
			
		||||
 | 
			
		||||
		// Generate the pseudo-header for the checksum
 | 
			
		||||
		ps := make([]byte, 44)
 | 
			
		||||
		pseudo := (*icmpv6PseudoHeader)(unsafe.Pointer(&ps[0]))
 | 
			
		||||
		copy(pseudo.destination[:], out.ipv6.destination[:])
 | 
			
		||||
		copy(pseudo.source[:], out.ipv6.source[:])
 | 
			
		||||
		binary.BigEndian.PutUint32(pseudo.length[:], uint32(binary.BigEndian.Uint16(out.ipv6.length[:])))
 | 
			
		||||
		pseudo.nextheader = out.ipv6.nextheader
 | 
			
		||||
 | 
			
		||||
		// Lazy-man's checksum using the icmp library
 | 
			
		||||
		icmpv6, err := icmp.ParseMessage(0x3A, dataout[ETHER+IPV6:])
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		payload, err := icmpv6.Marshal(ps)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		copy(dataout[ETHER+IPV6:], payload)
 | 
			
		||||
 | 
			
		||||
		// Send the frame back to the TAP adapter
 | 
			
		||||
		n.tun.iface.Write(dataout)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,17 +17,17 @@ type tunInterface interface {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type tunDevice struct {
 | 
			
		||||
	core  *Core
 | 
			
		||||
	ndp   ndp
 | 
			
		||||
	send  chan<- []byte
 | 
			
		||||
	recv  <-chan []byte
 | 
			
		||||
	mtu   int
 | 
			
		||||
	iface tunInterface
 | 
			
		||||
	core   *Core
 | 
			
		||||
	icmpv6 icmpv6
 | 
			
		||||
	send   chan<- []byte
 | 
			
		||||
	recv   <-chan []byte
 | 
			
		||||
	mtu    int
 | 
			
		||||
	iface  tunInterface
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *tunDevice) init(core *Core) {
 | 
			
		||||
	tun.core = core
 | 
			
		||||
	tun.ndp.init(tun)
 | 
			
		||||
	tun.icmpv6.init(tun)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (tun *tunDevice) write() error {
 | 
			
		||||
| 
						 | 
				
			
			@ -36,11 +36,11 @@ func (tun *tunDevice) write() error {
 | 
			
		|||
		if tun.iface.IsTAP() {
 | 
			
		||||
			var frame ethernet.Frame
 | 
			
		||||
			frame.Prepare(
 | 
			
		||||
				tun.ndp.peermac[:6], // Destination MAC address
 | 
			
		||||
				tun.ndp.mymac[:6],   // Source MAC address
 | 
			
		||||
				ethernet.NotTagged,  // VLAN tagging
 | 
			
		||||
				ethernet.IPv6,       // Ethertype
 | 
			
		||||
				len(data))           // Payload length
 | 
			
		||||
				tun.icmpv6.peermac[:6], // Destination MAC address
 | 
			
		||||
				tun.icmpv6.mymac[:6],   // Source MAC address
 | 
			
		||||
				ethernet.NotTagged,     // VLAN tagging
 | 
			
		||||
				ethernet.IPv6,          // Ethertype
 | 
			
		||||
				len(data))              // Payload length
 | 
			
		||||
			copy(frame[ETHER_HEADER_LENGTH:], data[:])
 | 
			
		||||
			if _, err := tun.iface.Write(frame); err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
| 
						 | 
				
			
			@ -68,9 +68,6 @@ func (tun *tunDevice) read() error {
 | 
			
		|||
		o := 0
 | 
			
		||||
		if tun.iface.IsTAP() {
 | 
			
		||||
			o = ETHER_HEADER_LENGTH
 | 
			
		||||
			b := make([]byte, n)
 | 
			
		||||
			copy(b, buf)
 | 
			
		||||
			tun.ndp.recv <- b
 | 
			
		||||
		}
 | 
			
		||||
		if buf[o]&0xf0 != 0x60 ||
 | 
			
		||||
			n != 256*int(buf[o+4])+int(buf[o+5])+IPv6_HEADER_LENGTH+o {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +75,12 @@ func (tun *tunDevice) read() error {
 | 
			
		|||
			//panic("Should not happen in testing")
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if buf[o+6] == 58 {
 | 
			
		||||
			// Found an ICMPv6 packet
 | 
			
		||||
			b := make([]byte, n)
 | 
			
		||||
			copy(b, buf)
 | 
			
		||||
			tun.icmpv6.recv <- b
 | 
			
		||||
		}
 | 
			
		||||
		packet := append(util_getBytes(), buf[o:n]...)
 | 
			
		||||
		tun.send <- packet
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue