Skip to content

Commit 04c7a87

Browse files
Use lookupHost = false by default for TCP & UDP (#3825)
* Use `lookupHost = false` by default for TCP & UDP The applications these days more and more are deployed and managed in the containers where DNS is not configured by default. Having `lookupHost = true` by default leads to a bad experience when some delays happen for reverse host lookups. * Use `lookupHost = false` by default for both TCP & UDP to have a reliable behavior independently of the environment. The `hostName` is used for `connectionId` and as a header in the message - semantically it doesn't matter for the application logic what value is present over there. * * Fix language in docs Co-authored-by: Gary Russell <[email protected]> Co-authored-by: Gary Russell <[email protected]>
1 parent 8cf5f90 commit 04c7a87

File tree

8 files changed

+70
-61
lines changed

8 files changed

+70
-61
lines changed

spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
119119

120120
private TcpConnectionInterceptorFactoryChain interceptorFactoryChain;
121121

122-
private boolean lookupHost = true;
122+
private boolean lookupHost;
123123

124124
private TcpSocketSupport tcpSocketSupport = new DefaultTcpSocketSupport();
125125

@@ -456,7 +456,8 @@ public void setInterceptorFactoryChain(TcpConnectionInterceptorFactoryChain inte
456456

457457
/**
458458
* If true, DNS reverse lookup is done on the remote ip address.
459-
* Default true.
459+
* Default false: not all environments (e.g. Docker containers) perform reliable DNS
460+
* resolution.
460461
* @param lookupHost the lookupHost to set
461462
*/
462463
public void setLookupHost(boolean lookupHost) {

spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapper.java

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121
import java.net.DatagramPacket;
2222
import java.nio.Buffer;
2323
import java.nio.ByteBuffer;
24+
import java.nio.charset.StandardCharsets;
2425
import java.util.Map;
2526
import java.util.UUID;
2627
import java.util.regex.Matcher;
@@ -71,26 +72,26 @@
7172
public class DatagramPacketMessageMapper implements InboundMessageMapper<DatagramPacket>,
7273
OutboundMessageMapper<DatagramPacket>, BeanFactoryAware {
7374

74-
private volatile String charset = "UTF-8";
75+
private static final Pattern UDP_HEADERS_PATTERN =
76+
Pattern.compile(RegexUtils.escapeRegexSpecials(IpHeaders.ACK_ADDRESS) +
77+
"=" + "([^;]*);" +
78+
RegexUtils.escapeRegexSpecials(MessageHeaders.ID) +
79+
"=" + "([^;]*);");
80+
81+
private String charset = StandardCharsets.UTF_8.name();
7582

76-
private boolean acknowledge = false;
83+
private boolean acknowledge;
7784

7885
private String ackAddress;
7986

80-
private boolean lengthCheck = false;
87+
private boolean lengthCheck;
8188

82-
private boolean lookupHost = true;
89+
private boolean lookupHost;
8390

8491
private volatile MessageBuilderFactory messageBuilderFactory = new DefaultMessageBuilderFactory();
8592

8693
private volatile boolean messageBuilderFactorySet;
8794

88-
private static Pattern udpHeadersPattern =
89-
Pattern.compile(RegexUtils.escapeRegexSpecials(IpHeaders.ACK_ADDRESS) +
90-
"=" + "([^;]*);" +
91-
RegexUtils.escapeRegexSpecials(MessageHeaders.ID) +
92-
"=" + "([^;]*);");
93-
9495
private BeanFactory beanFactory;
9596

9697
public void setCharset(String charset) {
@@ -110,6 +111,9 @@ public void setLengthCheck(boolean lengthCheck) {
110111
}
111112

112113
/**
114+
* If true, DNS reverse lookup is done on the remote ip address.
115+
* Default false: not all environments (e.g. Docker containers) perform reliable DNS
116+
* resolution.
113117
* @param lookupHost the lookupHost to set
114118
*/
115119
public void setLookupHost(boolean lookupHost) {
@@ -232,20 +236,17 @@ public Message<byte[]> toMessage(DatagramPacket packet, @Nullable Map<String, Ob
232236
length -= 4; // NOSONAR magic number
233237
}
234238
String hostAddress = packet.getAddress().getHostAddress();
235-
String hostName;
239+
String hostName = hostAddress;
236240
if (this.lookupHost) {
237241
hostName = packet.getAddress().getHostName();
238242
}
239-
else {
240-
hostName = hostAddress;
241-
}
242243
int port = packet.getPort();
243244
// Peek at the message in case they didn't configure us for ack but the sending
244245
// side expects it.
245246
if (this.acknowledge || startsWith(buffer, IpHeaders.ACK_ADDRESS)) {
246247
try {
247248
String headersString = new String(packet.getData(), offset, length, this.charset);
248-
Matcher matcher = udpHeadersPattern.matcher(headersString);
249+
Matcher matcher = UDP_HEADERS_PATTERN.matcher(headersString);
249250
if (matcher.find()) {
250251
// Strip off the ack headers and put in Message headers
251252
length = length - matcher.end();
@@ -292,8 +293,8 @@ private boolean startsWith(ByteBuffer buffer, String prefix) {
292293
try {
293294
byte[] comparing;
294295
comparing = prefix.getBytes(this.charset);
295-
for (int i = 0; i < comparing.length; i++) {
296-
if (buffer.get() != comparing[i]) {
296+
for (byte b : comparing) {
297+
if (buffer.get() != b) {
297298
return false;
298299
}
299300
}

spring-integration-ip/src/main/resources/org/springframework/integration/ip/config/spring-integration-ip.xsd

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -663,9 +663,9 @@
663663
<xsd:attribute name="lookup-host" type="xsd:string">
664664
<xsd:annotation>
665665
<xsd:documentation>
666-
Whether or not to do a DNS reverse-lookup on the remote ip address to
666+
Whether to perform a DNS reverse-lookup on the remote ip address to
667667
insert the host name into the
668-
message headers (ip_connectionId, ip_hostName). Default "true".
668+
message headers (ip_connectionId, ip_hostName). Default "false".
669669
</xsd:documentation>
670670
</xsd:annotation>
671671
</xsd:attribute>
@@ -853,9 +853,9 @@
853853
<xsd:attribute name="lookup-host" type="xsd:string">
854854
<xsd:annotation>
855855
<xsd:documentation>
856-
Whether or not to do a DNS reverse-lookup on the remote ip address to
856+
Whether to do a DNS reverse-lookup on the remote ip address to
857857
insert the host name into the
858-
message headers (ip_hostName). Default "true".
858+
message headers (ip_hostName). Default "false".
859859
</xsd:documentation>
860860
</xsd:annotation>
861861
</xsd:attribute>

spring-integration-ip/src/test/java/org/springframework/integration/ip/config/ParserUnitTests.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
2121
import static org.mockito.Mockito.mock;
2222

2323
import java.net.DatagramSocket;
24-
import java.net.SocketException;
2524
import java.time.Duration;
2625
import java.util.Iterator;
2726
import java.util.Set;
@@ -249,10 +248,12 @@ public class ParserUnitTests {
249248
@Autowired
250249
MessageChannel udpAutoChannel;
251250

252-
@Autowired @Qualifier("tcpAutoChannel.adapter")
251+
@Autowired
252+
@Qualifier("tcpAutoChannel.adapter")
253253
TcpReceivingChannelAdapter tcpAutoAdapter;
254254

255-
@Autowired @Qualifier("udpAutoChannel.adapter")
255+
@Autowired
256+
@Qualifier("udpAutoChannel.adapter")
256257
UnicastReceivingChannelAdapter udpAutoAdapter;
257258

258259
@Autowired
@@ -316,7 +317,7 @@ public void testInUdpMulticast() {
316317
assertThat(dfa.getPropertyValue("errorChannel")).isNull();
317318
DatagramPacketMessageMapper mapper = (DatagramPacketMessageMapper) dfa.getPropertyValue("mapper");
318319
DirectFieldAccessor mapperAccessor = new DirectFieldAccessor(mapper);
319-
assertThat((Boolean) mapperAccessor.getPropertyValue("lookupHost")).isTrue();
320+
assertThat((Boolean) mapperAccessor.getPropertyValue("lookupHost")).isFalse();
320321
}
321322

322323
@Test
@@ -611,10 +612,10 @@ public void testtCPOrder() {
611612
TestUtils.getPropertyValue(this.tcpChannel, "dispatcher"),
612613
"handlers");
613614
Iterator<MessageHandler> iterator = handlers.iterator();
614-
assertThat(iterator.next()).isSameAs(this.tcpNewOut2); //15
615-
assertThat(iterator.next()).isSameAs(this.tcpOutboundGateway); //24
616-
assertThat(iterator.next()).isSameAs(this.tcpNewOut1); //25
617-
assertThat(iterator.next()).isSameAs(this.tcpOut); //35
615+
assertThat(iterator.next()).isSameAs(this.tcpNewOut2); //15
616+
assertThat(iterator.next()).isSameAs(this.tcpOutboundGateway); //24
617+
assertThat(iterator.next()).isSameAs(this.tcpNewOut1); //25
618+
assertThat(iterator.next()).isSameAs(this.tcpOut); //35
618619
}
619620

620621
@Test
@@ -682,6 +683,7 @@ public static class EventSubclass1 extends TcpConnectionEvent {
682683
public EventSubclass1(TcpConnectionSupport connection, String connectionFactoryName) {
683684
super(connection, connectionFactoryName);
684685
}
686+
685687
}
686688

687689
@SuppressWarnings("serial")
@@ -690,6 +692,7 @@ public static class EventSubclass2 extends TcpConnectionEvent {
690692
public EventSubclass2(TcpConnectionSupport connection, String connectionFactoryName) {
691693
super(connection, connectionFactoryName);
692694
}
695+
693696
}
694697

695698
@Configuration
@@ -708,7 +711,7 @@ AbstractClientConnectionFactory mockClientCf() {
708711
public static class SocketCust implements SocketCustomizer {
709712

710713
@Override
711-
public void configure(DatagramSocket socket) throws SocketException {
714+
public void configure(DatagramSocket socket) {
712715
}
713716

714717
}

spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ public void testWriteTimeout(TestInfo testInfo) throws Exception {
133133
}
134134
});
135135
assertThat(latch.await(10000, TimeUnit.MILLISECONDS)).isTrue();
136-
TcpNioClientConnectionFactory factory = new TcpNioClientConnectionFactory("localhost",
137-
serverSocket.get().getLocalPort());
136+
TcpNioClientConnectionFactory factory =
137+
new TcpNioClientConnectionFactory("localhost", serverSocket.get().getLocalPort());
138+
factory.setLookupHost(true);
138139
AtomicReference<String> connectionId = new AtomicReference<>();
139140
factory.setApplicationEventPublisher(event -> {
140141
if (event instanceof TcpConnectionOpenEvent) {

spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapperTests.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
2323
import java.net.InetSocketAddress;
2424
import java.nio.ByteBuffer;
2525

26-
import org.junit.Test;
26+
import org.junit.jupiter.api.Test;
2727

2828
import org.springframework.integration.ip.IpHeaders;
2929
import org.springframework.integration.mapping.MessageMappingException;
@@ -33,31 +33,33 @@
3333
/**
3434
* @author Gary Russell
3535
* @author Dave Syer
36+
* @author Artem Bilan
37+
*
3638
* @since 2.0
3739
*/
3840
public class DatagramPacketMessageMapperTests {
3941

4042
@Test
41-
public void testFromToMessageNoAckNoLengthCheck() throws Exception {
43+
public void testFromToMessageNoAckNoLengthCheck() {
4244
test(false, false);
4345
}
4446

4547
@Test
46-
public void testFromToMessageAckNoLengthCheck() throws Exception {
48+
public void testFromToMessageAckNoLengthCheck() {
4749
test(true, false);
4850
}
4951

5052
@Test
51-
public void testFromToMessageNoAckLengthCheck() throws Exception {
53+
public void testFromToMessageNoAckLengthCheck() {
5254
test(false, true);
5355
}
5456

5557
@Test
56-
public void testFromToMessageAckLengthCheck() throws Exception {
58+
public void testFromToMessageAckLengthCheck() {
5759
test(true, true);
5860
}
5961

60-
private void test(boolean ack, boolean lengthCheck) throws Exception {
62+
private void test(boolean ack, boolean lengthCheck) {
6163
Message<byte[]> message = MessageBuilder.withPayload("ABCD".getBytes()).build();
6264
DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper();
6365
mapper.setAckAddress("localhost:11111");
@@ -71,19 +73,19 @@ private void test(boolean ack, boolean lengthCheck) throws Exception {
7173
assertThat(message.getHeaders().getId().toString())
7274
.isEqualTo(messageOut.getHeaders().get(IpHeaders.ACK_ID).toString());
7375
}
74-
assertThat(((String) messageOut.getHeaders().get(IpHeaders.HOSTNAME)).contains("localhost")).isTrue();
75-
mapper.setLookupHost(false);
76+
assertThat(((String) messageOut.getHeaders().get(IpHeaders.HOSTNAME))).doesNotContain("localhost");
77+
mapper.setLookupHost(true);
7678
messageOut = mapper.toMessage(packet);
7779
assertThat(new String(messageOut.getPayload())).isEqualTo(new String(message.getPayload()));
7880
if (ack) {
7981
assertThat(message.getHeaders().getId().toString())
8082
.isEqualTo(messageOut.getHeaders().get(IpHeaders.ACK_ID).toString());
8183
}
82-
assertThat(((String) messageOut.getHeaders().get(IpHeaders.HOSTNAME)).contains("localhost")).isFalse();
84+
assertThat(((String) messageOut.getHeaders().get(IpHeaders.HOSTNAME))).contains("localhost");
8385
}
8486

8587
@Test
86-
public void testTruncation() throws Exception {
88+
public void testTruncation() {
8789
String test = "ABCD";
8890
Message<byte[]> message = MessageBuilder.withPayload(test.getBytes()).build();
8991
DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper();
@@ -101,8 +103,7 @@ public void testTruncation() throws Exception {
101103
fail("Truncated message exception expected");
102104
}
103105
catch (MessageMappingException e) {
104-
assertThat(e.getMessage().contains("expected " + (bigLen + 4) + ", received " + (test.length() + 4)))
105-
.isTrue();
106+
assertThat(e.getMessage()).contains("expected " + (bigLen + 4) + ", received " + (test.length() + 4));
106107
}
107108
}
108109

src/reference/asciidoc/ip.adoc

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,8 @@ The following example shows how to configure a basic multicast inbound udp chann
200200
----
201201
====
202202

203-
By default, reverse DNS lookups are done on inbound packets to convert IP addresses to host names for use in message headers.
204-
In environments where DNS is not configured, this can cause delays.
205-
You can override this default behavior by setting the `lookup-host` attribute to `false`.
203+
By default, reverse DNS lookups are not performed on inbound packets: in environments where DNS is not configured (e.g. Docker containers), this can cause connection delays.
204+
To convert IP addresses to host names for use in message headers, the default behavior can be overridden by setting the `lookup-host` attribute to `true`.
206205

207206
Starting with version 5.3.3, you can add a `SocketCustomizer` bean to modify the `DatagramSocket` after it is created.
208207
It is called for the receiving socket and any sockets created for sending acks.
@@ -489,13 +488,12 @@ A server connection factory that uses `java.net.Socket` connections and uses Jav
489488

490489
For full details of the attributes available on connection factories, see <<ip-annotation,the reference>> at the end of this section.
491490

492-
By default, reverse DNS lookups are done on inbound packets to convert IP addresses to host names for use in message headers.
493-
In environments where DNS is not configured, this can cause connection delays.
494-
You can override this default behavior by setting the `lookup-host` attribute to `false`.
491+
By default, reverse DNS lookups are not performed on inbound packets: in environments where DNS is not configured (e.g. Docker containers), this can cause connection delays.
492+
To convert IP addresses to host names for use in message headers, the default behavior can be overridden by setting the `lookup-host` attribute to `true`.
495493

496494
NOTE: You can also modify the attributes of sockets and socket factories.
497495
See <<ssl-tls>> for more information.
498-
As noted there, such modifications are possible whether or not SSL is being used.
496+
As noted there, such modifications are possible if SSL is being used, or not.
499497

500498
Also see <<ip-annotation>> and <<ip-dsl>>.
501499

@@ -1584,7 +1582,7 @@ Defaults to `ByteArrayCrLfSerializer`
15841582
| Y
15851583
| Y
15861584
| `true`, `false`
1587-
| Whether or not connection uses NIO.
1585+
| Whether the connection uses NIO.
15881586
Refer to the `java.nio` package for more information.
15891587
See <<note-nio>>.
15901588
Default: `false`.
@@ -1693,7 +1691,7 @@ For backward compatibility, it sets the backlog, but you should use `backlog` to
16931691
| `true`, `false`
16941692
| Specifies whether reverse lookups are done on IP addresses to convert to host names for use in message headers.
16951693
If false, the IP address is used instead.
1696-
Default: `true`.
1694+
Default: `false`.
16971695

16981696
| `interceptor-factory-chain`
16991697
| Y
@@ -1778,7 +1776,7 @@ You can detect this by using the `check-length` attribute..
17781776

17791777
| `check-length`
17801778
| `true`, `false`
1781-
| Whether or not a UDP adapter expects a data length field in the packet received.
1779+
| Whether a UDP adapter expects a data length field in the packet received.
17821780
Used to detect packet truncation.
17831781

17841782
| `so-timeout`
@@ -1806,7 +1804,7 @@ See the setSendBufferSize() methods in `java.net.DatagramSocket` for more inform
18061804
| `true`, `false`
18071805
| Specifies whether reverse lookups are done on IP addresses to convert to host names for use in message headers.
18081806
If `false`, the IP address is used instead.
1809-
Default: `true`.
1807+
Default: `false`.
18101808

18111809
|===
18121810

src/reference/asciidoc/whats-new.adoc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ See <<./kafka.adoc#kafka,Spring for Apache Kafka Support>> for more information.
6969

7070
=== JDBC Changes
7171

72-
The `DefaultLockRepository` can now be supplied with a `PlatformTransactionManager` instead of relying on the primary bean from the application context.
72+
The `DefaultLockRepository` can now be supplied with a `PlatformTransactionManager` instead of relying on the primary bean from the application context.
73+
74+
=== TCP/IP Changes
75+
76+
The `lookupHost` property of the `AbstractConnectionFactory` and `DatagramPacketMessageMapper` is now set to `false` by default to avoid delays in the environments where DNS is not configured.

0 commit comments

Comments
 (0)