Skip to content

Commit 9c23def

Browse files
committed
wip
1 parent 1c2d049 commit 9c23def

File tree

2 files changed

+99
-76
lines changed

2 files changed

+99
-76
lines changed

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/http/ClientIpAddressResolver.java

Lines changed: 88 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ private static InetAddress doResolve(AgentSpanContext.Extracted context, Mutable
100100
result = coalesce(result, addr);
101101
}
102102

103+
addr = tryHeader(context.getForwarded(), FORWARDED_PARSER);
104+
if (addr != null) {
105+
if (!isIpAddrPrivate(addr)) {
106+
return addr;
107+
}
108+
result = coalesce(result, addr);
109+
}
110+
103111
addr = tryHeader(context.getXClusterClientIp(), PLAIN_IP_ADDRESS_PARSER);
104112
if (addr != null) {
105113
if (!isIpAddrPrivate(addr)) {
@@ -196,95 +204,99 @@ enum ForwardedParseState {
196204

197205
@Override
198206
public InetAddress apply(String headerValue) {
199-
InetAddress resultPrivate = null;
200-
ForwardedParseState state = ForwardedParseState.BETWEEN;
201-
202-
// https://datatracker.ietf.org/doc/html/rfc7239#section-4
203-
int pos = 0;
204-
int end = headerValue.length();
205-
// compiler requires that these two be initialized:
206-
int start = 0;
207-
boolean considerValue = false;
208-
while (pos < end) {
209-
char c = headerValue.charAt(pos);
210-
switch (state) {
211-
case BETWEEN:
212-
if (c == ' ' || c == ';' || c == ',') {
213-
break;
214-
}
215-
start = pos;
216-
state = ForwardedParseState.KEY;
217-
break;
218-
case KEY:
219-
if (c != '=') {
207+
String[] entries = headerValue.split(",");
208+
for (int i = entries.length - 1; i >= 0; i--) {
209+
String entry = entries[i].trim();
210+
InetAddress resultPrivate = null;
211+
ForwardedParseState state = ForwardedParseState.BETWEEN;
212+
// https://datatracker.ietf.org/doc/html/rfc7239#section-4
213+
int pos = 0;
214+
int end = entry.length();
215+
// compiler requires that these two be initialized:
216+
int start = 0;
217+
boolean considerValue = false;
218+
while (pos < end) {
219+
char c = entry.charAt(pos);
220+
switch (state) {
221+
case BETWEEN:
222+
if (c == ' ' || c == ';' || c == ',') {
223+
break;
224+
}
225+
start = pos;
226+
state = ForwardedParseState.KEY;
220227
break;
221-
}
228+
case KEY:
229+
if (c != '=') {
230+
break;
231+
}
222232

223-
state = ForwardedParseState.BEFORE_VALUE;
224-
if (pos - start == 3) {
225-
String key = headerValue.substring(start, pos);
226-
considerValue = key.equalsIgnoreCase("for");
227-
} else {
228-
considerValue = false;
229-
}
230-
break;
231-
case BEFORE_VALUE:
232-
if (c == '"') {
233-
start = pos + 1;
234-
state = ForwardedParseState.VALUE_QUOTED;
235-
} else if (c == ' ' || c == ';' || c == ',') {
236-
// empty value
237-
state = ForwardedParseState.BETWEEN;
238-
} else {
239-
start = pos;
240-
state = ForwardedParseState.VALUE_TOKEN;
241-
}
242-
break;
243-
case VALUE_TOKEN:
244-
{
245-
int tokenEnd;
246-
if (c == ' ' || c == ';' || c == ',') {
247-
tokenEnd = pos;
248-
} else if (pos + 1 == end) {
249-
tokenEnd = end;
233+
state = ForwardedParseState.BEFORE_VALUE;
234+
if (pos - start == 3) {
235+
String key = entry.substring(start, pos);
236+
considerValue = key.equalsIgnoreCase("for");
250237
} else {
251-
break;
238+
considerValue = false;
239+
}
240+
break;
241+
case BEFORE_VALUE:
242+
if (c == '"') {
243+
start = pos + 1;
244+
state = ForwardedParseState.VALUE_QUOTED;
245+
} else if (c == ' ' || c == ';' || c == ',') {
246+
// empty value
247+
state = ForwardedParseState.BETWEEN;
248+
} else {
249+
start = pos;
250+
state = ForwardedParseState.VALUE_TOKEN;
252251
}
252+
break;
253+
case VALUE_TOKEN:
254+
{
255+
int tokenEnd;
256+
if (c == ' ' || c == ';' || c == ',') {
257+
tokenEnd = pos;
258+
} else if (pos + 1 == end) {
259+
tokenEnd = end;
260+
} else {
261+
break;
262+
}
253263

254-
if (considerValue) {
255-
InetAddress ipAddr =
256-
parseIpAddressAndMaybePort(headerValue.substring(start, tokenEnd));
257-
if (ipAddr != null) {
258-
if (isIpAddrPrivate(ipAddr)) {
259-
if (resultPrivate == null) {
260-
resultPrivate = ipAddr;
264+
if (considerValue) {
265+
InetAddress ipAddr = parseIpAddressAndMaybePort(entry.substring(start, tokenEnd));
266+
if (ipAddr != null) {
267+
if (isIpAddrPrivate(ipAddr)) {
268+
if (resultPrivate == null) {
269+
resultPrivate = ipAddr;
270+
}
271+
} else {
272+
return ipAddr;
261273
}
262-
} else {
263-
return ipAddr;
264274
}
265275
}
276+
state = ForwardedParseState.BETWEEN;
277+
break;
266278
}
267-
state = ForwardedParseState.BETWEEN;
268-
break;
269-
}
270-
case VALUE_QUOTED:
271-
if (c == '"') {
272-
if (considerValue) {
273-
InetAddress ipAddr = parseIpAddressAndMaybePort(headerValue.substring(start, pos));
274-
if (ipAddr != null && !isIpAddrPrivate(ipAddr)) {
275-
return ipAddr;
279+
case VALUE_QUOTED:
280+
if (c == '"') {
281+
if (considerValue) {
282+
InetAddress ipAddr = parseIpAddressAndMaybePort(entry.substring(start, pos));
283+
if (ipAddr != null && !isIpAddrPrivate(ipAddr)) {
284+
return ipAddr;
285+
}
276286
}
287+
state = ForwardedParseState.BETWEEN;
288+
} else if (c == '\\') {
289+
pos++;
277290
}
278-
state = ForwardedParseState.BETWEEN;
279-
} else if (c == '\\') {
280-
pos++;
281-
}
282-
break;
291+
break;
292+
}
293+
pos++;
294+
}
295+
if (resultPrivate != null) {
296+
return resultPrivate;
283297
}
284-
pos++;
285298
}
286-
287-
return resultPrivate;
299+
return null;
288300
}
289301
}
290302

dd-java-agent/agent-bootstrap/src/test/groovy/datadog/trace/bootstrap/instrumentation/decorator/http/ClientIpAddressResolverSpecification.groovy

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ class ClientIpAddressResolverSpecification extends Specification {
7070
'fastly-client-ip' | '3.3.3.3' | '3.3.3.3'
7171
'cf-connecting-ip' | '4.4.4.4' | '4.4.4.4'
7272
'cf-connecting-ipv6' | '2001::2' | '2001::2'
73+
74+
'forwarded' | 'for=192.0.2.60;proto=http;by=203.0.113.43' | '192.0.2.60'
75+
'forwarded' | 'For="[2001:db8:cafe::17]:4711"' | '2001:db8:cafe::17'
76+
'forwarded' | 'for=192.0.2.43, for=198.51.100.17' | '198.51.100.17'
77+
'forwarded' | 'for=192.0.2.43;proto=https;by=203.0.113.43' | '192.0.2.43'
78+
'forwarded' | 'for="_gazonk"' | null
79+
'forwarded' | 'for=unknown, for=8.8.8.8' | '8.8.8.8'
80+
'forwarded' | 'for="[::ffff:192.0.2.128]";proto=http' | '192.0.2.128'
7381
}
7482

7583
void 'test recognition strategy with custom header'() {
@@ -113,6 +121,9 @@ class ClientIpAddressResolverSpecification extends Specification {
113121
then:
114122
1 * context.getForwardedFor() >> null
115123

124+
then:
125+
1 * context.getForwarded() >> null
126+
116127
then:
117128
1 * context.getXClusterClientIp() >> null
118129

0 commit comments

Comments
 (0)