github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/hostmatcher/http.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 package hostmatcher 7 8 import ( 9 "context" 10 "fmt" 11 "net" 12 "syscall" 13 "time" 14 ) 15 16 // NewDialContext returns a DialContext for Transport, the DialContext will do allow/block list check 17 func NewDialContext(usage string, allowList, blockList *HostMatchList) func(ctx context.Context, network, addr string) (net.Conn, error) { 18 // How Go HTTP Client works with redirection: 19 // transport.RoundTrip URL=http://domain.com, Host=domain.com 20 // transport.DialContext addrOrHost=domain.com:80 21 // dialer.Control tcp4:11.22.33.44:80 22 // transport.RoundTrip URL=http://www.domain.com/, Host=(empty here, in the direction, HTTP client doesn't fill the Host field) 23 // transport.DialContext addrOrHost=domain.com:80 24 // dialer.Control tcp4:11.22.33.44:80 25 return func(ctx context.Context, network, addrOrHost string) (net.Conn, error) { 26 dialer := net.Dialer{ 27 // default values comes from http.DefaultTransport 28 Timeout: 30 * time.Second, 29 KeepAlive: 30 * time.Second, 30 31 Control: func(network, ipAddr string, c syscall.RawConn) (err error) { 32 var host string 33 if host, _, err = net.SplitHostPort(addrOrHost); err != nil { 34 return err 35 } 36 // in Control func, the addr was already resolved to IP:PORT format, there is no cost to do ResolveTCPAddr here 37 tcpAddr, err := net.ResolveTCPAddr(network, ipAddr) 38 if err != nil { 39 return fmt.Errorf("%s can only call HTTP servers via TCP, deny '%s(%s:%s)', err=%v", usage, host, network, ipAddr, err) 40 } 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 47 // if we have an allow-list, check the allow-list first 48 if !allowList.IsEmpty() { 49 if !allowList.MatchHostOrIP(host, tcpAddr.IP) { 50 return fmt.Errorf("%s can only call allowed HTTP servers (check your %s setting), deny '%s(%s)'", usage, allowList.SettingKeyHint, host, ipAddr) 51 } 52 } 53 // otherwise, we always follow the blocked list 54 return blockedError 55 }, 56 } 57 return dialer.DialContext(ctx, network, addrOrHost) 58 } 59 }