2626import io .netty .handler .codec .http .HttpResponseEncoder ;
2727import io .netty .handler .timeout .ReadTimeoutHandler ;
2828import jakarta .annotation .Nullable ;
29+ import jakarta .inject .Named ;
2930import org .graylog2 .configuration .TLSProtocolsConfiguration ;
3031import org .graylog2 .inputs .transports .netty .EventLoopGroupFactory ;
32+ import org .graylog2 .inputs .transports .netty .HttpForwardedForHandler ;
3133import org .graylog2 .inputs .transports .netty .HttpHandler ;
3234import org .graylog2 .inputs .transports .netty .LenientDelimiterBasedFrameDecoder ;
3335import org .graylog2 .plugin .InputFailureRecorder ;
4345import org .graylog2 .plugin .inputs .annotations .ConfigClass ;
4446import org .graylog2 .plugin .inputs .transports .AbstractTcpTransport ;
4547import org .graylog2 .plugin .inputs .util .ThroughputCounter ;
48+ import org .graylog2 .utilities .IpSubnet ;
4649
4750import java .util .LinkedHashMap ;
51+ import java .util .Set ;
4852import java .util .concurrent .Callable ;
4953import java .util .concurrent .TimeUnit ;
5054
@@ -66,22 +70,33 @@ abstract public class AbstractHttpTransport extends AbstractTcpTransport {
6670 static final String CK_AUTHORIZATION_HEADER_VALUE = "authorization_header_value" ;
6771 private static final String AUTHORIZATION_HEADER_NAME_LABEL = "Authorization Header Name" ;
6872 private static final String AUTHORIZATION_HEADER_VALUE_LABEL = "Authorization Header Value" ;
73+ static final String CK_REAL_IP_HEADER_NAME = "real_ip_header_name" ;
74+ static final String CK_ENABLE_FORWARDED_FOR = "enable_forwarded_for" ;
75+ static final String CK_REQUIRE_TRUSTED_PROXIES = "require_trusted_proxies" ;
76+ static final String CK_ENABLE_REAL_IP_HEADER = "enable_real_ip_header" ;
6977
7078 protected final boolean enableBulkReceiving ;
7179 protected final boolean enableCors ;
7280 protected final int maxChunkSize ;
7381 private final int idleWriterTimeout ;
7482 private final String authorizationHeader ;
7583 private final String authorizationHeaderValue ;
84+ private final Set <IpSubnet > trustedProxies ;
7685 private final String path ;
86+ private final boolean enableForwardedFor ;
87+ private final boolean requireTrustedProxies ;
88+ private final boolean enableRealIpHeader ;
89+ private final String realIpHeaders ;
7790
7891 public AbstractHttpTransport (Configuration configuration ,
7992 EventLoopGroup eventLoopGroup ,
8093 EventLoopGroupFactory eventLoopGroupFactory ,
8194 NettyTransportConfiguration nettyTransportConfiguration ,
8295 ThroughputCounter throughputCounter ,
8396 LocalMetricRegistry localRegistry ,
84- TLSProtocolsConfiguration tlsConfiguration , String path ) {
97+ TLSProtocolsConfiguration tlsConfiguration ,
98+ @ Named ("trusted_proxies" ) Set <IpSubnet > trustedProxies ,
99+ String path ) {
85100 super (configuration ,
86101 throughputCounter ,
87102 localRegistry ,
@@ -95,6 +110,11 @@ public AbstractHttpTransport(Configuration configuration,
95110 this .idleWriterTimeout = configuration .intIsSet (CK_IDLE_WRITER_TIMEOUT ) ? configuration .getInt (CK_IDLE_WRITER_TIMEOUT , DEFAULT_IDLE_WRITER_TIMEOUT ) : DEFAULT_IDLE_WRITER_TIMEOUT ;
96111 this .authorizationHeader = configuration .getString (CK_AUTHORIZATION_HEADER_NAME );
97112 this .authorizationHeaderValue = configuration .getString (CK_AUTHORIZATION_HEADER_VALUE );
113+ this .enableForwardedFor = configuration .getBoolean (CK_ENABLE_FORWARDED_FOR );
114+ this .requireTrustedProxies = configuration .getBoolean (CK_REQUIRE_TRUSTED_PROXIES );
115+ this .enableRealIpHeader = configuration .getBoolean (CK_ENABLE_REAL_IP_HEADER );
116+ this .realIpHeaders = configuration .getString (CK_REAL_IP_HEADER_NAME );
117+ this .trustedProxies = trustedProxies ;
98118 this .path = path ;
99119 }
100120
@@ -120,6 +140,7 @@ protected LinkedHashMap<String, Callable<? extends ChannelHandler>> getCustomChi
120140 handlers .put ("decompressor" , HttpContentDecompressor ::new );
121141 handlers .put ("encoder" , HttpResponseEncoder ::new );
122142 handlers .put ("aggregator" , () -> new HttpObjectAggregator (maxChunkSize ));
143+ handlers .put ("http-forwarded-for-handler" , () -> new HttpForwardedForHandler (enableForwardedFor , enableRealIpHeader , realIpHeaders , requireTrustedProxies , trustedProxies ));
123144 handlers .put ("http-handler" , () -> new HttpHandler (enableCors , authorizationHeader , authorizationHeaderValue , path ));
124145 if (enableBulkReceiving ) {
125146 handlers .put ("http-bulk-newline-decoder" ,
@@ -180,6 +201,31 @@ public ConfigurationRequest getRequestedConfiguration() {
180201 "The secret authorization header value which all request must have in order to authenticate successfully. e.g. Bearer: <api-token>N" ,
181202 ConfigurationField .Optional .OPTIONAL ,
182203 TextField .Attribute .IS_PASSWORD ));
204+ r .addField (new BooleanField (
205+ CK_ENABLE_FORWARDED_FOR ,
206+ "Take original client IP from X-Forwarded-For or Forwarded headers" ,
207+ false ,
208+ "Parse X-Forwarded-For and Forwarded (RFC 7239) headers to find the original client IP address, when relayed through proxies or load balancers."
209+ ));
210+ r .addField (new BooleanField (
211+ CK_REQUIRE_TRUSTED_PROXIES ,
212+ "Only allow trusted proxies" ,
213+ false ,
214+ "Check all relaying proxies in forwarded-for headers to match the server configuration's trusted_proxies setting."
215+ ));
216+ r .addField (new BooleanField (
217+ CK_ENABLE_REAL_IP_HEADER ,
218+ "Enable trusting the original client IP header(s)" ,
219+ false ,
220+ "If enabled try to find the original client IP in one of the specified 'real ip' headers."
221+ ));
222+ r .addField (new TextField (
223+ CK_REAL_IP_HEADER_NAME ,
224+ "Header(s) containing the original client IP" ,
225+ "X-Real-IP, X-Client-IP, CF-Connecting-IP, True-Client-IP, Fastly-Client-IP" ,
226+ "Some services and proxies set the first non-proxy IP address in a special header, these headers are checked in order if specified. Separate multiple headers by comma." ,
227+ ConfigurationField .Optional .OPTIONAL
228+ ));
183229 return r ;
184230 }
185231 }
0 commit comments