|
16 | 16 | dnsProtocol = ma.ProtocolWithCode(ma.P_DNS)
|
17 | 17 | )
|
18 | 18 |
|
19 |
| -var ResolvableProtocols = []ma.Protocol{dnsaddrProtocol, dns4Protocol, dns6Protocol, dnsProtocol} |
20 |
| -var DefaultResolver = &Resolver{def: net.DefaultResolver} |
| 19 | +var ( |
| 20 | + ResolvableProtocols = []ma.Protocol{dnsaddrProtocol, dns4Protocol, dns6Protocol, dnsProtocol} |
| 21 | + DefaultResolver = &Resolver{def: net.DefaultResolver} |
| 22 | +) |
21 | 23 |
|
22 | 24 | const dnsaddrTXTPrefix = "dnsaddr="
|
23 | 25 |
|
@@ -104,179 +106,166 @@ func (r *Resolver) getResolver(domain string) BasicResolver {
|
104 | 106 | return r.def
|
105 | 107 | }
|
106 | 108 |
|
107 |
| -// Resolve resolves a DNS multiaddr. |
| 109 | +// Resolve resolves a DNS multiaddr. It will only resolve the first DNS component in the multiaddr. |
| 110 | +// If you need to resolve multiple DNS components, you may call this function again with each returned address. |
108 | 111 | func (r *Resolver) Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error) {
|
109 |
| - var results []ma.Multiaddr |
110 |
| - for i := 0; maddr != nil; i++ { |
111 |
| - var keep ma.Multiaddr |
112 |
| - |
113 |
| - // Find the next dns component. |
114 |
| - keep, maddr = ma.SplitFunc(maddr, func(c ma.Component) bool { |
115 |
| - switch c.Protocol().Code { |
116 |
| - case dnsProtocol.Code, dns4Protocol.Code, dns6Protocol.Code, dnsaddrProtocol.Code: |
117 |
| - return true |
118 |
| - default: |
119 |
| - return false |
120 |
| - } |
121 |
| - }) |
| 112 | + if maddr == nil { |
| 113 | + return nil, nil |
| 114 | + } |
122 | 115 |
|
123 |
| - // Keep everything before the dns component. |
124 |
| - if keep != nil { |
125 |
| - if len(results) == 0 { |
126 |
| - results = []ma.Multiaddr{keep} |
127 |
| - } else { |
128 |
| - for i, r := range results { |
129 |
| - results[i] = r.Encapsulate(keep) |
130 |
| - } |
131 |
| - } |
| 116 | + // Find the next dns component. |
| 117 | + preDNS, maddr := ma.SplitFunc(maddr, func(c ma.Component) bool { |
| 118 | + switch c.Protocol().Code { |
| 119 | + case dnsProtocol.Code, dns4Protocol.Code, dns6Protocol.Code, dnsaddrProtocol.Code: |
| 120 | + return true |
| 121 | + default: |
| 122 | + return false |
132 | 123 | }
|
| 124 | + }) |
133 | 125 |
|
134 |
| - // If the rest is empty, we've hit the end (there _was_ no dns component). |
135 |
| - if maddr == nil { |
136 |
| - break |
137 |
| - } |
| 126 | + // If the rest is empty, we've hit the end (there _was_ no dns component). |
| 127 | + if maddr == nil { |
| 128 | + return []ma.Multiaddr{preDNS}, nil |
| 129 | + } |
138 | 130 |
|
139 |
| - // split off the dns component. |
140 |
| - var resolve *ma.Component |
141 |
| - resolve, maddr = ma.SplitFirst(maddr) |
142 |
| - |
143 |
| - proto := resolve.Protocol() |
144 |
| - value := resolve.Value() |
145 |
| - rslv := r.getResolver(value) |
146 |
| - |
147 |
| - // resolve the dns component |
148 |
| - var resolved []ma.Multiaddr |
149 |
| - switch proto.Code { |
150 |
| - case dns4Protocol.Code, dns6Protocol.Code, dnsProtocol.Code: |
151 |
| - // The dns, dns4, and dns6 resolver simply resolves each |
152 |
| - // dns* component into an ipv4/ipv6 address. |
153 |
| - |
154 |
| - v4only := proto.Code == dns4Protocol.Code |
155 |
| - v6only := proto.Code == dns6Protocol.Code |
156 |
| - |
157 |
| - // XXX: Unfortunately, go does a pretty terrible job of |
158 |
| - // differentiating between IPv6 and IPv4. A v4-in-v6 |
159 |
| - // AAAA record will _look_ like an A record to us and |
160 |
| - // there's nothing we can do about that. |
161 |
| - records, err := rslv.LookupIPAddr(ctx, value) |
162 |
| - if err != nil { |
163 |
| - return nil, err |
164 |
| - } |
| 131 | + // split off the dns component. |
| 132 | + resolve, postDNS := ma.SplitFirst(maddr) |
| 133 | + |
| 134 | + proto := resolve.Protocol() |
| 135 | + value := resolve.Value() |
| 136 | + rslv := r.getResolver(value) |
| 137 | + |
| 138 | + // resolve the dns component |
| 139 | + var resolved []ma.Multiaddr |
| 140 | + switch proto.Code { |
| 141 | + case dns4Protocol.Code, dns6Protocol.Code, dnsProtocol.Code: |
| 142 | + // The dns, dns4, and dns6 resolver simply resolves each |
| 143 | + // dns* component into an ipv4/ipv6 address. |
| 144 | + |
| 145 | + v4only := proto.Code == dns4Protocol.Code |
| 146 | + v6only := proto.Code == dns6Protocol.Code |
165 | 147 |
|
166 |
| - // Convert each DNS record into a multiaddr. If the |
167 |
| - // protocol is dns4, throw away any IPv6 addresses. If |
168 |
| - // the protocol is dns6, throw away any IPv4 addresses. |
169 |
| - |
170 |
| - for _, r := range records { |
171 |
| - var ( |
172 |
| - rmaddr ma.Multiaddr |
173 |
| - err error |
174 |
| - ) |
175 |
| - ip4 := r.IP.To4() |
176 |
| - if ip4 == nil { |
177 |
| - if v4only { |
178 |
| - continue |
179 |
| - } |
180 |
| - rmaddr, err = ma.NewMultiaddr("/ip6/" + r.IP.String()) |
181 |
| - } else { |
182 |
| - if v6only { |
183 |
| - continue |
184 |
| - } |
185 |
| - rmaddr, err = ma.NewMultiaddr("/ip4/" + ip4.String()) |
| 148 | + // XXX: Unfortunately, go does a pretty terrible job of |
| 149 | + // differentiating between IPv6 and IPv4. A v4-in-v6 |
| 150 | + // AAAA record will _look_ like an A record to us and |
| 151 | + // there's nothing we can do about that. |
| 152 | + records, err := rslv.LookupIPAddr(ctx, value) |
| 153 | + if err != nil { |
| 154 | + return nil, err |
| 155 | + } |
| 156 | + |
| 157 | + // Convert each DNS record into a multiaddr. If the |
| 158 | + // protocol is dns4, throw away any IPv6 addresses. If |
| 159 | + // the protocol is dns6, throw away any IPv4 addresses. |
| 160 | + |
| 161 | + for _, r := range records { |
| 162 | + var ( |
| 163 | + rmaddr ma.Multiaddr |
| 164 | + err error |
| 165 | + ) |
| 166 | + ip4 := r.IP.To4() |
| 167 | + if ip4 == nil { |
| 168 | + if v4only { |
| 169 | + continue |
186 | 170 | }
|
187 |
| - if err != nil { |
188 |
| - return nil, err |
| 171 | + rmaddr, err = ma.NewMultiaddr("/ip6/" + r.IP.String()) |
| 172 | + } else { |
| 173 | + if v6only { |
| 174 | + continue |
189 | 175 | }
|
190 |
| - resolved = append(resolved, rmaddr) |
| 176 | + rmaddr, err = ma.NewMultiaddr("/ip4/" + ip4.String()) |
191 | 177 | }
|
192 |
| - case dnsaddrProtocol.Code: |
193 |
| - // The dnsaddr resolver is a bit more complicated. We: |
194 |
| - // |
195 |
| - // 1. Lookup the dnsaddr txt record on _dnsaddr.DOMAIN.TLD |
196 |
| - // 2. Take everything _after_ the `/dnsaddr/DOMAIN.TLD` |
197 |
| - // part of the multiaddr. |
198 |
| - // 3. Find the dnsaddr records (if any) with suffixes |
199 |
| - // matching the result of step 2. |
200 |
| - |
201 |
| - // First, lookup the TXT record |
202 |
| - records, err := rslv.LookupTXT(ctx, "_dnsaddr."+value) |
203 | 178 | if err != nil {
|
204 | 179 | return nil, err
|
205 | 180 | }
|
| 181 | + resolved = append(resolved, rmaddr) |
| 182 | + } |
| 183 | + case dnsaddrProtocol.Code: |
| 184 | + // The dnsaddr resolver is a bit more complicated. We: |
| 185 | + // |
| 186 | + // 1. Lookup the dnsaddr txt record on _dnsaddr.DOMAIN.TLD |
| 187 | + // 2. Take everything _after_ the `/dnsaddr/DOMAIN.TLD` |
| 188 | + // part of the multiaddr. |
| 189 | + // 3. Find the dnsaddr records (if any) with suffixes |
| 190 | + // matching the result of step 2. |
| 191 | + |
| 192 | + // First, lookup the TXT record |
| 193 | + records, err := rslv.LookupTXT(ctx, "_dnsaddr."+value) |
| 194 | + if err != nil { |
| 195 | + return nil, err |
| 196 | + } |
206 | 197 |
|
207 |
| - // Then, calculate the length of the suffix we're |
208 |
| - // looking for. |
209 |
| - length := 0 |
210 |
| - if maddr != nil { |
211 |
| - length = addrLen(maddr) |
| 198 | + // Then, calculate the length of the suffix we're |
| 199 | + // looking for. |
| 200 | + length := 0 |
| 201 | + if postDNS != nil { |
| 202 | + length = addrLen(postDNS) |
| 203 | + } |
| 204 | + |
| 205 | + for _, r := range records { |
| 206 | + // Ignore non dnsaddr TXT records. |
| 207 | + if !strings.HasPrefix(r, dnsaddrTXTPrefix) { |
| 208 | + continue |
212 | 209 | }
|
213 | 210 |
|
214 |
| - for _, r := range records { |
215 |
| - // Ignore non dnsaddr TXT records. |
216 |
| - if !strings.HasPrefix(r, dnsaddrTXTPrefix) { |
217 |
| - continue |
218 |
| - } |
| 211 | + // Extract and decode the multiaddr. |
| 212 | + rmaddr, err := ma.NewMultiaddr(r[len(dnsaddrTXTPrefix):]) |
| 213 | + if err != nil { |
| 214 | + // discard multiaddrs we don't understand. |
| 215 | + // XXX: Is this right? It's the best we |
| 216 | + // can do for now, really. |
| 217 | + continue |
| 218 | + } |
219 | 219 |
|
220 |
| - // Extract and decode the multiaddr. |
221 |
| - rmaddr, err := ma.NewMultiaddr(r[len(dnsaddrTXTPrefix):]) |
222 |
| - if err != nil { |
223 |
| - // discard multiaddrs we don't understand. |
224 |
| - // XXX: Is this right? It's the best we |
225 |
| - // can do for now, really. |
| 220 | + // If we have a suffix to match on. |
| 221 | + if postDNS != nil { |
| 222 | + // Make sure the new address is at least |
| 223 | + // as long as the suffix we're looking |
| 224 | + // for. |
| 225 | + rmlen := addrLen(rmaddr) |
| 226 | + if rmlen < length { |
| 227 | + // not long enough. |
226 | 228 | continue
|
227 | 229 | }
|
228 | 230 |
|
229 |
| - // If we have a suffix to match on. |
230 |
| - if maddr != nil { |
231 |
| - // Make sure the new address is at least |
232 |
| - // as long as the suffix we're looking |
233 |
| - // for. |
234 |
| - rmlen := addrLen(rmaddr) |
235 |
| - if rmlen < length { |
236 |
| - // not long enough. |
237 |
| - continue |
238 |
| - } |
239 |
| - |
240 |
| - // Matches everything after the /dnsaddr/... with the end of the |
241 |
| - // dnsaddr record: |
242 |
| - // |
243 |
| - // v----------rmlen-----------------v |
244 |
| - // /ip4/1.2.3.4/tcp/1234/p2p/QmFoobar |
245 |
| - // /p2p/QmFoobar |
246 |
| - // ^--(rmlen - length)--^---length--^ |
247 |
| - if !maddr.Equal(offset(rmaddr, rmlen-length)) { |
248 |
| - continue |
249 |
| - } |
| 231 | + // Matches everything after the /dnsaddr/... with the end of the |
| 232 | + // dnsaddr record: |
| 233 | + // |
| 234 | + // v----------rmlen-----------------v |
| 235 | + // /ip4/1.2.3.4/tcp/1234/p2p/QmFoobar |
| 236 | + // /p2p/QmFoobar |
| 237 | + // ^--(rmlen - length)--^---length--^ |
| 238 | + if !postDNS.Equal(offset(rmaddr, rmlen-length)) { |
| 239 | + continue |
250 | 240 | }
|
251 |
| - |
252 |
| - resolved = append(resolved, rmaddr) |
253 | 241 | }
|
254 | 242 |
|
255 |
| - // consumes the rest of the multiaddr as part of the "match" process. |
256 |
| - maddr = nil |
257 |
| - default: |
258 |
| - panic("unreachable") |
| 243 | + // remove the suffix from the multiaddr, we'll add it back at the end. |
| 244 | + if postDNS != nil { |
| 245 | + rmaddr = rmaddr.Decapsulate(postDNS) |
| 246 | + } |
| 247 | + resolved = append(resolved, rmaddr) |
259 | 248 | }
|
| 249 | + default: |
| 250 | + panic("unreachable") |
| 251 | + } |
| 252 | + |
| 253 | + if len(resolved) == 0 { |
| 254 | + return nil, nil |
| 255 | + } |
260 | 256 |
|
261 |
| - if len(resolved) == 0 { |
262 |
| - return nil, nil |
263 |
| - } else if len(results) == 0 { |
264 |
| - results = resolved |
265 |
| - } else { |
266 |
| - // We take the cross product here as we don't have any |
267 |
| - // better way to represent "ORs" in multiaddrs. For |
268 |
| - // example, `/dns/foo.com/p2p-circuit/dns/bar.com` could |
269 |
| - // resolve to: |
270 |
| - // |
271 |
| - // * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.1 |
272 |
| - // * /ip4/1.1.1.1/p2p-circuit/ip4/2.1.1.2 |
273 |
| - // * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.1 |
274 |
| - // * /ip4/1.1.1.2/p2p-circuit/ip4/2.1.1.2 |
275 |
| - results = cross(results, resolved) |
| 257 | + if preDNS != nil { |
| 258 | + for i, m := range resolved { |
| 259 | + resolved[i] = preDNS.Encapsulate(m) |
| 260 | + } |
| 261 | + } |
| 262 | + if postDNS != nil { |
| 263 | + for i, m := range resolved { |
| 264 | + resolved[i] = m.Encapsulate(postDNS) |
276 | 265 | }
|
277 | 266 | }
|
278 | 267 |
|
279 |
| - return results, nil |
| 268 | + return resolved, nil |
280 | 269 | }
|
281 | 270 |
|
282 | 271 | func (r *Resolver) LookupIPAddr(ctx context.Context, domain string) ([]net.IPAddr, error) {
|
|
0 commit comments