mirror of
				https://git.zx2c4.com/wireguard-go
				synced 2025-11-01 04:12:47 +08:00 
			
		
		
		
	Definition of platform specific socket bind
This commit is contained in:
		| @@ -56,7 +56,7 @@ func updateUDPConn(device *Device) error { | ||||
|  | ||||
| 		// set fwmark | ||||
|  | ||||
| 		err = setMark(netc.conn, netc.fwmark) | ||||
| 		err = SetMark(netc.conn, netc.fwmark) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|   | ||||
| @@ -6,6 +6,6 @@ import ( | ||||
| 	"net" | ||||
| ) | ||||
|  | ||||
| func setMark(conn *net.UDPConn, value uint32) error { | ||||
| func SetMark(conn *net.UDPConn, value uint32) error { | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -14,23 +14,30 @@ import ( | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| import "fmt" | ||||
|  | ||||
| /* Supports source address caching | ||||
|  * | ||||
|  * It is important that the endpoint is only updated after the packet content has been authenticated. | ||||
|  * | ||||
|  * Currently there is no way to achieve this within the net package: | ||||
|  * See e.g. https://github.com/golang/go/issues/17930 | ||||
|  * So this code is platform dependent. | ||||
|  * | ||||
|  * It is important that the endpoint is only updated after the packet content has been authenticated! | ||||
|  */ | ||||
|  | ||||
| type Endpoint struct { | ||||
| 	// source (selected based on dst type) | ||||
| 	// (could use RawSockaddrAny and unsafe) | ||||
| 	srcIPv6 unix.RawSockaddrInet6 | ||||
| 	srcIPv4 unix.RawSockaddrInet4 | ||||
| 	srcIf4  int32 | ||||
| 	src6   unix.RawSockaddrInet6 | ||||
| 	src4   unix.RawSockaddrInet4 | ||||
| 	src4if int32 | ||||
|  | ||||
| 	dst unix.RawSockaddrAny | ||||
| } | ||||
|  | ||||
| type IPv4Socket int | ||||
| type IPv6Socket int | ||||
|  | ||||
| func zoneToUint32(zone string) (uint32, error) { | ||||
| 	if zone == "" { | ||||
| 		return 0, nil | ||||
| @@ -42,10 +49,115 @@ func zoneToUint32(zone string) (uint32, error) { | ||||
| 	return uint32(n), err | ||||
| } | ||||
|  | ||||
| func CreateIPv4Socket(port int) (IPv4Socket, error) { | ||||
|  | ||||
| 	// create socket | ||||
|  | ||||
| 	fd, err := unix.Socket( | ||||
| 		unix.AF_INET, | ||||
| 		unix.SOCK_DGRAM, | ||||
| 		0, | ||||
| 	) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
|  | ||||
| 	// set sockopts and bind | ||||
|  | ||||
| 	if err := func() error { | ||||
|  | ||||
| 		if err := unix.SetsockoptInt( | ||||
| 			fd, | ||||
| 			unix.SOL_SOCKET, | ||||
| 			unix.SO_REUSEADDR, | ||||
| 			1, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if err := unix.SetsockoptInt( | ||||
| 			fd, | ||||
| 			unix.IPPROTO_IP, | ||||
| 			unix.IP_PKTINFO, | ||||
| 			1, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		addr := unix.SockaddrInet4{ | ||||
| 			Port: port, | ||||
| 		} | ||||
| 		return unix.Bind(fd, &addr) | ||||
|  | ||||
| 	}(); err != nil { | ||||
| 		unix.Close(fd) | ||||
| 	} | ||||
|  | ||||
| 	return IPv4Socket(fd), err | ||||
| } | ||||
|  | ||||
| func CreateIPv6Socket(port int) (IPv6Socket, error) { | ||||
|  | ||||
| 	// create socket | ||||
|  | ||||
| 	fd, err := unix.Socket( | ||||
| 		unix.AF_INET, | ||||
| 		unix.SOCK_DGRAM, | ||||
| 		0, | ||||
| 	) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
|  | ||||
| 	// set sockopts and bind | ||||
|  | ||||
| 	if err := func() error { | ||||
|  | ||||
| 		if err := unix.SetsockoptInt( | ||||
| 			fd, | ||||
| 			unix.SOL_SOCKET, | ||||
| 			unix.SO_REUSEADDR, | ||||
| 			1, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if err := unix.SetsockoptInt( | ||||
| 			fd, | ||||
| 			unix.IPPROTO_IPV6, | ||||
| 			unix.IPV6_RECVPKTINFO, | ||||
| 			1, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if err := unix.SetsockoptInt( | ||||
| 			fd, | ||||
| 			unix.IPPROTO_IPV6, | ||||
| 			unix.IPV6_V6ONLY, | ||||
| 			1, | ||||
| 		); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		addr := unix.SockaddrInet6{ | ||||
| 			Port: port, | ||||
| 		} | ||||
| 		return unix.Bind(fd, &addr) | ||||
|  | ||||
| 	}(); err != nil { | ||||
| 		unix.Close(fd) | ||||
| 	} | ||||
|  | ||||
| 	return IPv6Socket(fd), err | ||||
| } | ||||
|  | ||||
| func (end *Endpoint) ClearSrc() { | ||||
| 	end.srcIf4 = 0 | ||||
| 	end.srcIPv4 = unix.RawSockaddrInet4{} | ||||
| 	end.srcIPv6 = unix.RawSockaddrInet6{} | ||||
| 	end.src4if = 0 | ||||
| 	end.src4 = unix.RawSockaddrInet4{} | ||||
| 	end.src6 = unix.RawSockaddrInet6{} | ||||
| } | ||||
|  | ||||
| func (end *Endpoint) Set(s string) error { | ||||
| @@ -85,8 +197,10 @@ func (end *Endpoint) Set(s string) error { | ||||
| } | ||||
|  | ||||
| func send6(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| 	var iovec unix.Iovec | ||||
|  | ||||
| 	// construct message header | ||||
|  | ||||
| 	var iovec unix.Iovec | ||||
| 	iovec.Base = (*byte)(unsafe.Pointer(&buff[0])) | ||||
| 	iovec.SetLen(len(buff)) | ||||
|  | ||||
| @@ -100,8 +214,8 @@ func send6(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| 			Len:   unix.SizeofInet6Pktinfo, | ||||
| 		}, | ||||
| 		unix.Inet6Pktinfo{ | ||||
| 			Addr:    end.srcIPv6.Addr, | ||||
| 			Ifindex: end.srcIPv6.Scope_id, | ||||
| 			Addr:    end.src6.Addr, | ||||
| 			Ifindex: end.src6.Scope_id, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| @@ -130,8 +244,10 @@ func send6(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| } | ||||
|  | ||||
| func send4(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| 	var iovec unix.Iovec | ||||
|  | ||||
| 	// construct message header | ||||
|  | ||||
| 	var iovec unix.Iovec | ||||
| 	iovec.Base = (*byte)(unsafe.Pointer(&buff[0])) | ||||
| 	iovec.SetLen(len(buff)) | ||||
|  | ||||
| @@ -142,11 +258,11 @@ func send4(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| 		unix.Cmsghdr{ | ||||
| 			Level: unix.IPPROTO_IP, | ||||
| 			Type:  unix.IP_PKTINFO, | ||||
| 			Len:   unix.SizeofInet6Pktinfo, | ||||
| 			Len:   unix.SizeofInet4Pktinfo, | ||||
| 		}, | ||||
| 		unix.Inet4Pktinfo{ | ||||
| 			Spec_dst: end.srcIPv4.Addr, | ||||
| 			Ifindex:  end.srcIf4, | ||||
| 			Spec_dst: end.src4.Addr, | ||||
| 			Ifindex:  end.src4if, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| @@ -174,7 +290,7 @@ func send4(sock uintptr, end *Endpoint, buff []byte) error { | ||||
| 	return errno | ||||
| } | ||||
|  | ||||
| func send(c *net.UDPConn, end *Endpoint, buff []byte) error { | ||||
| func (end *Endpoint) Send(c *net.UDPConn, buff []byte) error { | ||||
|  | ||||
| 	// extract underlying file descriptor | ||||
|  | ||||
| @@ -195,12 +311,9 @@ func send(c *net.UDPConn, end *Endpoint, buff []byte) error { | ||||
| 	return errors.New("Unknown address family of source") | ||||
| } | ||||
|  | ||||
| func receiveIPv4(end *Endpoint, c *net.UDPConn, buff []byte) (error, *net.UDPAddr, *net.UDPAddr) { | ||||
| func (end *Endpoint) ReceiveIPv4(sock IPv4Socket, buff []byte) (int, error) { | ||||
|  | ||||
| 	file, err := c.File() | ||||
| 	if err != nil { | ||||
| 		return err, nil, nil | ||||
| 	} | ||||
| 	// contruct message header | ||||
|  | ||||
| 	var iovec unix.Iovec | ||||
| 	iovec.Base = (*byte)(unsafe.Pointer(&buff[0])) | ||||
| @@ -208,47 +321,92 @@ func receiveIPv4(end *Endpoint, c *net.UDPConn, buff []byte) (error, *net.UDPAdd | ||||
|  | ||||
| 	var cmsg struct { | ||||
| 		cmsghdr unix.Cmsghdr | ||||
| 		pktinfo unix.Inet6Pktinfo // big enough | ||||
| 		pktinfo unix.Inet4Pktinfo | ||||
| 	} | ||||
|  | ||||
| 	var msghdr unix.Msghdr | ||||
| 	msghdr.Iov = &iovec | ||||
| 	msghdr.Iovlen = 1 | ||||
| 	msghdr.Name = (*byte)(unsafe.Pointer(&end.dst)) | ||||
| 	msghdr.Namelen = unix.SizeofSockaddrInet4 | ||||
| 	msghdr.Control = (*byte)(unsafe.Pointer(&cmsg)) | ||||
| 	msghdr.SetControllen(int(unsafe.Sizeof(cmsg))) | ||||
|  | ||||
| 	// recvmsg(sock, &mskhdr, 0) | ||||
|  | ||||
| 	size, _, errno := unix.Syscall( | ||||
| 		unix.SYS_RECVMSG, | ||||
| 		uintptr(sock), | ||||
| 		uintptr(unsafe.Pointer(&msghdr)), | ||||
| 		0, | ||||
| 	) | ||||
|  | ||||
| 	if errno != 0 { | ||||
| 		return 0, errno | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(msghdr) | ||||
| 	fmt.Println(cmsg) | ||||
|  | ||||
| 	// update source cache | ||||
|  | ||||
| 	if cmsg.cmsghdr.Level == unix.IPPROTO_IP && | ||||
| 		cmsg.cmsghdr.Type == unix.IP_PKTINFO && | ||||
| 		cmsg.cmsghdr.Len >= unix.SizeofInet4Pktinfo { | ||||
| 		end.src4.Addr = cmsg.pktinfo.Spec_dst | ||||
| 		end.src4if = cmsg.pktinfo.Ifindex | ||||
| 	} | ||||
|  | ||||
| 	return int(size), nil | ||||
| } | ||||
|  | ||||
| func (end *Endpoint) ReceiveIPv6(sock IPv6Socket, buff []byte) error { | ||||
|  | ||||
| 	// contruct message header | ||||
|  | ||||
| 	var iovec unix.Iovec | ||||
| 	iovec.Base = (*byte)(unsafe.Pointer(&buff[0])) | ||||
| 	iovec.SetLen(len(buff)) | ||||
|  | ||||
| 	var cmsg struct { | ||||
| 		cmsghdr unix.Cmsghdr | ||||
| 		pktinfo unix.Inet6Pktinfo | ||||
| 	} | ||||
|  | ||||
| 	var msg unix.Msghdr | ||||
| 	msg.Iov = &iovec | ||||
| 	msg.Iovlen = 1 | ||||
| 	msg.Name = (*byte)(unsafe.Pointer(&end.dst)) | ||||
| 	msg.Namelen = uint32(unix.SizeofSockaddrAny) | ||||
| 	msg.Namelen = uint32(unix.SizeofSockaddrInet6) | ||||
| 	msg.Control = (*byte)(unsafe.Pointer(&cmsg)) | ||||
| 	msg.SetControllen(int(unsafe.Sizeof(cmsg))) | ||||
|  | ||||
| 	// recvmsg(sock, &mskhdr, 0) | ||||
|  | ||||
| 	_, _, errno := unix.Syscall( | ||||
| 		unix.SYS_RECVMSG, | ||||
| 		file.Fd(), | ||||
| 		uintptr(sock), | ||||
| 		uintptr(unsafe.Pointer(&msg)), | ||||
| 		0, | ||||
| 	) | ||||
|  | ||||
| 	if errno != 0 { | ||||
| 		return errno, nil, nil | ||||
| 		return errno | ||||
| 	} | ||||
|  | ||||
| 	// update source cache | ||||
|  | ||||
| 	if cmsg.cmsghdr.Level == unix.IPPROTO_IPV6 && | ||||
| 		cmsg.cmsghdr.Type == unix.IPV6_PKTINFO && | ||||
| 		cmsg.cmsghdr.Len >= unix.SizeofInet6Pktinfo { | ||||
|  | ||||
| 		end.src6.Addr = cmsg.pktinfo.Addr | ||||
| 		end.src6.Scope_id = cmsg.pktinfo.Ifindex | ||||
| 	} | ||||
|  | ||||
| 	if cmsg.cmsghdr.Level == unix.IPPROTO_IP && | ||||
| 		cmsg.cmsghdr.Type == unix.IP_PKTINFO && | ||||
| 		cmsg.cmsghdr.Len >= unix.SizeofInet4Pktinfo { | ||||
|  | ||||
| 		info := (*unix.Inet4Pktinfo)(unsafe.Pointer(&cmsg.pktinfo)) | ||||
| 		println(info) | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	return nil, nil, nil | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func setMark(conn *net.UDPConn, value uint32) error { | ||||
| func SetMark(conn *net.UDPConn, value uint32) error { | ||||
| 	if conn == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
| @@ -166,7 +166,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError { | ||||
| 				device.net.mutex.Lock() | ||||
| 				if fwmark > 0 || device.net.fwmark > 0 { | ||||
| 					device.net.fwmark = uint32(fwmark) | ||||
| 					err := setMark( | ||||
| 					err := SetMark( | ||||
| 						device.net.conn, | ||||
| 						device.net.fwmark, | ||||
| 					) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Mathias Hall-Andersen
					Mathias Hall-Andersen