-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
translate_addr.go
163 lines (147 loc) · 6.27 KB
/
translate_addr.go
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package agent
import (
"fmt"
"net"
"github.com/hashicorp/consul/agent/structs"
)
type TranslateAddressAccept int
const (
TranslateAddressAcceptDomain TranslateAddressAccept = 1 << iota
TranslateAddressAcceptIPv4
TranslateAddressAcceptIPv6
TranslateAddressAcceptAny TranslateAddressAccept = ^0
)
// TranslateServicePort is used to provide the final, translated port for a service,
// depending on how the agent and the other node are configured. The dc
// parameter is the dc the datacenter this node is from.
func (a *Agent) TranslateServicePort(dc string, port int, taggedAddresses map[string]structs.ServiceAddress) int {
if a.config.TranslateWANAddrs && (a.config.Datacenter != dc) {
if wanAddr, ok := taggedAddresses[structs.TaggedAddressWAN]; ok && wanAddr.Port != 0 {
return wanAddr.Port
}
}
return port
}
// TranslateServiceAddress is used to provide the final, translated address for a node,
// depending on how the agent and the other node are configured. The dc
// parameter is the dc the datacenter this node is from.
func (a *Agent) TranslateServiceAddress(dc string, addr string, taggedAddresses map[string]structs.ServiceAddress, accept TranslateAddressAccept) string {
def := addr
v4 := taggedAddresses[structs.TaggedAddressLANIPv4].Address
v6 := taggedAddresses[structs.TaggedAddressLANIPv6].Address
shouldUseWan := a.config.TranslateWANAddrs && (a.config.Datacenter != dc)
if shouldUseWan {
if v, ok := taggedAddresses[structs.TaggedAddressWAN]; ok {
def = v.Address
}
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv4]; ok {
v4 = v.Address
}
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv6]; ok {
v6 = v.Address
}
}
return translateAddressAccept(accept, def, v4, v6)
}
// TranslateAddress is used to provide the final, translated address for a node,
// depending on how the agent and the other node are configured. The dc
// parameter is the dc the datacenter this node is from.
func (a *Agent) TranslateAddress(dc string, addr string, taggedAddresses map[string]string, accept TranslateAddressAccept) string {
def := addr
v4 := taggedAddresses[structs.TaggedAddressLANIPv4]
v6 := taggedAddresses[structs.TaggedAddressLANIPv6]
shouldUseWan := a.config.TranslateWANAddrs && (a.config.Datacenter != dc)
if shouldUseWan {
if v, ok := taggedAddresses[structs.TaggedAddressWAN]; ok {
def = v
}
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv4]; ok {
v4 = v
}
if v, ok := taggedAddresses[structs.TaggedAddressWANIPv6]; ok {
v6 = v
}
}
return translateAddressAccept(accept, def, v4, v6)
}
func translateAddressAccept(accept TranslateAddressAccept, def, v4, v6 string) string {
switch {
case accept&TranslateAddressAcceptIPv6 > 0 && v6 != "":
return v6
case accept&TranslateAddressAcceptIPv4 > 0 && v4 != "":
return v4
case accept&TranslateAddressAcceptAny > 0 && def != "":
return def
default:
defIP := net.ParseIP(def)
switch {
case defIP != nil && defIP.To4() != nil && accept&TranslateAddressAcceptIPv4 > 0:
return def
case defIP != nil && defIP.To4() == nil && accept&TranslateAddressAcceptIPv6 > 0:
return def
case defIP == nil && accept&TranslateAddressAcceptDomain > 0:
return def
}
}
return ""
}
// TranslateAddresses translates addresses in the given structure into the
// final, translated address, depending on how the agent and the other node are
// configured. The dc parameter is the datacenter this structure is from.
func (a *Agent) TranslateAddresses(dc string, subj interface{}, accept TranslateAddressAccept) {
// CAUTION - SUBTLE! An agent running on a server can, in some cases,
// return pointers directly into the immutable state store for
// performance (it's via the in-memory RPC mechanism). It's never safe
// to modify those values, so we short circuit here so that we never
// update any structures that are from our own datacenter. This works
// for address translation because we *never* need to translate local
// addresses, but this is super subtle, so we've piped all the in-place
// address translation into this function which makes sure this check is
// done. This also happens to skip looking at any of the incoming
// structure for the common case of not needing to translate, so it will
// skip a lot of work if no translation needs to be done.
if !a.config.TranslateWANAddrs || (a.config.Datacenter == dc) {
return
}
// Translate addresses in-place, subject to the condition checked above
// which ensures this is safe to do since we are operating on a local
// copy of the data.
switch v := subj.(type) {
case structs.CheckServiceNodes:
for _, entry := range v {
entry.Node.Address = a.TranslateAddress(dc, entry.Node.Address, entry.Node.TaggedAddresses, accept)
entry.Service.Address = a.TranslateServiceAddress(dc, entry.Service.Address, entry.Service.TaggedAddresses, accept)
entry.Service.Port = a.TranslateServicePort(dc, entry.Service.Port, entry.Service.TaggedAddresses)
}
case *structs.Node:
v.Address = a.TranslateAddress(dc, v.Address, v.TaggedAddresses, accept)
case structs.Nodes:
for _, node := range v {
node.Address = a.TranslateAddress(dc, node.Address, node.TaggedAddresses, accept)
}
case structs.ServiceNodes:
for _, entry := range v {
entry.Address = a.TranslateAddress(dc, entry.Address, entry.TaggedAddresses, accept)
entry.ServiceAddress = a.TranslateServiceAddress(dc, entry.ServiceAddress, entry.ServiceTaggedAddresses, accept)
entry.ServicePort = a.TranslateServicePort(dc, entry.ServicePort, entry.ServiceTaggedAddresses)
}
case *structs.NodeServices:
if v.Node != nil {
v.Node.Address = a.TranslateAddress(dc, v.Node.Address, v.Node.TaggedAddresses, accept)
}
for _, entry := range v.Services {
entry.Address = a.TranslateServiceAddress(dc, entry.Address, entry.TaggedAddresses, accept)
entry.Port = a.TranslateServicePort(dc, entry.Port, entry.TaggedAddresses)
}
case *structs.NodeServiceList:
if v.Node != nil {
v.Node.Address = a.TranslateAddress(dc, v.Node.Address, v.Node.TaggedAddresses, accept)
}
for _, entry := range v.Services {
entry.Address = a.TranslateServiceAddress(dc, entry.Address, entry.TaggedAddresses, accept)
entry.Port = a.TranslateServicePort(dc, entry.Port, entry.TaggedAddresses)
}
default:
panic(fmt.Errorf("Unhandled type passed to address translator: %#v", subj))
}
}