Skip to content

Commit fd359ff

Browse files
authored
Add load balancer IPs to "localIPs" (#167)
* Adds a function to add load balancer IPs to localIPs variable * Adds log statement when a LB IP is added to localIPs * Causes loadbalancerIPs() to work for both IP and CIDR formats The values being parsed were ultimately fetched from the GCE VM metadata server. The server seems to return IPv4 addresses in standard dotted decimal notation, while IPv6 addresses are returned in CIDR format. * Log errors from findDestination() findDestination() returns an err, but it was previously unused other than to check whether it was nil or not. This change just prints the error to help in debugging. * Bumps Go version to v1.21 * Adds loadbalancer IPs to handler.LocalIPs This allows traceroute-caller to recognize the loadbalancer IPs as "local". Without this traceroute-caller will fail to recognize its own (loadbalanced) IP addresses and will not run any traces. * Removes pointer from slice-of-pointers h.LocalIPs of type []*net.IP Instead it is now just []net.IP, which is easier to work with. * Updates Go to v1.21 in Travis-CI config * Reverts Travis-CI config Go version back to v1.20 (1.21 not supported?) * Sets Go version in Travis config back to 1.21, but in double quotes * Reverts back to Go v1.20 in Travis-CI config (1.21 not supported)
1 parent 8840b69 commit fd359ff

File tree

5 files changed

+131
-10
lines changed

5 files changed

+131
-10
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
language: go
22
go:
3-
- 1.20
3+
- "1.20"
44

55
before_install:
66
- go install github.com/mattn/goveralls@latest

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/m-lab/traceroute-caller
22

3-
go 1.20
3+
go 1.21
44

55
require (
66
github.com/go-test/deep v1.0.7

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
120120
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
121121
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
122122
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d h1:r3mStZSyjKhEcgbJ5xtv7kT5PZw/tDiFBTMgQx2qsXE=
123+
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
123124
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
124125
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
125126
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -224,6 +225,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
224225
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
225226
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
226227
github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M=
228+
github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU=
227229
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
228230
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
229231
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -232,6 +234,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
232234
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
233235
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
234236
github.com/m-lab/annotation-service v0.0.0-20210504151333-138bdf572368 h1:cRzgLEJxoMI0iSexWOxTZQR/gNG08ra1IoEEgwJBdgs=
237+
github.com/m-lab/annotation-service v0.0.0-20210504151333-138bdf572368/go.mod h1:bW5A2AmUqyh6kGbmu4X8fYK2pRcfTvTjAXW/+4VQZUA=
235238
github.com/m-lab/go v0.1.66 h1:adDJILqKBCkd5YeVhCrrjWkjoNRtDzlDr6uizWu5/pE=
236239
github.com/m-lab/go v0.1.66/go.mod h1:O1D/EoVarJ8lZt9foANcqcKtwxHatBzUxXFFyC87aQQ=
237240
github.com/m-lab/tcp-info v1.5.3 h1:4IspTPcNc8D8LNRvuFnID8gDiz+hxPAtYvpKZaiGGe8=
@@ -298,6 +301,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
298301
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
299302
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
300303
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
304+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
301305
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
302306
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
303307
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

internal/triggertrace/triggertrace.go

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@ package triggertrace
66

77
import (
88
"context"
9+
"errors"
910
"fmt"
1011
"log"
1112
"net"
13+
"os"
14+
"strings"
1215
"sync"
1316
"time"
1417

@@ -23,6 +26,7 @@ import (
2326
var (
2427
// Variables to aid in black-box testing.
2528
netInterfaceAddrs = net.InterfaceAddrs
29+
metadataDir = "/metadata"
2630
)
2731

2832
// Destination is the host to run a traceroute to.
@@ -61,7 +65,7 @@ type TracerWriter interface {
6165
type Handler struct {
6266
Destinations map[string]Destination // key is UUID
6367
DestinationsLock sync.Mutex
64-
LocalIPs []*net.IP
68+
LocalIPs []net.IP
6569
IPCache FetchTracer
6670
Parser ParseTracer
6771
HopAnnotator AnnotateAndArchiver
@@ -76,7 +80,7 @@ func NewHandler(ctx context.Context, tracetool TracerWriter, ipcCfg ipcache.Conf
7680
if err != nil {
7781
return nil, err
7882
}
79-
myIPs, err := localIPs()
83+
myIPs, err := localIPs(metadataDir)
8084
if err != nil {
8185
return nil, err
8286
}
@@ -115,7 +119,7 @@ func (h *Handler) Open(ctx context.Context, timestamp time.Time, uuid string, so
115119
defer h.DestinationsLock.Unlock()
116120
destination, err := h.findDestination(sockID)
117121
if err != nil {
118-
log.Printf("context %p: failed to find destination from SockID %+v\n", ctx, *sockID)
122+
log.Printf("context %p: failed to find destination from SockID %+v: %v\n", ctx, *sockID, err)
119123
return
120124
}
121125
h.Destinations[uuid] = destination
@@ -220,12 +224,13 @@ func (h *Handler) findDestination(sockid *inetdiag.SockID) (Destination, error)
220224
}
221225

222226
// localIPs returns the list of system's unicast interface addresses.
223-
func localIPs() ([]*net.IP, error) {
224-
localIPs := make([]*net.IP, 0)
227+
func localIPs(metadataDir string) ([]net.IP, error) {
228+
localIPs := make([]net.IP, 0)
225229
addrs, err := netInterfaceAddrs()
226230
if err != nil {
227231
return localIPs, err
228232
}
233+
229234
for _, addr := range addrs {
230235
var ip net.IP
231236
switch a := addr.(type) {
@@ -237,8 +242,62 @@ func localIPs() ([]*net.IP, error) {
237242
return localIPs, fmt.Errorf("unknown address type %q", addr.String())
238243
}
239244
if ip != nil {
240-
localIPs = append(localIPs, &ip)
245+
localIPs = append(localIPs, ip)
241246
}
242247
}
248+
249+
localIPs, err = loadbalancerIPs(localIPs, metadataDir)
250+
if err != nil {
251+
return localIPs, err
252+
}
253+
254+
return localIPs, nil
255+
}
256+
257+
// loadbalancerIPs returns the public IP addresses, if any, of a load balancer
258+
// that may sit in front of the machine. Not all machines site in front of a
259+
// load balancer, so this function may return the the same []*net.IP that was
260+
// passed to it. This function is necessary because traceroute-caller needs to
261+
// recognize the load balancer IPs as "local", else it will fail to identify a
262+
// proper destination, and will exit with an error, producing no traceroute data.
263+
func loadbalancerIPs(localIPs []net.IP, metadataDir string) ([]net.IP, error) {
264+
var ip net.IP
265+
266+
// While every machine _should_ have a /metadata/loadbalanced file, for now
267+
// consider its non-existence to mean that the machine is not load balanced.
268+
if _, err := os.Stat(metadataDir + "/loadbalanced"); errors.Is(err, os.ErrNotExist) {
269+
return localIPs, nil
270+
}
271+
272+
lb, err := os.ReadFile(metadataDir + "/loadbalanced")
273+
if err != nil {
274+
return localIPs, fmt.Errorf("unable to read file %s/loadbalanced: %v", metadataDir, err)
275+
}
276+
277+
// If the machine isn't load balanced, then just return localIPs unmodified.
278+
if string(lb) == "false" {
279+
return localIPs, nil
280+
}
281+
282+
for _, f := range []string{"external-ip", "external-ipv6"} {
283+
ipBytes, err := os.ReadFile(metadataDir + "/" + f)
284+
if err != nil {
285+
return localIPs, fmt.Errorf("unable to read file %s/%s: %v", metadataDir, f, err)
286+
}
287+
ipString := string(ipBytes)
288+
289+
// GCE metadata for key "forwarded-ipv6s" is returned in CIDR format.
290+
if strings.Contains(ipString, "/") {
291+
ip, _, _ = net.ParseCIDR(ipString)
292+
} else {
293+
ip = net.ParseIP(ipString)
294+
}
295+
if ip == nil {
296+
return localIPs, fmt.Errorf("failed to parse IP: %s", ipString)
297+
}
298+
localIPs = append(localIPs, ip)
299+
log.Printf("added load balancer IP %s to localIPs\n", ip.String())
300+
}
301+
243302
return localIPs, nil
244303
}

internal/triggertrace/triggertrace_test.go

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ func (fa *fakeAnnotator) Annotate(ctx context.Context, ips []string) (map[string
106106
}
107107

108108
func TestNewHandler(t *testing.T) {
109+
var strV4 string = "77.77.88.88"
110+
var strV6 string = "7777:77:888:88::"
111+
112+
metadataDir = "./testdata/metadata"
113+
109114
saveNetInterfaceAddrs := netInterfaceAddrs
110115
defer func() { netInterfaceAddrs = saveNetInterfaceAddrs }()
111116

@@ -114,10 +119,63 @@ func TestNewHandler(t *testing.T) {
114119
t.Fatalf("NewHandler() = nil, want error")
115120
}
116121

122+
// Set up metadata files
123+
os.MkdirAll(metadataDir, 0755)
124+
os.WriteFile(metadataDir+"/loadbalanced", []byte("true"), 0644)
125+
os.WriteFile(metadataDir+"/external-ip", []byte(strV4), 0644)
126+
os.WriteFile(metadataDir+"/external-ipv6", []byte(strV6), 0644)
127+
defer os.RemoveAll(metadataDir)
128+
117129
netInterfaceAddrs = fakeInterfaceAddrs
118-
if _, err := newHandler(t, &fakeTracer{}); err != nil {
130+
handler, err := newHandler(t, &fakeTracer{})
131+
addrCount := len(handler.LocalIPs)
132+
133+
if err != nil {
119134
t.Fatalf("NewHandler() = %v, want nil", err)
120135
}
136+
137+
var ipv4 net.IP = net.ParseIP(strV4)
138+
var ipv6 net.IP = net.ParseIP(strV6)
139+
140+
ok := false
141+
for _, v := range handler.LocalIPs {
142+
if v.Equal(ipv4) {
143+
ok = true
144+
break
145+
}
146+
}
147+
if !ok {
148+
t.Fatalf("NewHandler(): h.LocalIPs does not contain loadbalancer IP %s", strV4)
149+
}
150+
151+
ok = false
152+
for _, v := range handler.LocalIPs {
153+
if v.Equal(ipv6) {
154+
ok = true
155+
break
156+
}
157+
}
158+
if !ok {
159+
t.Fatalf("NewHandler(): h.LocalIPs does not contain loadbalancer IP %s", strV6)
160+
}
161+
162+
// Setting loadbalanced=false should result in the original addrCount to
163+
// stay the same, since loadbalancerIPs() should return localIPs unmodified.
164+
os.WriteFile(metadataDir+"/loadbalanced", []byte("false"), 0644)
165+
handler, _ = newHandler(t, &fakeTracer{})
166+
if len(handler.LocalIPs) > addrCount {
167+
t.Fatalf("NewHandler(): LocalIPs has %d addresses, but should have %d", len(handler.LocalIPs), addrCount)
168+
}
169+
170+
// If the metadata file loadbalanced doesn't exist then the original
171+
// addrCount should stay the same, since loadbalancerIPs() should return
172+
// localIPs unmodified.
173+
os.Remove(metadataDir + "/loadbalanced")
174+
handler, _ = newHandler(t, &fakeTracer{})
175+
if len(handler.LocalIPs) > addrCount {
176+
t.Fatalf("NewHandler(): LocalIPs has %d addresses, but should have %d", len(handler.LocalIPs), addrCount)
177+
}
178+
121179
}
122180

123181
func TestOpen(t *testing.T) {
@@ -362,7 +420,7 @@ func TestAnonymize(t *testing.T) {
362420
t.Fatalf("NewHandler() = %v, want nil", err)
363421
}
364422
l := net.ParseIP(tt.input.Tracelb.Src)
365-
h.LocalIPs = []*net.IP{&l}
423+
h.LocalIPs = []net.IP{l}
366424
h.done = make(chan struct{})
367425
sockID := &inetdiag.SockID{SrcIP: tt.input.Tracelb.Src, DstIP: tt.input.Tracelb.Dst}
368426
h.Open(context.TODO(), time.Now(), tt.name, sockID)

0 commit comments

Comments
 (0)