OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / multiformats / go-multiaddr-dns / resolve.go
1 package madns
2
3 import (
4         "context"
5         "fmt"
6         "net"
7         "strings"
8
9         ma "github.com/multiformats/go-multiaddr"
10 )
11
12 var ResolvableProtocols = []ma.Protocol{DnsaddrProtocol, Dns4Protocol, Dns6Protocol}
13 var DefaultResolver = &Resolver{Backend: net.DefaultResolver}
14
15 type backend interface {
16         LookupIPAddr(context.Context, string) ([]net.IPAddr, error)
17         LookupTXT(context.Context, string) ([]string, error)
18 }
19
20 type Resolver struct {
21         Backend backend
22 }
23
24 type MockBackend struct {
25         IP  map[string][]net.IPAddr
26         TXT map[string][]string
27 }
28
29 func (r *MockBackend) LookupIPAddr(ctx context.Context, name string) ([]net.IPAddr, error) {
30         results, ok := r.IP[name]
31         if ok {
32                 return results, nil
33         } else {
34                 return []net.IPAddr{}, nil
35         }
36 }
37
38 func (r *MockBackend) LookupTXT(ctx context.Context, name string) ([]string, error) {
39         results, ok := r.TXT[name]
40         if ok {
41                 return results, nil
42         } else {
43                 return []string{}, nil
44         }
45 }
46
47 func Matches(maddr ma.Multiaddr) bool {
48         protos := maddr.Protocols()
49         if len(protos) == 0 {
50                 return false
51         }
52
53         for _, p := range ResolvableProtocols {
54                 if protos[0].Code == p.Code {
55                         return true
56                 }
57         }
58
59         return false
60 }
61
62 func Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
63         return DefaultResolver.Resolve(ctx, maddr)
64 }
65
66 func (r *Resolver) Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
67         if !Matches(maddr) {
68                 return []ma.Multiaddr{maddr}, nil
69         }
70
71         protos := maddr.Protocols()
72         if protos[0].Code == Dns4Protocol.Code {
73                 return r.resolveDns4(ctx, maddr)
74         }
75         if protos[0].Code == Dns6Protocol.Code {
76                 return r.resolveDns6(ctx, maddr)
77         }
78         if protos[0].Code == DnsaddrProtocol.Code {
79                 return r.resolveDnsaddr(ctx, maddr)
80         }
81
82         panic("unreachable")
83 }
84
85 func (r *Resolver) resolveDns4(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
86         value, err := maddr.ValueForProtocol(Dns4Protocol.Code)
87         if err != nil {
88                 return nil, fmt.Errorf("error resolving %s: %s", maddr.String(), err)
89         }
90
91         encap := ma.Split(maddr)[1:]
92
93         result := []ma.Multiaddr{}
94         records, err := r.Backend.LookupIPAddr(ctx, value)
95         if err != nil {
96                 return result, err
97         }
98
99         for _, r := range records {
100                 ip4 := r.IP.To4()
101                 if ip4 == nil {
102                         continue
103                 }
104                 ip4maddr, err := ma.NewMultiaddr("/ip4/" + ip4.String())
105                 if err != nil {
106                         return result, err
107                 }
108                 parts := append([]ma.Multiaddr{ip4maddr}, encap...)
109                 result = append(result, ma.Join(parts...))
110         }
111         return result, nil
112 }
113
114 func (r *Resolver) resolveDns6(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
115         value, err := maddr.ValueForProtocol(Dns6Protocol.Code)
116         if err != nil {
117                 return nil, fmt.Errorf("error resolving %s: %s", maddr.String(), err)
118         }
119
120         encap := ma.Split(maddr)[1:]
121
122         result := []ma.Multiaddr{}
123         records, err := r.Backend.LookupIPAddr(ctx, value)
124         if err != nil {
125                 return result, err
126         }
127
128         for _, r := range records {
129                 if r.IP.To4() != nil {
130                         continue
131                 }
132                 ip6maddr, err := ma.NewMultiaddr("/ip6/" + r.IP.To16().String())
133                 if err != nil {
134                         return result, err
135                 }
136                 parts := append([]ma.Multiaddr{ip6maddr}, encap...)
137                 result = append(result, ma.Join(parts...))
138         }
139         return result, nil
140 }
141
142 func (r *Resolver) resolveDnsaddr(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
143         value, err := maddr.ValueForProtocol(DnsaddrProtocol.Code)
144         if err != nil {
145                 return nil, fmt.Errorf("error resolving %s: %s", maddr.String(), err)
146         }
147
148         trailer := ma.Split(maddr)[1:]
149
150         result := []ma.Multiaddr{}
151         records, err := r.Backend.LookupTXT(ctx, "_dnsaddr."+value)
152         if err != nil {
153                 return result, err
154         }
155
156         for _, r := range records {
157                 rv := strings.Split(r, "dnsaddr=")
158                 if len(rv) != 2 {
159                         continue
160                 }
161
162                 rmaddr, err := ma.NewMultiaddr(rv[1])
163                 if err != nil {
164                         return result, err
165                 }
166
167                 if matchDnsaddr(rmaddr, trailer) {
168                         result = append(result, rmaddr)
169                 }
170         }
171         return result, nil
172 }
173
174 // XXX probably insecure
175 func matchDnsaddr(maddr ma.Multiaddr, trailer []ma.Multiaddr) bool {
176         parts := ma.Split(maddr)
177         if ma.Join(parts[len(parts)-len(trailer):]...).Equal(ma.Join(trailer...)) {
178                 return true
179         }
180         return false
181 }