22
33import static io .quarkus .vertx .http .runtime .TrustedProxyCheck .denyAll ;
44
5+ import java .net .Inet4Address ;
6+ import java .net .Inet6Address ;
57import java .net .InetAddress ;
8+ import java .util .ArrayList ;
9+ import java .util .Collection ;
610import java .util .Iterator ;
11+ import java .util .List ;
712import java .util .Map ;
813import java .util .Objects ;
14+ import java .util .Set ;
915import java .util .function .Supplier ;
16+ import java .util .stream .Collectors ;
1017
1118import org .jboss .logging .Logger ;
1219
1320import io .smallrye .common .net .Inet ;
14- import io .vertx .core .AsyncResult ;
21+ import io .vertx .core .Future ;
1522import io .vertx .core .Handler ;
1623import io .vertx .core .Vertx ;
1724import io .vertx .core .dns .DnsClient ;
1825import io .vertx .core .http .HttpServerRequest ;
26+ import io .vertx .core .net .SocketAddress ;
1927import io .vertx .core .net .impl .SocketAddressImpl ;
2028
2129/**
@@ -75,30 +83,28 @@ private void lookupHostNamesAndHandleRequest(HttpServerRequest event,
7583 // we do not cache result as IP address may change, and we advise users to use IP or CIDR
7684 final var entry = iterator .next ();
7785 final String hostName = entry .getKey ();
78- dnsClient .lookup (hostName ,
79- new Handler <AsyncResult <String >>() {
80- @ Override
81- public void handle (AsyncResult <String > stringAsyncResult ) {
82- if (stringAsyncResult .succeeded () && stringAsyncResult .result () != null ) {
83- var trustedIP = Inet .parseInetAddress (stringAsyncResult .result ());
84- if (trustedIP != null ) {
85- // create proxy check for resolved IP and proceed with the lookup
86- lookupHostNamesAndHandleRequest (event , iterator ,
87- builder .withTrustedIP (trustedIP , entry .getValue ()), dnsClient );
88- } else {
89- logInvalidIpAddress (hostName );
90- // ignore this hostname proxy check and proceed with the lookup
91- lookupHostNamesAndHandleRequest (event , iterator , builder , dnsClient );
92- }
93- } else {
94- // inform we can't cope without IP
95- logDnsLookupFailure (hostName );
96- // ignore this hostname proxy check and proceed with the lookup
97- lookupHostNamesAndHandleRequest (event , iterator , builder , dnsClient );
98- }
99- }
10086
101- });
87+ resolveHostNameToAllIpAddresses (dnsClient , hostName , event .remoteAddress (), results -> {
88+ if (!results .isEmpty ()) {
89+ Set <InetAddress > trustedIPs = results .stream ().map (Inet ::parseInetAddress ).filter (Objects ::nonNull )
90+ .collect (Collectors .toSet ());
91+ if (!trustedIPs .isEmpty ()) {
92+ // create proxy check for resolved IP and proceed with the lookup
93+ lookupHostNamesAndHandleRequest (event , iterator ,
94+ builder .withTrustedIP (trustedIPs , entry .getValue ()), dnsClient );
95+ } else {
96+ logInvalidIpAddress (hostName );
97+ // ignore this hostname proxy check and proceed with the lookup
98+ lookupHostNamesAndHandleRequest (event , iterator , builder , dnsClient );
99+ }
100+ } else {
101+ // inform we can't cope without IP
102+ logDnsLookupFailure (hostName );
103+ // ignore this hostname proxy check and proceed with the lookup
104+ lookupHostNamesAndHandleRequest (event , iterator , builder , dnsClient );
105+ }
106+ });
107+
102108 } else {
103109 // DNS lookup is done
104110 if (builder .hasProxyChecks ()) {
@@ -110,6 +116,38 @@ public void handle(AsyncResult<String> stringAsyncResult) {
110116 }
111117 }
112118
119+ private void resolveHostNameToAllIpAddresses (DnsClient dnsClient , String hostName , SocketAddress callersSocketAddress ,
120+ Handler <Collection <String >> handler ) {
121+ ArrayList <Future <List <String >>> results = new ArrayList <>();
122+ InetAddress proxyIP = null ;
123+ if (callersSocketAddress != null ) {
124+ proxyIP = ((SocketAddressImpl ) callersSocketAddress ).ipAddress ();
125+ }
126+ // Match the lookup with the address type of the caller
127+ if (proxyIP == null || proxyIP instanceof Inet4Address ) {
128+ results .add (dnsClient .resolveA (hostName ));
129+ }
130+ if (proxyIP == null || proxyIP instanceof Inet6Address ) {
131+ results .add (dnsClient .resolveAAAA (hostName ));
132+ }
133+ processFutures (results , new ArrayList <>(), handler );
134+ }
135+
136+ private void processFutures (ArrayList <Future <List <String >>> future , Collection <String > results ,
137+ Handler <Collection <String >> handler ) {
138+ if (!future .isEmpty ()) {
139+ Future <List <String >> poll = future .remove (0 );
140+ poll .onComplete (result -> {
141+ if (result .succeeded () && result .result () != null ) {
142+ results .addAll (result .result ());
143+ }
144+ processFutures (future , results , handler );
145+ });
146+ } else {
147+ handler .handle (results );
148+ }
149+ }
150+
113151 private void resolveProxyIpAndHandleRequest (HttpServerRequest event ,
114152 TrustedProxyCheck .TrustedProxyCheckBuilder builder ) {
115153 InetAddress proxyIP = ((SocketAddressImpl ) event .remoteAddress ()).ipAddress ();
@@ -121,28 +159,26 @@ private void resolveProxyIpAndHandleRequest(HttpServerRequest event,
121159 if (proxyIP == null ) {
122160 // perform DNS lookup, then create proxy check and handle request
123161 final String hostName = Objects .requireNonNull (event .remoteAddress ().hostName ());
124- vertx .get ().createDnsClient ().lookup (hostName ,
125- new Handler <AsyncResult <String >>() {
126- @ Override
127- public void handle (AsyncResult <String > stringAsyncResult ) {
128- TrustedProxyCheck proxyCheck ;
129- if (stringAsyncResult .succeeded ()) {
130- // use resolved IP to build proxy check
131- final var proxyIP = Inet .parseInetAddress (stringAsyncResult .result ());
132- if (proxyIP != null ) {
133- proxyCheck = builder .build (proxyIP , event .remoteAddress ().port ());
134- } else {
135- logInvalidIpAddress (hostName );
136- proxyCheck = denyAll ();
137- }
162+ resolveHostNameToAllIpAddresses (vertx .get ().createDnsClient (), hostName , null ,
163+ results -> {
164+ TrustedProxyCheck proxyCheck ;
165+ if (!results .isEmpty ()) {
166+ // use resolved IP to build proxy check
167+ Set <InetAddress > proxyIPs = results .stream ().map (Inet ::parseInetAddress ).filter (Objects ::nonNull )
168+ .collect (Collectors .toSet ());
169+ if (!proxyIPs .isEmpty ()) {
170+ proxyCheck = builder .build (proxyIPs , event .remoteAddress ().port ());
138171 } else {
139- // we can't cope without IP => ignore headers
140- logDnsLookupFailure (hostName );
172+ logInvalidIpAddress (hostName );
141173 proxyCheck = denyAll ();
142174 }
143-
144- handleForwardedServerRequest (event , proxyCheck );
175+ } else {
176+ // we can't cope without IP => ignore headers
177+ logDnsLookupFailure (hostName );
178+ proxyCheck = denyAll ();
145179 }
180+
181+ handleForwardedServerRequest (event , proxyCheck );
146182 });
147183 } else {
148184 // we have proxy IP => create proxy check and handle request
0 commit comments