netsafe_test.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package netsafe
  2. import (
  3. "context"
  4. "net"
  5. "strings"
  6. "testing"
  7. )
  8. func TestIsBlockedIP(t *testing.T) {
  9. cases := []struct {
  10. ip string
  11. want bool
  12. }{
  13. {"127.0.0.1", true},
  14. {"::1", true},
  15. {"10.0.0.5", true},
  16. {"172.16.0.1", true},
  17. {"192.168.1.1", true},
  18. {"169.254.0.1", true},
  19. {"0.0.0.0", true},
  20. {"::", true},
  21. {"8.8.8.8", false},
  22. {"1.1.1.1", false},
  23. {"2606:4700:4700::1111", false},
  24. }
  25. for _, c := range cases {
  26. t.Run(c.ip, func(t *testing.T) {
  27. ip := net.ParseIP(c.ip)
  28. if ip == nil {
  29. t.Fatalf("could not parse %q", c.ip)
  30. }
  31. if got := IsBlockedIP(ip); got != c.want {
  32. t.Fatalf("IsBlockedIP(%s) = %v, want %v", c.ip, got, c.want)
  33. }
  34. })
  35. }
  36. }
  37. func TestAllowPrivateFromContext_Default(t *testing.T) {
  38. if AllowPrivateFromContext(context.Background()) {
  39. t.Fatal("default context should report AllowPrivate=false")
  40. }
  41. }
  42. func TestAllowPrivateFromContext_RoundTrip(t *testing.T) {
  43. ctx := ContextWithAllowPrivate(context.Background(), true)
  44. if !AllowPrivateFromContext(ctx) {
  45. t.Fatal("expected AllowPrivate=true after ContextWithAllowPrivate(true)")
  46. }
  47. ctx = ContextWithAllowPrivate(ctx, false)
  48. if AllowPrivateFromContext(ctx) {
  49. t.Fatal("expected AllowPrivate=false after overriding with false")
  50. }
  51. }
  52. func TestNormalizeHost_Valid(t *testing.T) {
  53. cases := []struct {
  54. in string
  55. want string
  56. }{
  57. {"example.com", "example.com"},
  58. {" example.com ", "example.com"},
  59. {"a.b.c.example.com", "a.b.c.example.com"},
  60. {"10.0.0.1", "10.0.0.1"},
  61. {"[2606:4700:4700::1111]", "2606:4700:4700::1111"},
  62. {"2606:4700:4700::1111", "2606:4700:4700::1111"},
  63. }
  64. for _, c := range cases {
  65. t.Run(c.in, func(t *testing.T) {
  66. got, err := NormalizeHost(c.in)
  67. if err != nil {
  68. t.Fatalf("NormalizeHost(%q) returned error: %v", c.in, err)
  69. }
  70. if !strings.EqualFold(got, c.want) {
  71. t.Fatalf("NormalizeHost(%q) = %q, want %q", c.in, got, c.want)
  72. }
  73. })
  74. }
  75. }
  76. func TestNormalizeHost_Invalid(t *testing.T) {
  77. cases := []string{
  78. "",
  79. " ",
  80. "-leading-dash.com",
  81. "trailing-dash-.com",
  82. "bad host with spaces",
  83. "under_score.example.com",
  84. "exa$mple.com",
  85. strings.Repeat("a", 254),
  86. }
  87. for _, in := range cases {
  88. t.Run(in, func(t *testing.T) {
  89. if _, err := NormalizeHost(in); err == nil {
  90. t.Fatalf("NormalizeHost(%q) expected error, got nil", in)
  91. }
  92. })
  93. }
  94. }
  95. func TestSSRFGuardedDialContext_BlocksLiteralPrivateIP(t *testing.T) {
  96. _, err := SSRFGuardedDialContext(context.Background(), "tcp", "127.0.0.1:1")
  97. if err == nil {
  98. t.Fatal("expected dial to 127.0.0.1 to be blocked")
  99. }
  100. if !strings.Contains(err.Error(), "blocked") {
  101. t.Fatalf("expected 'blocked' in error, got: %v", err)
  102. }
  103. }
  104. func TestSSRFGuardedDialContext_AllowPrivateBypassesGuard(t *testing.T) {
  105. ctx := ContextWithAllowPrivate(context.Background(), true)
  106. _, err := SSRFGuardedDialContext(ctx, "tcp", "127.0.0.1:1")
  107. if err == nil {
  108. t.Fatal("dial to a closed loopback port should still fail at the connect step")
  109. }
  110. if strings.Contains(err.Error(), "blocked private/internal address") {
  111. t.Fatalf("expected guard to be bypassed when AllowPrivate=true, got: %v", err)
  112. }
  113. }
  114. func TestSSRFGuardedDialContext_BadAddress(t *testing.T) {
  115. if _, err := SSRFGuardedDialContext(context.Background(), "tcp", "no-port"); err == nil {
  116. t.Fatal("expected error for address without port")
  117. }
  118. }