Skip to content

Commit 40539de

Browse files
dfuchslowhog
authored andcommitted
8286910: Improve JNDI lookups
Reviewed-by: jpai, msheppar, rhalade, aefimov
1 parent 896a29d commit 40539de

File tree

1 file changed

+58
-11
lines changed

1 file changed

+58
-11
lines changed

src/jdk.naming.dns/share/classes/com/sun/jndi/dns/DNSDatagramSocketFactory.java

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,8 @@
3030
import java.net.SocketException;
3131
import java.net.InetSocketAddress;
3232
import java.nio.channels.DatagramChannel;
33+
import java.security.AccessController;
34+
import java.security.PrivilegedExceptionAction;
3335
import java.util.Objects;
3436
import java.util.Random;
3537

@@ -50,6 +52,21 @@ private EphemeralPortRange() {}
5052
static final int RANGE = UPPER - LOWER + 1;
5153
}
5254

55+
private static int findFirstFreePort() {
56+
PrivilegedExceptionAction<DatagramSocket> action = () -> new DatagramSocket(0);
57+
int port;
58+
try {
59+
@SuppressWarnings({"deprecated", "removal"})
60+
DatagramSocket ds = AccessController.doPrivileged(action);
61+
try (DatagramSocket ds1 = ds) {
62+
port = ds1.getLocalPort();
63+
}
64+
} catch (Exception x) {
65+
port = 0;
66+
}
67+
return port;
68+
}
69+
5370
// Records a subset of max {@code capacity} previously used ports
5471
static final class PortHistory {
5572
final int capacity;
@@ -74,7 +91,10 @@ public boolean contains(int port) {
7491
public boolean add(int port) {
7592
if (ports[index] != 0) { // at max capacity
7693
// remove one port at random and store the new port there
77-
ports[random.nextInt(capacity)] = port;
94+
// don't remove the last port
95+
int remove = random.nextInt(capacity);
96+
if ((remove +1) % capacity == index) remove = index;
97+
ports[index = remove] = port;
7898
} else { // there's a free slot
7999
ports[index] = port;
80100
}
@@ -90,7 +110,8 @@ public boolean offer(int port) {
90110
}
91111
}
92112

93-
int lastport = 0;
113+
int lastport = findFirstFreePort();
114+
int lastSystemAllocated = lastport;
94115
int suitablePortCount;
95116
int unsuitablePortCount;
96117
final ProtocolFamily family; // null (default) means dual stack
@@ -147,13 +168,16 @@ public synchronized DatagramSocket open() throws SocketException {
147168
s = openDefault();
148169
lastport = s.getLocalPort();
149170
if (lastseen == 0) {
171+
lastSystemAllocated = lastport;
150172
history.offer(lastport);
151173
return s;
152174
}
153175

154176
thresholdCrossed = suitablePortCount > thresholdCount;
155-
boolean farEnough = Integer.bitCount(lastseen ^ lastport) > BIT_DEVIATION
156-
&& Math.abs(lastport - lastseen) > deviation;
177+
boolean farEnough = farEnough(lastseen);
178+
if (farEnough && lastSystemAllocated > 0) {
179+
farEnough = farEnough(lastSystemAllocated);
180+
}
157181
boolean recycled = history.contains(lastport);
158182
boolean suitable = (thresholdCrossed || farEnough && !recycled);
159183
if (suitable && !recycled) history.add(lastport);
@@ -168,6 +192,7 @@ public synchronized DatagramSocket open() throws SocketException {
168192
// Either the underlying stack supports random UDP port allocation,
169193
// or the new port is sufficiently distant from last port to make
170194
// it look like it is. Let's use it.
195+
lastSystemAllocated = lastport;
171196
return s;
172197
}
173198

@@ -196,9 +221,7 @@ private DatagramSocket openDefault() throws SocketException {
196221
} catch (SocketException x) {
197222
throw x;
198223
} catch (IOException x) {
199-
SocketException e = new SocketException(x.getMessage());
200-
e.initCause(x);
201-
throw e;
224+
throw new SocketException(x.getMessage(), x);
202225
}
203226
}
204227
return new DatagramSocket();
@@ -218,24 +241,48 @@ synchronized boolean isUndecided() {
218241
&& !isUsingNativePortRandomization();
219242
}
220243

244+
private boolean farEnough(int port) {
245+
return Integer.bitCount(port ^ lastport) > BIT_DEVIATION
246+
&& Math.abs(port - lastport) > deviation;
247+
}
248+
221249
private DatagramSocket openRandom() {
222250
int maxtries = MAX_RANDOM_TRIES;
223251
while (maxtries-- > 0) {
224-
int port = EphemeralPortRange.LOWER
225-
+ random.nextInt(EphemeralPortRange.RANGE);
252+
int port;
253+
boolean suitable;
254+
boolean recycled;
255+
int maxrandom = MAX_RANDOM_TRIES;
256+
do {
257+
port = EphemeralPortRange.LOWER
258+
+ random.nextInt(EphemeralPortRange.RANGE);
259+
recycled = history.contains(port);
260+
suitable = lastport == 0 || (farEnough(port) && !recycled);
261+
} while (maxrandom-- > 0 && !suitable);
262+
263+
// if no suitable port was found, try again
264+
// this means we might call random MAX_RANDOM_TRIES x MAX_RANDOM_TRIES
265+
// times - but that should be OK with MAX_RANDOM_TRIES = 5.
266+
if (!suitable) continue;
267+
226268
try {
227269
if (family != null) {
228270
DatagramChannel c = DatagramChannel.open(family);
229271
try {
230272
DatagramSocket s = c.socket();
231273
s.bind(new InetSocketAddress(port));
274+
lastport = s.getLocalPort();
275+
if (!recycled) history.add(port);
232276
return s;
233277
} catch (Throwable x) {
234278
c.close();
235279
throw x;
236280
}
237281
}
238-
return new DatagramSocket(port);
282+
DatagramSocket s = new DatagramSocket(port);
283+
lastport = s.getLocalPort();
284+
if (!recycled) history.add(port);
285+
return s;
239286
} catch (IOException x) {
240287
// try again until maxtries == 0;
241288
}

0 commit comments

Comments
 (0)