Skip to content

Commit 935aa32

Browse files
committed
Add support for Client Subnet in DNS Queries (RFC7871), close AsyncHttpClient#1337
Motivation: RFC7871 defines an extension which allows to request responses for a given subset. Modifications: - Add DnsOptPseudoRrRecord which can act as base class for extensions based on EDNS(0) as defined in RFC6891 - Add DnsOptEcsRecord to support the Client Subnet in DNS Queries extension - Add tests Result: Client Subnet in DNS Queries extension is now supported.
1 parent 549fb25 commit 935aa32

16 files changed

+951
-216
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2012 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.channel.socket;
17+
18+
import io.netty.util.NetUtil;
19+
20+
import java.net.Inet4Address;
21+
import java.net.Inet6Address;
22+
import java.net.InetAddress;
23+
24+
/**
25+
* Internet Protocol (IP) families used byte the {@link DatagramChannel}
26+
*/
27+
public enum InternetProtocolFamily2 {
28+
IPv4(Inet4Address.class),
29+
IPv6(Inet6Address.class);
30+
31+
private final Class<? extends InetAddress> addressType;
32+
private final int addressNumber;
33+
private final InetAddress localHost;
34+
35+
InternetProtocolFamily2(Class<? extends InetAddress> addressType) {
36+
this.addressType = addressType;
37+
addressNumber = addressNumber(addressType);
38+
localHost = localhost(addressType);
39+
}
40+
41+
/**
42+
* Returns the address type of this protocol family.
43+
*/
44+
public Class<? extends InetAddress> addressType() {
45+
return addressType;
46+
}
47+
48+
/**
49+
* Returns the
50+
* <a href="http://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml">address number</a>
51+
* of the family.
52+
*/
53+
public int addressNumber() {
54+
return addressNumber;
55+
}
56+
57+
/**
58+
* Returns the {@link InetAddress} that represent the {@code LOCALHOST} for the family.
59+
*/
60+
public InetAddress localhost() {
61+
return localHost;
62+
}
63+
64+
private static InetAddress localhost(Class<? extends InetAddress> addressType) {
65+
if (addressType.isAssignableFrom(Inet4Address.class)) {
66+
return NetUtil.LOCALHOST4;
67+
}
68+
if (addressType.isAssignableFrom(Inet6Address.class)) {
69+
return NetUtil.LOCALHOST6;
70+
}
71+
throw new Error();
72+
}
73+
74+
private static int addressNumber(Class<? extends InetAddress> addressType) {
75+
if (addressType.isAssignableFrom(Inet4Address.class)) {
76+
return 1;
77+
}
78+
if (addressType.isAssignableFrom(Inet6Address.class)) {
79+
return 2;
80+
}
81+
throw new IllegalArgumentException("addressType " + addressType + " not supported");
82+
}
83+
84+
/**
85+
* Returns the {@link InternetProtocolFamily} for the given {@link InetAddress}.
86+
*/
87+
public static InternetProtocolFamily2 of(InetAddress address) {
88+
if (address instanceof Inet4Address) {
89+
return IPv4;
90+
}
91+
if (address instanceof Inet6Address) {
92+
return IPv6;
93+
}
94+
throw new IllegalArgumentException("address " + address + " not supported");
95+
}
96+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2016 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.dns;
17+
18+
import io.netty.util.internal.StringUtil;
19+
import io.netty.util.internal.UnstableApi;
20+
21+
/**
22+
* An <a href="https://tools.ietf.org/html/rfc6891#section-6.1">OPT RR</a> record.
23+
*
24+
* This is used for <a href="https://tools.ietf.org/html/rfc6891#section-6.1.3">
25+
* Extension Mechanisms for DNS (EDNS(0))</a>.
26+
*/
27+
@UnstableApi
28+
public abstract class AbstractDnsOptPseudoRrRecord extends AbstractDnsRecord implements DnsOptPseudoRecord {
29+
30+
protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize, int extendedRcode, int version) {
31+
super(StringUtil.EMPTY_STRING, DnsRecordType.OPT, maxPayloadSize, packIntoLong(extendedRcode, version));
32+
}
33+
34+
protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize) {
35+
super(StringUtil.EMPTY_STRING, DnsRecordType.OPT, maxPayloadSize, 0);
36+
}
37+
38+
// See https://tools.ietf.org/html/rfc6891#section-6.1.3
39+
private static long packIntoLong(int val, int val2) {
40+
// We are currently not support DO and Z fields, just use 0.
41+
return ((val & 0xff) << 24 | (val2 & 0xff) << 16 | (0 & 0xff) << 8 | 0 & 0xff) & 0xFFFFFFFFL;
42+
}
43+
44+
@Override
45+
public int extendedRcode() {
46+
return (short) (((int) timeToLive() >> 24) & 0xff);
47+
}
48+
49+
@Override
50+
public int version() {
51+
return (short) (((int) timeToLive() >> 16) & 0xff);
52+
}
53+
54+
@Override
55+
public int flags() {
56+
return (short) ((short) timeToLive() & 0xff);
57+
}
58+
59+
@Override
60+
public String toString() {
61+
return toStringBuilder().toString();
62+
}
63+
64+
final StringBuilder toStringBuilder() {
65+
return new StringBuilder(64)
66+
.append(StringUtil.simpleClassName(this))
67+
.append('(')
68+
.append("OPT flags:")
69+
.append(flags())
70+
.append(" version:")
71+
.append(version())
72+
.append(" extendedRecode:")
73+
.append(extendedRcode())
74+
.append(" udp:")
75+
.append(dnsClass())
76+
.append(')');
77+
}
78+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2016 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.codec.dns;
17+
18+
import io.netty.channel.socket.InternetProtocolFamily2;
19+
import io.netty.util.internal.UnstableApi;
20+
21+
import java.net.InetAddress;
22+
import java.util.Arrays;
23+
24+
/**
25+
* Default {@link DnsOptEcsRecord} implementation.
26+
*/
27+
@UnstableApi
28+
public final class DefaultDnsOptEcsRecord extends AbstractDnsOptPseudoRrRecord implements DnsOptEcsRecord {
29+
private final int srcPrefixLength;
30+
private final byte[] address;
31+
32+
/**
33+
* Creates a new instance.
34+
*
35+
* @param maxPayloadSize the suggested max payload size in bytes
36+
* @param extendedRcode the extended rcode
37+
* @param version the version
38+
* @param srcPrefixLength the prefix length
39+
* @param address the bytes of the {@link InetAddress} to use
40+
*/
41+
public DefaultDnsOptEcsRecord(int maxPayloadSize, int extendedRcode, int version,
42+
int srcPrefixLength, byte[] address) {
43+
super(maxPayloadSize, extendedRcode, version);
44+
this.srcPrefixLength = srcPrefixLength;
45+
this.address = verifyAddress(address).clone();
46+
}
47+
48+
/**
49+
* Creates a new instance.
50+
*
51+
* @param maxPayloadSize the suggested max payload size in bytes
52+
* @param srcPrefixLength the prefix length
53+
* @param address the bytes of the {@link InetAddress} to use
54+
*/
55+
public DefaultDnsOptEcsRecord(int maxPayloadSize, int srcPrefixLength, byte[] address) {
56+
this(maxPayloadSize, 0, 0, srcPrefixLength, address);
57+
}
58+
59+
/**
60+
* Creates a new instance.
61+
*
62+
* @param maxPayloadSize the suggested max payload size in bytes
63+
* @param protocolFamily the {@link InternetProtocolFamily2} to use. This should be the same as the one used to
64+
* send the query.
65+
*/
66+
public DefaultDnsOptEcsRecord(int maxPayloadSize, InternetProtocolFamily2 protocolFamily) {
67+
this(maxPayloadSize, 0, 0, 0, protocolFamily.localhost().getAddress());
68+
}
69+
70+
private static byte[] verifyAddress(byte[] bytes) {
71+
if (bytes.length == 4 || bytes.length == 16) {
72+
return bytes;
73+
}
74+
throw new IllegalArgumentException("bytes.length must either 4 or 16");
75+
}
76+
77+
@Override
78+
public int sourcePrefixLength() {
79+
return srcPrefixLength;
80+
}
81+
82+
@Override
83+
public int scopePrefixLength() {
84+
return 0;
85+
}
86+
87+
@Override
88+
public byte[] address() {
89+
return address.clone();
90+
}
91+
92+
@Override
93+
public String toString() {
94+
StringBuilder sb = toStringBuilder();
95+
sb.setLength(sb.length() - 1);
96+
return sb.append(" address:")
97+
.append(Arrays.toString(address))
98+
.append(" sourcePrefixLength:")
99+
.append(sourcePrefixLength())
100+
.append(" scopePrefixLength:")
101+
.append(scopePrefixLength())
102+
.append(')').toString();
103+
}
104+
}

0 commit comments

Comments
 (0)