github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/connection/dns_option.go (about) 1 /* 2 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package connection 19 20 import ( 21 "encoding/json" 22 "net" 23 "strings" 24 25 "github.com/mysteriumnetwork/node/utils/stringutil" 26 "github.com/pkg/errors" 27 "github.com/rs/zerolog/log" 28 ) 29 30 // DNSOption defines DNS server selection strategy for consumer 31 type DNSOption string 32 33 const ( 34 // DNSOptionAuto (default) tries the following with fallbacks: provider's DNS -> client's system DNS -> public DNS 35 DNSOptionAuto = DNSOption("auto") 36 // DNSOptionProvider uses DNS servers from provider's system configuration 37 DNSOptionProvider = DNSOption("provider") 38 // DNSOptionSystem uses DNS servers from client's system configuration 39 DNSOptionSystem = DNSOption("system") 40 ) 41 42 // NewDNSOption creates and validates DNSOption 43 func NewDNSOption(str string) (DNSOption, error) { 44 opt := DNSOption(str) 45 switch opt { 46 case DNSOptionAuto, DNSOptionProvider, DNSOptionSystem, "": 47 return opt, nil 48 } 49 // It may also be a set of IP addresses, e.g. 1.1.1.1,8.8.8.8 50 split := strings.Split(str, ",") 51 for _, s := range split { 52 if ip := net.ParseIP(s); ip == nil { 53 return "", errors.New("invalid IP address provided as a DNS option: " + s) 54 } 55 } 56 return opt, nil 57 } 58 59 // UnmarshalJSON parses JSON → DNSOption 60 func (o *DNSOption) UnmarshalJSON(data []byte) error { 61 var str string 62 if err := json.Unmarshal(data, &str); err != nil { 63 return err 64 } 65 option, err := NewDNSOption(str) 66 if err != nil { 67 return err 68 } 69 *o = option 70 return nil 71 } 72 73 // Exact returns a slice of DNS server IPs, if they were set 74 func (o DNSOption) Exact() (servers []string, ok bool) { 75 switch o { 76 case DNSOptionAuto, DNSOptionProvider, DNSOptionSystem: 77 return nil, false 78 } 79 return stringutil.Split(string(o), ','), true 80 } 81 82 // ResolveIPs resolves DNS server IPs on the consumer side using self as the 83 // consumer preference and `providerDNS` argument as received from the provider 84 func (o *DNSOption) ResolveIPs(providerDNS string) ([]string, error) { 85 log.Debug().Msg("Selecting DNS servers using strategy: " + string(*o)) 86 if exact, ok := o.Exact(); ok { 87 return exact, nil 88 } 89 switch *o { 90 case DNSOptionProvider: 91 return selectProviderDNS(providerDNS) 92 case DNSOptionSystem: 93 return nil, nil 94 case DNSOptionAuto: 95 log.Debug().Msg("Attempting to use provider DNS") 96 if providerDNS, err := selectProviderDNS(providerDNS); err == nil { 97 return providerDNS, nil 98 } 99 log.Debug().Msg("Attempting to use system DNS") 100 return nil, nil 101 } 102 log.Debug().Msg("Falling back to public DNS") 103 return []string{"1.1.1.1", "8.8.8.8"}, nil 104 } 105 106 func selectProviderDNS(providerDNS string) ([]string, error) { 107 opt, err := NewDNSOption(providerDNS) 108 if err != nil { 109 return nil, errors.Wrap(err, "can't parse provider DNS string") 110 } 111 servers, ok := opt.Exact() 112 if !ok || len(servers) == 0 { 113 return nil, errors.New("provider DNS is not available") 114 } 115 return servers, nil 116 }