gitea源码

http.go 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package hostmatcher
  4. import (
  5. "context"
  6. "fmt"
  7. "net"
  8. "net/url"
  9. "syscall"
  10. "time"
  11. )
  12. // NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check
  13. func NewDialContext(usage string, allowList, blockList *HostMatchList, proxy *url.URL) func(ctx context.Context, network, addr string) (net.Conn, error) {
  14. // How Go HTTP Client works with redirection:
  15. // transport.RoundTrip URL=http://domain.com, Host=domain.com
  16. // transport.DialContext addrOrHost=domain.com:80
  17. // dialer.Control tcp4:11.22.33.44:80
  18. // transport.RoundTrip URL=http://www.domain.com/, Host=(empty here, in the direction, HTTP client doesn't fill the Host field)
  19. // transport.DialContext addrOrHost=domain.com:80
  20. // dialer.Control tcp4:11.22.33.44:80
  21. return func(ctx context.Context, network, addrOrHost string) (net.Conn, error) {
  22. dialer := net.Dialer{
  23. // default values comes from http.DefaultTransport
  24. Timeout: 30 * time.Second,
  25. KeepAlive: 30 * time.Second,
  26. Control: func(network, ipAddr string, c syscall.RawConn) error {
  27. host, port, err := net.SplitHostPort(addrOrHost)
  28. if err != nil {
  29. return err
  30. }
  31. if proxy != nil {
  32. // Always allow the host of the proxy, but only on the specified port.
  33. if host == proxy.Hostname() && port == proxy.Port() {
  34. return nil
  35. }
  36. }
  37. // in Control func, the addr was already resolved to IP:PORT format, there is no cost to do ResolveTCPAddr here
  38. tcpAddr, err := net.ResolveTCPAddr(network, ipAddr)
  39. if err != nil {
  40. return fmt.Errorf("%s can only call HTTP servers via TCP, deny '%s(%s:%s)', err=%w", usage, host, network, ipAddr, err)
  41. }
  42. var blockedError error
  43. if blockList.MatchHostOrIP(host, tcpAddr.IP) {
  44. blockedError = fmt.Errorf("%s can not call blocked HTTP servers (check your %s setting), deny '%s(%s)'", usage, blockList.SettingKeyHint, host, ipAddr)
  45. }
  46. // if we have an allow-list, check the allow-list first
  47. if !allowList.IsEmpty() {
  48. if !allowList.MatchHostOrIP(host, tcpAddr.IP) {
  49. return fmt.Errorf("%s can only call allowed HTTP servers (check your %s setting), deny '%s(%s)'", usage, allowList.SettingKeyHint, host, ipAddr)
  50. }
  51. }
  52. // otherwise, we always follow the blocked list
  53. return blockedError
  54. },
  55. }
  56. return dialer.DialContext(ctx, network, addrOrHost)
  57. }
  58. }