diff --git a/main.go b/main.go index 4344720..e94fd68 100644 --- a/main.go +++ b/main.go @@ -31,27 +31,36 @@ func (vx *vx46) transform46(msgs4 []ipv4.Message, msgs6 []ipv6.Message) error { // embed the "client" ipv4 into the src address for the packet to the upstream vxlan ipv6 endpoint // the destination is the upstream vxlan endpoint for i := range msgs4 { - cm4 := ipv4.ControlMessage{} - if err := cm4.Parse(msgs4[i].OOB[:msgs4[i].NN]); err != nil { - return err + if len(msgs6[i].OOB) < OOB_SIZE { + msgs6[i].OOB = make([]byte, OOB_SIZE) + msgs6[i].NN = OOB_SIZE } + var hdr syscall.Cmsghdr + hdr.SetLen(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) + hdr.Level = syscall.IPPROTO_IPV6 + hdr.Type = syscall.IPV6_PKTINFO + + oobdata := msgs6[i].OOB[:0] + + // set cmsg header + oobdata = binary.NativeEndian.AppendUint64(oobdata, hdr.Len) + oobdata = binary.NativeEndian.AppendUint32(oobdata, uint32(hdr.Level)) + oobdata = binary.NativeEndian.AppendUint32(oobdata, uint32(hdr.Type)) + + // set the address + // prefix + embeded v4 + port + oobdata = append(oobdata, vx.natprefix[:10]...) inUDPAddr4 := msgs4[i].Addr.(*net.UDPAddr) - egressSrcAddr := vx.natprefix.As16() - copy(egressSrcAddr[10:14], inUDPAddr4.IP.To4()[:4]) // panics if To4 returns nil - binary.BigEndian.PutUint16(egressSrcAddr[14:16], uint16(inUDPAddr4.Port)) + oobdata = append(oobdata, inUDPAddr4.IP.To4()[:4]...) + oobdata = binary.BigEndian.AppendUint16(oobdata, uint16(inUDPAddr4.Port)) - if vx.oobkey != egressSrcAddr { - vx.oobkey = egressSrcAddr - cm6 := ipv6.ControlMessage{Src: net.IP(egressSrcAddr[:])} - vx.oobcache = cm6.Marshal() - } + // let the kernel decide which interface to use + oobdata = binary.NativeEndian.AppendUint32(oobdata, 0) // iface msgs6[i].Buffers[0] = msgs4[i].Buffers[0][:msgs4[i].N] - msgs6[i].OOB = vx.oobcache msgs6[i].Addr = vx.upstream msgs6[i].N = msgs4[i].N - msgs6[i].NN = len(msgs6[i].OOB) } return nil @@ -93,21 +102,30 @@ func (vx *vx46) transform64(msgs6 []ipv6.Message, msgs4 []ipv4.Message) error { // embed the "client" ipv4 into the src address for the packet to the upstream vxlan ipv6 endpoint // the destination is the upstream vxlan endpoint for i := range msgs6 { - cm6 := ipv6.ControlMessage{} - if err := cm6.Parse(msgs6[i].OOB[:msgs6[i].NN]); err != nil { - return err + var hdr syscall.Cmsghdr + hdr.Len = binary.NativeEndian.Uint64(msgs6[i].OOB[0:]) + hdr.Level = int32(binary.NativeEndian.Uint32(msgs6[i].OOB[8:])) + hdr.Type = int32(binary.NativeEndian.Uint32(msgs6[i].OOB[12:])) + + if hdr.Len != uint64(syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) { + log.Fatal("OOB: unexpected Len: ", hdr.Len, syscall.CmsgLen(syscall.SizeofInet6Pktinfo)) } - if cm6.Dst.To16() == nil { - return fmt.Errorf("Destination information not available") + if hdr.Level != syscall.IPPROTO_IPV6 { + log.Fatal("OOB: unexpected Level", hdr.Level) } + if hdr.Type != syscall.IPV6_PKTINFO { + log.Fatal("OOB: unexpected Type", hdr.Type) + } + + dstaddr6 := msgs6[i].OOB[16:32] msgs4[i].Buffers[0] = msgs6[i].Buffers[0][:msgs6[i].N] if msgs4[i].Addr == nil { msgs4[i].Addr = &net.UDPAddr{} } addr := msgs4[i].Addr.(*net.UDPAddr) - addr.IP = cm6.Dst[10:14] - addr.Port = int(binary.BigEndian.Uint16(cm6.Dst[14:16])) + addr.IP = dstaddr6[10:14] + addr.Port = int(binary.BigEndian.Uint16(dstaddr6[14:16])) msgs4[i].N = msgs6[i].N msgs4[i].OOB = nil msgs4[i].NN = 0 @@ -190,15 +208,12 @@ func (vx *vx46) forward() error { type vx46 struct { pc4 *ipv4.PacketConn pc6 *ipv6.PacketConn - natprefix netip.Addr + natprefix [16]byte upstreamAddr netip.Addr upstream *net.UDPAddr port uint16 mtu uint16 buffers int - - oobkey [16]byte - oobcache []byte } func vx46forward(natprefix netip.Addr, upstreamAddr netip.Addr, port uint16, mtu uint16) error { @@ -309,7 +324,7 @@ func main() { log.Println(vx46forward(natprefix, upstreamAddr, port, mtu)) } else { vx := vx46{ - natprefix: natprefix, + natprefix: natprefix.As16(), upstream: &net.UDPAddr{ IP: net.IP(upstreamAddr.AsSlice()), Port: *portInt,