Skip to content

Commit e19abce

Browse files
alvdaviRealCLanger
authored andcommitted
8286910: Improve JNDI lookups
Reviewed-by: mbalao, mbaesken Backport-of: daf133f773ea567d66663ce6916541bc0df1421a
1 parent e3ad4e5 commit e19abce

File tree

1 file changed

+57
-8
lines changed

1 file changed

+57
-8
lines changed

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

Lines changed: 57 additions & 8 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

@@ -218,24 +243,48 @@ synchronized boolean isUndecided() {
218243
&& !isUsingNativePortRandomization();
219244
}
220245

246+
private boolean farEnough(int port) {
247+
return Integer.bitCount(port ^ lastport) > BIT_DEVIATION
248+
&& Math.abs(port - lastport) > deviation;
249+
}
250+
221251
private DatagramSocket openRandom() {
222252
int maxtries = MAX_RANDOM_TRIES;
223253
while (maxtries-- > 0) {
224-
int port = EphemeralPortRange.LOWER
225-
+ random.nextInt(EphemeralPortRange.RANGE);
254+
int port;
255+
boolean suitable;
256+
boolean recycled;
257+
int maxrandom = MAX_RANDOM_TRIES;
258+
do {
259+
port = EphemeralPortRange.LOWER
260+
+ random.nextInt(EphemeralPortRange.RANGE);
261+
recycled = history.contains(port);
262+
suitable = lastport == 0 || (farEnough(port) && !recycled);
263+
} while (maxrandom-- > 0 && !suitable);
264+
265+
// if no suitable port was found, try again
266+
// this means we might call random MAX_RANDOM_TRIES x MAX_RANDOM_TRIES
267+
// times - but that should be OK with MAX_RANDOM_TRIES = 5.
268+
if (!suitable) continue;
269+
226270
try {
227271
if (family != null) {
228272
DatagramChannel c = DatagramChannel.open(family);
229273
try {
230274
DatagramSocket s = c.socket();
231275
s.bind(new InetSocketAddress(port));
276+
lastport = s.getLocalPort();
277+
if (!recycled) history.add(port);
232278
return s;
233279
} catch (Throwable x) {
234280
c.close();
235281
throw x;
236282
}
237283
}
238-
return new DatagramSocket(port);
284+
DatagramSocket s = new DatagramSocket(port);
285+
lastport = s.getLocalPort();
286+
if (!recycled) history.add(port);
287+
return s;
239288
} catch (IOException x) {
240289
// try again until maxtries == 0;
241290
}

0 commit comments

Comments
 (0)