1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.resolver.dns;
17
18 import io.netty5.channel.ChannelFactory;
19 import io.netty5.channel.EventLoop;
20 import io.netty5.channel.ReflectiveChannelFactory;
21 import io.netty5.channel.socket.DatagramChannel;
22 import io.netty5.channel.socket.SocketChannel;
23 import io.netty5.resolver.HostsFileEntriesResolver;
24 import io.netty5.resolver.ResolvedAddressTypes;
25 import io.netty5.util.concurrent.Future;
26
27 import java.net.Inet4Address;
28 import java.net.Inet6Address;
29 import java.net.ProtocolFamily;
30 import java.net.SocketAddress;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.List;
34
35 import static io.netty5.util.NetUtil.addressType;
36 import static io.netty5.util.NetUtil.isFamilySupported;
37 import static io.netty5.util.internal.ObjectUtil.intValue;
38 import static java.util.Objects.requireNonNull;
39
40
41
42
43 public final class DnsNameResolverBuilder {
44 volatile EventLoop eventLoop;
45 private ChannelFactory<? extends DatagramChannel> channelFactory;
46 private ChannelFactory<? extends SocketChannel> socketChannelFactory;
47 private DnsCache resolveCache;
48 private DnsCnameCache cnameCache;
49 private AuthoritativeDnsServerCache authoritativeDnsServerCache;
50 private SocketAddress localAddress;
51 private Integer minTtl;
52 private Integer maxTtl;
53 private Integer negativeTtl;
54 private long queryTimeoutMillis = -1;
55 private ResolvedAddressTypes resolvedAddressTypes = DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
56 private boolean completeOncePreferredResolved;
57 private boolean recursionDesired = true;
58 private int maxQueriesPerResolve = -1;
59 private int maxPayloadSize = 4096;
60 private boolean optResourceEnabled = true;
61 private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
62 private DnsServerAddressStreamProvider dnsServerAddressStreamProvider =
63 DnsServerAddressStreamProviders.platformDefault();
64 private DnsQueryLifecycleObserverFactory dnsQueryLifecycleObserverFactory =
65 NoopDnsQueryLifecycleObserverFactory.INSTANCE;
66 private String[] searchDomains;
67 private int ndots = -1;
68 private boolean decodeIdn = true;
69
70
71
72
73 public DnsNameResolverBuilder() {
74 }
75
76
77
78
79
80
81
82 public DnsNameResolverBuilder(EventLoop eventLoop) {
83 eventLoop(eventLoop);
84 }
85
86
87
88
89
90
91
92 public DnsNameResolverBuilder eventLoop(EventLoop eventLoop) {
93 this.eventLoop = eventLoop;
94 return this;
95 }
96
97 protected ChannelFactory<? extends DatagramChannel> channelFactory() {
98 return this.channelFactory;
99 }
100
101
102
103
104
105
106
107 public DnsNameResolverBuilder channelFactory(ChannelFactory<? extends DatagramChannel> channelFactory) {
108 this.channelFactory = channelFactory;
109 return this;
110 }
111
112
113
114
115
116
117
118
119 public DnsNameResolverBuilder channelType(Class<? extends DatagramChannel> channelType) {
120 return channelFactory(new ReflectiveChannelFactory<DatagramChannel>(channelType));
121 }
122
123
124
125
126
127
128
129
130
131 public DnsNameResolverBuilder socketChannelFactory(ChannelFactory<? extends SocketChannel> channelFactory) {
132 this.socketChannelFactory = channelFactory;
133 return this;
134 }
135
136
137
138
139
140
141
142
143
144
145 public DnsNameResolverBuilder socketChannelType(Class<? extends SocketChannel> channelType) {
146 if (channelType == null) {
147 return socketChannelFactory(null);
148 }
149 return socketChannelFactory(new ReflectiveChannelFactory<SocketChannel>(channelType));
150 }
151
152
153
154
155
156
157
158 public DnsNameResolverBuilder resolveCache(DnsCache resolveCache) {
159 this.resolveCache = resolveCache;
160 return this;
161 }
162
163
164
165
166
167
168
169 public DnsNameResolverBuilder cnameCache(DnsCnameCache cnameCache) {
170 this.cnameCache = cnameCache;
171 return this;
172 }
173
174
175
176
177
178
179 public DnsNameResolverBuilder dnsQueryLifecycleObserverFactory(DnsQueryLifecycleObserverFactory
180 lifecycleObserverFactory) {
181 this.dnsQueryLifecycleObserverFactory = requireNonNull(lifecycleObserverFactory, "lifecycleObserverFactory");
182 return this;
183 }
184
185
186
187
188
189
190
191
192 @Deprecated
193 public DnsNameResolverBuilder authoritativeDnsServerCache(DnsCache authoritativeDnsServerCache) {
194 this.authoritativeDnsServerCache = new AuthoritativeDnsServerCacheAdapter(authoritativeDnsServerCache);
195 return this;
196 }
197
198
199
200
201
202
203
204 public DnsNameResolverBuilder authoritativeDnsServerCache(AuthoritativeDnsServerCache authoritativeDnsServerCache) {
205 this.authoritativeDnsServerCache = authoritativeDnsServerCache;
206 return this;
207 }
208
209
210
211
212
213
214 public DnsNameResolverBuilder localAddress(SocketAddress localAddress) {
215 this.localAddress = localAddress;
216 return this;
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230
231 public DnsNameResolverBuilder ttl(int minTtl, int maxTtl) {
232 this.maxTtl = maxTtl;
233 this.minTtl = minTtl;
234 return this;
235 }
236
237
238
239
240
241
242
243 public DnsNameResolverBuilder negativeTtl(int negativeTtl) {
244 this.negativeTtl = negativeTtl;
245 return this;
246 }
247
248
249
250
251
252
253
254 public DnsNameResolverBuilder queryTimeoutMillis(long queryTimeoutMillis) {
255 this.queryTimeoutMillis = queryTimeoutMillis;
256 return this;
257 }
258
259
260
261
262
263
264
265
266 public static ResolvedAddressTypes computeResolvedAddressTypes(ProtocolFamily... protocolFamilies) {
267 if (protocolFamilies == null || protocolFamilies.length == 0) {
268 return DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
269 }
270 if (protocolFamilies.length > 2) {
271 throw new IllegalArgumentException("No more than 2 ProtocolFamilies");
272 }
273
274 ProtocolFamily first = protocolFamilies[0];
275 if (isFamilySupported(Inet4Address.class, first)) {
276 if (protocolFamilies.length == 1) {
277 return ResolvedAddressTypes.IPV4_ONLY;
278 } else {
279 ProtocolFamily second = protocolFamilies[1];
280 if (isFamilySupported(Inet4Address.class, second)) {
281 return ResolvedAddressTypes.IPV4_ONLY;
282 }
283 if (isFamilySupported(Inet6Address.class, second)) {
284 return ResolvedAddressTypes.IPV4_PREFERRED;
285 }
286 }
287 } else if (isFamilySupported(Inet6Address.class, first)) {
288 if (protocolFamilies.length == 1) {
289 return ResolvedAddressTypes.IPV6_ONLY;
290 } else {
291 ProtocolFamily second = protocolFamilies[1];
292 if (isFamilySupported(Inet6Address.class, second)) {
293 return ResolvedAddressTypes.IPV6_ONLY;
294 }
295 if (isFamilySupported(Inet4Address.class, second)) {
296 return ResolvedAddressTypes.IPV6_PREFERRED;
297 }
298 }
299 }
300 throw new IllegalArgumentException("Couldn't resolve ResolvedAddressTypes from ProtocolFamily array: " +
301 Arrays.toString(protocolFamilies));
302 }
303
304
305
306
307
308
309
310
311
312 public DnsNameResolverBuilder resolvedAddressTypes(ResolvedAddressTypes resolvedAddressTypes) {
313 this.resolvedAddressTypes = resolvedAddressTypes;
314 return this;
315 }
316
317
318
319
320
321
322
323
324 public DnsNameResolverBuilder completeOncePreferredResolved(boolean completeOncePreferredResolved) {
325 this.completeOncePreferredResolved = completeOncePreferredResolved;
326 return this;
327 }
328
329
330
331
332
333
334
335 public DnsNameResolverBuilder recursionDesired(boolean recursionDesired) {
336 this.recursionDesired = recursionDesired;
337 return this;
338 }
339
340
341
342
343
344
345
346 public DnsNameResolverBuilder maxQueriesPerResolve(int maxQueriesPerResolve) {
347 this.maxQueriesPerResolve = maxQueriesPerResolve;
348 return this;
349 }
350
351
352
353
354
355
356
357 public DnsNameResolverBuilder maxPayloadSize(int maxPayloadSize) {
358 this.maxPayloadSize = maxPayloadSize;
359 return this;
360 }
361
362
363
364
365
366
367
368
369
370 public DnsNameResolverBuilder optResourceEnabled(boolean optResourceEnabled) {
371 this.optResourceEnabled = optResourceEnabled;
372 return this;
373 }
374
375
376
377
378
379
380 public DnsNameResolverBuilder hostsFileEntriesResolver(HostsFileEntriesResolver hostsFileEntriesResolver) {
381 this.hostsFileEntriesResolver = hostsFileEntriesResolver;
382 return this;
383 }
384
385 protected DnsServerAddressStreamProvider nameServerProvider() {
386 return this.dnsServerAddressStreamProvider;
387 }
388
389
390
391
392
393
394 public DnsNameResolverBuilder nameServerProvider(DnsServerAddressStreamProvider dnsServerAddressStreamProvider) {
395 this.dnsServerAddressStreamProvider =
396 requireNonNull(dnsServerAddressStreamProvider, "dnsServerAddressStreamProvider");
397 return this;
398 }
399
400
401
402
403
404
405
406 public DnsNameResolverBuilder searchDomains(Iterable<String> searchDomains) {
407 requireNonNull(searchDomains, "searchDomains");
408
409 final List<String> list = new ArrayList<>(4);
410
411 for (String f : searchDomains) {
412 if (f == null) {
413 break;
414 }
415
416
417 if (list.contains(f)) {
418 continue;
419 }
420
421 list.add(f);
422 }
423
424 this.searchDomains = list.toArray(new String[0]);
425 return this;
426 }
427
428
429
430
431
432
433
434
435 public DnsNameResolverBuilder ndots(int ndots) {
436 this.ndots = ndots;
437 return this;
438 }
439
440 private DnsCache newCache() {
441 return new DefaultDnsCache(intValue(minTtl, 0), intValue(maxTtl, Integer.MAX_VALUE), intValue(negativeTtl, 0));
442 }
443
444 private AuthoritativeDnsServerCache newAuthoritativeDnsServerCache() {
445 return new DefaultAuthoritativeDnsServerCache(
446 intValue(minTtl, 0), intValue(maxTtl, Integer.MAX_VALUE),
447
448
449 new NameServerComparator(addressType(DnsNameResolver.preferredAddressType(resolvedAddressTypes))));
450 }
451
452 private DnsCnameCache newCnameCache() {
453 return new DefaultDnsCnameCache(
454 intValue(minTtl, 0), intValue(maxTtl, Integer.MAX_VALUE));
455 }
456
457
458
459
460
461
462
463
464 public DnsNameResolverBuilder decodeIdn(boolean decodeIdn) {
465 this.decodeIdn = decodeIdn;
466 return this;
467 }
468
469
470
471
472
473
474 public DnsNameResolver build() {
475 if (eventLoop == null) {
476 throw new IllegalStateException("eventLoop should be specified to build a DnsNameResolver.");
477 }
478
479 if (resolveCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
480 throw new IllegalStateException("resolveCache and TTLs are mutually exclusive");
481 }
482
483 if (authoritativeDnsServerCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
484 throw new IllegalStateException("authoritativeDnsServerCache and TTLs are mutually exclusive");
485 }
486
487 DnsCache resolveCache = this.resolveCache != null ? this.resolveCache : newCache();
488 DnsCnameCache cnameCache = this.cnameCache != null ? this.cnameCache : newCnameCache();
489 AuthoritativeDnsServerCache authoritativeDnsServerCache = this.authoritativeDnsServerCache != null ?
490 this.authoritativeDnsServerCache : newAuthoritativeDnsServerCache();
491 return new DnsNameResolver(
492 eventLoop,
493 channelFactory,
494 socketChannelFactory,
495 resolveCache,
496 cnameCache,
497 authoritativeDnsServerCache,
498 localAddress,
499 dnsQueryLifecycleObserverFactory,
500 queryTimeoutMillis,
501 resolvedAddressTypes,
502 recursionDesired,
503 maxQueriesPerResolve,
504 maxPayloadSize,
505 optResourceEnabled,
506 hostsFileEntriesResolver,
507 dnsServerAddressStreamProvider,
508 searchDomains,
509 ndots,
510 decodeIdn,
511 completeOncePreferredResolved);
512 }
513
514
515
516
517
518
519 public DnsNameResolverBuilder copy() {
520 DnsNameResolverBuilder copiedBuilder = new DnsNameResolverBuilder();
521
522 if (eventLoop != null) {
523 copiedBuilder.eventLoop(eventLoop);
524 }
525
526 if (channelFactory != null) {
527 copiedBuilder.channelFactory(channelFactory);
528 }
529
530 if (socketChannelFactory != null) {
531 copiedBuilder.socketChannelFactory(socketChannelFactory);
532 }
533
534 if (resolveCache != null) {
535 copiedBuilder.resolveCache(resolveCache);
536 }
537
538 if (cnameCache != null) {
539 copiedBuilder.cnameCache(cnameCache);
540 }
541 if (maxTtl != null && minTtl != null) {
542 copiedBuilder.ttl(minTtl, maxTtl);
543 }
544
545 if (negativeTtl != null) {
546 copiedBuilder.negativeTtl(negativeTtl);
547 }
548
549 if (authoritativeDnsServerCache != null) {
550 copiedBuilder.authoritativeDnsServerCache(authoritativeDnsServerCache);
551 }
552
553 if (dnsQueryLifecycleObserverFactory != null) {
554 copiedBuilder.dnsQueryLifecycleObserverFactory(dnsQueryLifecycleObserverFactory);
555 }
556
557 copiedBuilder.queryTimeoutMillis(queryTimeoutMillis);
558 copiedBuilder.resolvedAddressTypes(resolvedAddressTypes);
559 copiedBuilder.recursionDesired(recursionDesired);
560 copiedBuilder.maxQueriesPerResolve(maxQueriesPerResolve);
561 copiedBuilder.maxPayloadSize(maxPayloadSize);
562 copiedBuilder.optResourceEnabled(optResourceEnabled);
563 copiedBuilder.hostsFileEntriesResolver(hostsFileEntriesResolver);
564
565 if (dnsServerAddressStreamProvider != null) {
566 copiedBuilder.nameServerProvider(dnsServerAddressStreamProvider);
567 }
568
569 if (searchDomains != null) {
570 copiedBuilder.searchDomains(Arrays.asList(searchDomains));
571 }
572
573 copiedBuilder.ndots(ndots);
574 copiedBuilder.decodeIdn(decodeIdn);
575 copiedBuilder.completeOncePreferredResolved(completeOncePreferredResolved);
576 copiedBuilder.localAddress(localAddress);
577 return copiedBuilder;
578 }
579 }