github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/http/dial_dnscache.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package http 19 20 import ( 21 "context" 22 "net" 23 "time" 24 ) 25 26 // LookupHost is a function to make custom lookupHost for optional cached DNS requests 27 type LookupHost func(ctx context.Context, host string) (addrs []string, err error) 28 29 // DialContextWithLookupHost is a helper function which returns `net.DialContext` function. 30 // It randomly fetches an IP via custom LookupHost function and dials it by the given dial 31 // function. LookupHost may implement an internal DNS caching implementation, lookupHost 32 // input if nil then net.DefaultResolver.LookupHost is used. 33 // 34 // It dials one by one and returns first connected `net.Conn`. 35 // If it fails to dial all IPs from cache it returns first error. If no baseDialFunc 36 // is given, it sets default dial function. 37 // 38 // You can use returned dial function for `http.Transport.DialContext`. 39 // 40 // In this function, it uses functions from `rand` package. To make it really random, 41 // you MUST call `rand.Seed` and change the value from the default in your application 42 func DialContextWithLookupHost(lookupHost LookupHost, baseDialCtx DialContext) DialContext { 43 if lookupHost == nil { 44 lookupHost = net.DefaultResolver.LookupHost 45 } 46 47 if baseDialCtx == nil { 48 // This is same as which `http.DefaultTransport` uses. 49 baseDialCtx = (&net.Dialer{ 50 Timeout: 30 * time.Second, 51 KeepAlive: 30 * time.Second, 52 }).DialContext 53 } 54 55 return func(ctx context.Context, network, addr string) (conn net.Conn, err error) { 56 host, port, err := net.SplitHostPort(addr) 57 if err != nil { 58 return nil, err 59 } 60 61 if net.ParseIP(host) != nil { 62 // For IP only setups there is no need for DNS lookups. 63 return baseDialCtx(ctx, "tcp", addr) 64 } 65 66 ips, err := lookupHost(ctx, host) 67 if err != nil { 68 return nil, err 69 } 70 71 for _, ip := range ips { 72 conn, err = baseDialCtx(ctx, "tcp", net.JoinHostPort(ip, port)) 73 if err == nil { 74 break 75 } 76 } 77 78 return 79 } 80 }