Add some error handling and other fixes to icmpv6.go

This commit is contained in:
Neil Alexander 2018-02-12 19:40:13 +00:00
parent be0d6feeba
commit fac4bf796e

View File

@ -6,6 +6,7 @@ package yggdrasil
import "golang.org/x/net/icmp" import "golang.org/x/net/icmp"
import "encoding/binary" import "encoding/binary"
import "errors"
import "unsafe" // TODO investigate if this can be done without resorting to unsafe import "unsafe" // TODO investigate if this can be done without resorting to unsafe
type macAddress [6]byte type macAddress [6]byte
@ -89,54 +90,77 @@ func (i *icmpv6) listen() {
if i.tun.iface.IsTAP() { if i.tun.iface.IsTAP() {
// TAP mode // TAP mode
dataout := make([]byte, ETHER+IPV6+32) response, err := i.parse_packet_tap(datain)
i.read_tap(datain, dataout) if err != nil {
i.tun.iface.Write(dataout) i.tun.core.log.Printf("Error from icmpv6.parse_packet_tap: %v", err)
continue
}
if response != nil {
i.tun.iface.Write(response)
}
} else { } else {
// TUN mode // TUN mode
dataout := make([]byte, IPV6+32) response, err := i.parse_packet_tun(datain)
i.read_tun(datain, dataout) if err != nil {
i.tun.iface.Write(dataout) i.tun.core.log.Printf("Error from icmpv6.parse_packet_tun: %v", err)
continue
}
if response != nil {
i.tun.iface.Write(response)
}
} }
} }
} }
func (i *icmpv6) read_tap(datain []byte, dataout []byte) { func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
// Set up // Set up
in := (*icmpv6Frame)(unsafe.Pointer(&datain[0])) in := (*icmpv6Frame)(unsafe.Pointer(&datain[0]))
out := (*icmpv6Frame)(unsafe.Pointer(&dataout[0]))
// Store the peer MAC address // Store the peer MAC address
copy(i.peermac[:6], in.ether.source[:6]) copy(i.peermac[:6], in.ether.source[:6])
// Ignore non-IPv6 frames // Ignore non-IPv6 frames
if binary.BigEndian.Uint16(in.ether.ethertype[:]) != uint16(0x86DD) { if binary.BigEndian.Uint16(in.ether.ethertype[:]) != uint16(0x86DD) {
return return nil, nil
} }
// Populate the out ethernet headers // Create the response buffer
dataout := make([]byte, ETHER+IPV6+32)
out := (*icmpv6Frame)(unsafe.Pointer(&dataout[0]))
// Populate the response ethernet headers
copy(out.ether.destination[:], in.ether.destination[:]) copy(out.ether.destination[:], in.ether.destination[:])
copy(out.ether.source[:], i.mymac[:]) copy(out.ether.source[:], i.mymac[:])
binary.BigEndian.PutUint16(out.ether.ethertype[:], uint16(0x86DD)) binary.BigEndian.PutUint16(out.ether.ethertype[:], uint16(0x86DD))
// And for now just copy the rest of the packet we were sent // Hand over to parse_packet_tun to interpret the IPv6 packet
copy(dataout[ETHER:ETHER+IPV6], datain[ETHER:ETHER+IPV6]) ipv6packet, err := i.parse_packet_tun(datain)
if err != nil {
return nil, nil
}
// Then pass the IP packet onto the next function // Copy the returned packet to our response ethernet frame
i.read_tun(datain[ETHER:], dataout[ETHER:]) if ipv6packet != nil {
copy(dataout[ETHER:ETHER+IPV6], ipv6packet)
return dataout, nil
}
// At this point there is no response to send back
return nil, nil
} }
func (i *icmpv6) read_tun(datain []byte, dataout []byte) { func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
// Set up // Set up
in := (*icmpv6Packet)(unsafe.Pointer(&datain[0])) dataout := make([]byte, IPV6+32)
out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0])) out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0]))
in := (*icmpv6Packet)(unsafe.Pointer(&datain[0]))
// Store the peer link-local address // Store the peer link-local address
copy(i.peerlladdr[:16], in.ipv6.source[:16]) copy(i.peerlladdr[:16], in.ipv6.source[:16])
// Ignore non-ICMPv6 packets // Ignore non-ICMPv6 packets
if in.ipv6.nextheader != uint8(0x3A) { if in.ipv6.nextheader != uint8(0x3A) {
return return nil, nil
} }
// What is the ICMPv6 message type? // What is the ICMPv6 message type?
@ -155,10 +179,16 @@ func (i *icmpv6) read_tun(datain []byte, dataout []byte) {
copy(dataout[IPV6:], datain[IPV6:]) copy(dataout[IPV6:], datain[IPV6:])
// Calculate the checksum // Calculate the checksum
i.calculate_checksum(dataout) err := i.calculate_checksum(dataout)
if err != nil {
return nil, err
}
// Return the response packet
return dataout, nil
} }
func (i *icmpv6) calculate_checksum(dataout []byte) { func (i *icmpv6) calculate_checksum(dataout []byte) (error) {
// Set up // Set up
out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0])) out := (*icmpv6Packet)(unsafe.Pointer(&dataout[0]))
@ -173,15 +203,18 @@ func (i *icmpv6) calculate_checksum(dataout []byte) {
// Lazy-man's checksum using the icmp library // Lazy-man's checksum using the icmp library
icmpv6, err := icmp.ParseMessage(0x3A, dataout[IPV6:]) icmpv6, err := icmp.ParseMessage(0x3A, dataout[IPV6:])
if err != nil { if err != nil {
return return err
} }
// And copy the payload // And copy the payload
payload, err := icmpv6.Marshal(ps) payload, err := icmpv6.Marshal(ps)
if err != nil { if err != nil {
return return err
} }
copy(dataout[IPV6:], payload) copy(dataout[IPV6:], payload)
// Return nil if successful
return nil
} }
func (i *icmpv6) handle_ndp(in *icmpv6Payload, out *icmpv6Payload) { func (i *icmpv6) handle_ndp(in *icmpv6Payload, out *icmpv6Payload) {