2024-04-03 21:02:36 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
package prober_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/netip"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"tailscale.com/prober"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
every30s = 30 * time.Second
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
hostname = flag.String("hostname", "tailscale.com", "hostname to probe")
|
|
|
|
oneshot = flag.Bool("oneshot", true, "run probes once and exit")
|
|
|
|
verbose = flag.Bool("verbose", false, "enable verbose logging")
|
|
|
|
)
|
|
|
|
|
|
|
|
// This example demonstrates how to use ForEachAddr to create a TLS probe for
|
|
|
|
// each IP address in the DNS record of a given hostname.
|
|
|
|
func ExampleForEachAddr() {
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
p := prober.New().WithSpread(true)
|
|
|
|
if *oneshot {
|
|
|
|
p = p.WithOnce(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is called every time we discover a new IP address to check.
|
2024-04-04 16:47:37 +00:00
|
|
|
makeTLSProbe := func(addr netip.Addr) []*prober.Probe {
|
2024-04-03 21:02:36 +00:00
|
|
|
pf := prober.TLSWithIP(*hostname, netip.AddrPortFrom(addr, 443))
|
|
|
|
if *verbose {
|
|
|
|
logger := logger.WithPrefix(log.Printf, fmt.Sprintf("[tls %s]: ", addr))
|
|
|
|
pf = probeLogWrapper(logger, pf)
|
|
|
|
}
|
|
|
|
|
2024-04-04 16:47:37 +00:00
|
|
|
probe := p.Run(fmt.Sprintf("website/%s/tls", addr), every30s, nil, pf)
|
|
|
|
return []*prober.Probe{probe}
|
2024-04-03 21:02:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Determine whether to use IPv4 or IPv6 based on whether we can create
|
|
|
|
// an IPv6 listening socket on localhost.
|
|
|
|
sock, err := net.Listen("tcp", "[::1]:0")
|
|
|
|
supportsIPv6 := err == nil
|
|
|
|
if sock != nil {
|
|
|
|
sock.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
networks := []string{"ip4"}
|
|
|
|
if supportsIPv6 {
|
|
|
|
networks = append(networks, "ip6")
|
|
|
|
}
|
|
|
|
|
|
|
|
var vlogf logger.Logf = logger.Discard
|
|
|
|
if *verbose {
|
|
|
|
vlogf = log.Printf
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the outer probe that resolves the hostname and creates a new
|
|
|
|
// TLS probe for each IP.
|
|
|
|
p.Run("website/dns", every30s, nil, prober.ForEachAddr(*hostname, makeTLSProbe, prober.ForEachAddrOpts{
|
|
|
|
Logf: vlogf,
|
|
|
|
Networks: networks,
|
|
|
|
}))
|
|
|
|
|
|
|
|
defer log.Printf("done")
|
|
|
|
|
|
|
|
// Wait until all probes have run if we're running in oneshot mode.
|
|
|
|
if *oneshot {
|
|
|
|
p.Wait()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, wait until we get a signal.
|
|
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(sigCh, os.Interrupt)
|
|
|
|
<-sigCh
|
|
|
|
}
|
|
|
|
|
2024-03-27 15:13:34 +00:00
|
|
|
func probeLogWrapper(logf logger.Logf, pc prober.ProbeClass) prober.ProbeClass {
|
|
|
|
return prober.ProbeClass{
|
|
|
|
Probe: func(ctx context.Context) error {
|
|
|
|
logf("starting probe")
|
|
|
|
err := pc.Probe(ctx)
|
|
|
|
logf("probe finished with %v", err)
|
|
|
|
return err
|
|
|
|
},
|
2024-04-03 21:02:36 +00:00
|
|
|
}
|
|
|
|
}
|