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
}
|