asnchecker.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package thoth
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "log/slog"
  7. "net/http"
  8. "strings"
  9. "time"
  10. "github.com/TecharoHQ/anubis/internal"
  11. "github.com/TecharoHQ/anubis/lib/policy/checker"
  12. iptoasnv1 "github.com/TecharoHQ/thoth-proto/gen/techaro/thoth/iptoasn/v1"
  13. )
  14. func (c *Client) ASNCheckerFor(asns []uint32) checker.Impl {
  15. asnMap := map[uint32]struct{}{}
  16. var sb strings.Builder
  17. fmt.Fprintln(&sb, "ASNChecker")
  18. for _, asn := range asns {
  19. asnMap[asn] = struct{}{}
  20. fmt.Fprintln(&sb, "AS", asn)
  21. }
  22. return &ASNChecker{
  23. iptoasn: c.IPToASN,
  24. asns: asnMap,
  25. hash: internal.FastHash(sb.String()),
  26. }
  27. }
  28. type ASNChecker struct {
  29. iptoasn iptoasnv1.IpToASNServiceClient
  30. asns map[uint32]struct{}
  31. hash string
  32. }
  33. func (asnc *ASNChecker) Check(r *http.Request) (bool, error) {
  34. ctx, cancel := context.WithTimeout(r.Context(), 500*time.Millisecond)
  35. defer cancel()
  36. ipInfo, err := asnc.iptoasn.Lookup(ctx, &iptoasnv1.LookupRequest{
  37. IpAddress: r.Header.Get("X-Real-Ip"),
  38. })
  39. if err != nil {
  40. switch {
  41. case errors.Is(err, context.DeadlineExceeded):
  42. slog.Debug("error contacting thoth", "err", err, "actionable", false)
  43. return false, nil
  44. default:
  45. slog.Error("error contacting thoth, please contact support", "err", err, "actionable", true)
  46. return false, nil
  47. }
  48. }
  49. // If IP is not publicly announced, return false
  50. if !ipInfo.GetAnnounced() {
  51. return false, nil
  52. }
  53. _, ok := asnc.asns[uint32(ipInfo.GetAsNumber())]
  54. return ok, nil
  55. }
  56. func (asnc *ASNChecker) Hash() string {
  57. return asnc.hash
  58. }