dns_example_test.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package prober_test
  4. import (
  5. "context"
  6. "crypto/tls"
  7. "flag"
  8. "fmt"
  9. "log"
  10. "net"
  11. "net/netip"
  12. "os"
  13. "os/signal"
  14. "time"
  15. "tailscale.com/prober"
  16. "tailscale.com/types/logger"
  17. )
  18. const (
  19. every30s = 30 * time.Second
  20. )
  21. var (
  22. hostname = flag.String("hostname", "tailscale.com", "hostname to probe")
  23. oneshot = flag.Bool("oneshot", true, "run probes once and exit")
  24. verbose = flag.Bool("verbose", false, "enable verbose logging")
  25. )
  26. // This example demonstrates how to use ForEachAddr to create a TLS probe for
  27. // each IP address in the DNS record of a given hostname.
  28. func ExampleForEachAddr() {
  29. flag.Parse()
  30. p := prober.New().WithSpread(true)
  31. if *oneshot {
  32. p = p.WithOnce(true)
  33. }
  34. // This function is called every time we discover a new IP address to check.
  35. makeTLSProbe := func(addr netip.Addr) []*prober.Probe {
  36. pf := prober.TLSWithIP(netip.AddrPortFrom(addr, 443), &tls.Config{ServerName: *hostname})
  37. if *verbose {
  38. logger := logger.WithPrefix(log.Printf, fmt.Sprintf("[tls %s]: ", addr))
  39. pf = probeLogWrapper(logger, pf)
  40. }
  41. probe := p.Run(fmt.Sprintf("website/%s/tls", addr), every30s, nil, pf)
  42. return []*prober.Probe{probe}
  43. }
  44. // Determine whether to use IPv4 or IPv6 based on whether we can create
  45. // an IPv6 listening socket on localhost.
  46. sock, err := net.Listen("tcp", "[::1]:0")
  47. supportsIPv6 := err == nil
  48. if sock != nil {
  49. sock.Close()
  50. }
  51. networks := []string{"ip4"}
  52. if supportsIPv6 {
  53. networks = append(networks, "ip6")
  54. }
  55. var vlogf logger.Logf = logger.Discard
  56. if *verbose {
  57. vlogf = log.Printf
  58. }
  59. // This is the outer probe that resolves the hostname and creates a new
  60. // TLS probe for each IP.
  61. p.Run("website/dns", every30s, nil, prober.ForEachAddr(*hostname, makeTLSProbe, prober.ForEachAddrOpts{
  62. Logf: vlogf,
  63. Networks: networks,
  64. }))
  65. defer log.Printf("done")
  66. // Wait until all probes have run if we're running in oneshot mode.
  67. if *oneshot {
  68. p.Wait()
  69. return
  70. }
  71. // Otherwise, wait until we get a signal.
  72. sigCh := make(chan os.Signal, 1)
  73. signal.Notify(sigCh, os.Interrupt)
  74. <-sigCh
  75. }
  76. func probeLogWrapper(logf logger.Logf, pc prober.ProbeClass) prober.ProbeClass {
  77. return prober.ProbeClass{
  78. Probe: func(ctx context.Context) error {
  79. logf("starting probe")
  80. err := pc.Probe(ctx)
  81. logf("probe finished with %v", err)
  82. return err
  83. },
  84. }
  85. }