wireguard-go/conn_default.go

219 lines
4.4 KiB
Go
Raw Normal View History

2018-05-26 00:59:26 +00:00
// +build !linux android
2017-08-25 12:53:23 +00:00
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2017-2018 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
2018-05-18 22:34:56 +00:00
* Copyright (C) 2017-2018 Mathias N. Hall-Andersen <mathias@hall-andersen.dk>.
*/
2017-08-25 12:53:23 +00:00
package main
import (
2018-05-21 15:27:18 +00:00
"golang.org/x/sys/unix"
2017-08-25 12:53:23 +00:00
"net"
2018-06-11 17:04:38 +00:00
"os"
2018-05-21 15:27:18 +00:00
"runtime"
2018-06-11 17:04:38 +00:00
"syscall"
2017-08-25 12:53:23 +00:00
)
/* This code is meant to be a temporary solution
* on platforms for which the sticky socket / source caching behavior
* has not yet been implemented.
*
* See conn_linux.go for an implementation on the linux platform.
*/
2017-11-18 23:21:58 +00:00
type NativeBind struct {
ipv4 *net.UDPConn
ipv6 *net.UDPConn
}
type NativeEndpoint net.UDPAddr
var _ Bind = (*NativeBind)(nil)
var _ Endpoint = (*NativeEndpoint)(nil)
func CreateEndpoint(s string) (Endpoint, error) {
addr, err := parseEndpoint(s)
return (*NativeEndpoint)(addr), err
2017-11-18 23:21:58 +00:00
}
func (_ *NativeEndpoint) ClearSrc() {}
func (e *NativeEndpoint) DstIP() net.IP {
return (*net.UDPAddr)(e).IP
}
func (e *NativeEndpoint) SrcIP() net.IP {
return nil // not supported
}
2017-11-18 23:21:58 +00:00
func (e *NativeEndpoint) DstToBytes() []byte {
addr := (*net.UDPAddr)(e)
2018-05-18 03:02:35 +00:00
out := addr.IP.To4()
if out == nil {
out = addr.IP
}
2017-11-18 23:21:58 +00:00
out = append(out, byte(addr.Port&0xff))
out = append(out, byte((addr.Port>>8)&0xff))
return out
}
2017-11-18 23:21:58 +00:00
func (e *NativeEndpoint) DstToString() string {
return (*net.UDPAddr)(e).String()
}
func (e *NativeEndpoint) SrcToString() string {
return ""
}
func listenNet(network string, port int) (*net.UDPConn, int, error) {
2017-11-18 23:21:58 +00:00
// listen
conn, err := net.ListenUDP(network, &net.UDPAddr{Port: port})
2017-11-18 23:21:58 +00:00
if err != nil {
return nil, 0, err
}
// retrieve port
laddr := conn.LocalAddr()
uaddr, err := net.ResolveUDPAddr(
2017-11-18 23:21:58 +00:00
laddr.Network(),
laddr.String(),
)
if err != nil {
return nil, 0, err
}
2017-11-18 23:21:58 +00:00
return conn, uaddr.Port, nil
}
2018-06-11 17:04:38 +00:00
func extractErrno(err error) error {
opErr, ok := err.(*net.OpError)
if !ok {
return nil
}
syscallErr, ok := opErr.Err.(*os.SyscallError)
if !ok {
return nil
}
return syscallErr.Err
}
2018-05-14 01:00:40 +00:00
func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
var err error
var bind NativeBind
port := int(uport)
bind.ipv4, port, err = listenNet("udp4", port)
2018-06-11 17:04:38 +00:00
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
return nil, 0, err
}
bind.ipv6, port, err = listenNet("udp6", port)
2018-06-11 17:04:38 +00:00
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
return nil, 0, err
bind.ipv4.Close()
2018-06-11 17:04:38 +00:00
bind.ipv4 = nil
return nil, 0, err
}
return &bind, uint16(port), nil
}
func (bind *NativeBind) Close() error {
2018-06-11 17:04:38 +00:00
var err1, err2 error
if bind.ipv4 != nil {
err1 = bind.ipv4.Close()
}
if bind.ipv6 != nil {
err2 = bind.ipv6.Close()
}
if err1 != nil {
return err1
}
return err2
}
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
2018-06-11 17:04:38 +00:00
if bind.ipv4 == nil {
return 0, nil, syscall.EAFNOSUPPORT
}
n, endpoint, err := bind.ipv4.ReadFromUDP(buff)
2018-05-18 03:02:35 +00:00
if endpoint != nil {
endpoint.IP = endpoint.IP.To4()
}
return n, (*NativeEndpoint)(endpoint), err
}
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
2018-06-11 17:04:38 +00:00
if bind.ipv6 == nil {
return 0, nil, syscall.EAFNOSUPPORT
}
n, endpoint, err := bind.ipv6.ReadFromUDP(buff)
return n, (*NativeEndpoint)(endpoint), err
}
func (bind *NativeBind) Send(buff []byte, endpoint Endpoint) error {
var err error
nend := endpoint.(*NativeEndpoint)
2018-05-18 03:02:35 +00:00
if nend.IP.To4() != nil {
2018-06-11 17:04:38 +00:00
if bind.ipv4 == nil {
return syscall.EAFNOSUPPORT
}
_, err = bind.ipv4.WriteToUDP(buff, (*net.UDPAddr)(nend))
2018-05-18 03:02:35 +00:00
} else {
2018-06-11 17:04:38 +00:00
if bind.ipv6 == nil {
return syscall.EAFNOSUPPORT
}
2018-05-18 03:02:35 +00:00
_, err = bind.ipv6.WriteToUDP(buff, (*net.UDPAddr)(nend))
}
return err
}
2018-05-22 13:17:35 +00:00
var fwmarkIoctl int
func init() {
switch runtime.GOOS {
case "linux", "android":
fwmarkIoctl = 36 /* unix.SO_MARK */
case "freebsd":
2018-05-22 13:17:35 +00:00
fwmarkIoctl = 0x1015 /* unix.SO_USER_COOKIE */
case "openbsd":
2018-05-22 13:17:35 +00:00
fwmarkIoctl = 0x1021 /* unix.SO_RTABLE */
}
}
func (bind *NativeBind) SetMark(mark uint32) error {
if fwmarkIoctl == 0 {
2018-05-21 15:27:18 +00:00
return nil
}
2018-06-11 17:04:38 +00:00
if bind.ipv4 != nil {
fd, err := bind.ipv4.SyscallConn()
if err != nil {
return err
}
err = fd.Control(func(fd uintptr) {
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
})
if err != nil {
return err
}
}
if bind.ipv6 != nil {
fd, err := bind.ipv6.SyscallConn()
if err != nil {
return err
}
err = fd.Control(func(fd uintptr) {
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
})
if err != nil {
return err
}
2018-05-22 13:17:35 +00:00
}
return nil
}