summaryrefslogtreecommitdiffhomepage
path: root/src/conn.go
blob: 3cf00ab5d5f52da0be66c63690f295ee672066bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package main

import (
	"errors"
	"golang.org/x/net/ipv4"
	"golang.org/x/net/ipv6"
	"net"
)

type UDPBind interface {
	SetMark(value uint32) error
	ReceiveIPv6(buff []byte, end *Endpoint) (int, error)
	ReceiveIPv4(buff []byte, end *Endpoint) (int, error)
	Send(buff []byte, end *Endpoint) error
	Close() error
}

/* An Endpoint maintains the source/destination caching for a peer
 *
 * dst : the remote address of a peer
 * src : the local address from which datagrams originate going to the peer
 *
 */
type UDPEndpoint interface {
	ClearSrc()           // clears the source address
	ClearDst()           // clears the destination address
	SrcToString() string // returns the local source address (ip:port)
	DstToString() string // returns the destination address (ip:port)
	DstToBytes() []byte  // used for mac2 cookie calculations
	DstIP() net.IP
	SrcIP() net.IP
}

func parseEndpoint(s string) (*net.UDPAddr, error) {

	// ensure that the host is an IP address

	host, _, err := net.SplitHostPort(s)
	if err != nil {
		return nil, err
	}
	if ip := net.ParseIP(host); ip == nil {
		return nil, errors.New("Failed to parse IP address: " + host)
	}

	// parse address and port

	addr, err := net.ResolveUDPAddr("udp", s)
	if err != nil {
		return nil, err
	}
	return addr, err
}

/* Must hold device and net lock
 */
func unsafeCloseUDPListener(device *Device) error {
	var err error
	netc := &device.net
	if netc.bind != nil {
		err = netc.bind.Close()
		netc.bind = nil
	}
	return err
}

// must inform all listeners
func UpdateUDPListener(device *Device) error {
	device.mutex.Lock()
	defer device.mutex.Unlock()

	netc := &device.net
	netc.mutex.Lock()
	defer netc.mutex.Unlock()

	// close existing sockets

	if err := unsafeCloseUDPListener(device); err != nil {
		return err
	}

	// assumption: netc.update WaitGroup should be exactly 1

	// open new sockets

	if device.tun.isUp.Get() {

		device.log.Debug.Println("UDP bind updating")

		// bind to new port

		var err error
		netc.bind, netc.port, err = CreateUDPBind(netc.port)
		if err != nil {
			netc.bind = nil
			return err
		}

		// set mark

		err = netc.bind.SetMark(netc.fwmark)
		if err != nil {
			return err
		}

		// clear cached source addresses

		for _, peer := range device.peers {
			peer.mutex.Lock()
			peer.endpoint.value.ClearSrc()
			peer.mutex.Unlock()
		}

		// decrease waitgroup to 0

		go device.RoutineReceiveIncomming(ipv4.Version, netc.bind)
		go device.RoutineReceiveIncomming(ipv6.Version, netc.bind)

		device.log.Debug.Println("UDP bind has been updated")
	}

	return nil
}

func CloseUDPListener(device *Device) error {
	device.mutex.Lock()
	device.net.mutex.Lock()
	err := unsafeCloseUDPListener(device)
	device.net.mutex.Unlock()
	device.mutex.Unlock()
	return err
}