1
0
Fork 1
mirror of https://gitlab.com/mangadex-pub/mangadex_at_home.git synced 2024-01-19 02:48:37 +00:00

Hides proxy protocol support behind a settings toggle and adds some implementation comments.

This commit is contained in:
Erek Speed 2021-07-05 08:38:15 +09:00
parent ecab240817
commit 610300c2e4
No known key found for this signature in database
GPG key ID: 12933BB2EAD9F705
3 changed files with 50 additions and 30 deletions

View file

@ -80,3 +80,10 @@ server_settings:
# 0 defaults to (2 * your available processors) # 0 defaults to (2 * your available processors)
# https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runtime.html#availableProcessors() # https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Runtime.html#availableProcessors()
threads: 0 threads: 0
# Whether to enable support for HAProxy Proxy Protocol
# If using a reverse proxy to forward requests to MD@H via
# ssl passthrough, you can use Proxy Protocol to preserve
# original IP if your reverse proxy supports it. This
# will allow geo location metrics to work correctly.
# https://www.haproxy.com/blog/haproxy/proxy-protocol/
enable_proxy_protocol: false

View file

@ -184,29 +184,35 @@ class Netty(
.childHandler(object : ChannelInitializer<SocketChannel>() { .childHandler(object : ChannelInitializer<SocketChannel>() {
val HAPROXY_SOURCE = AttributeKey.newInstance<String>("haproxy_source") val HAPROXY_SOURCE = AttributeKey.newInstance<String>("haproxy_source")
public override fun initChannel(ch: SocketChannel) { public override fun initChannel(ch: SocketChannel) {
ch.pipeline().addLast( if (serverSettings.enableProxyProtocol) {
"proxyProtocol", ch.pipeline().addLast(
object : ChannelInboundHandlerAdapter() { "proxyProtocol",
override fun channelRead(ctx: ChannelHandlerContext, msg: Any) { object : ChannelInboundHandlerAdapter() {
if (msg is ByteBuf) { override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
val result: ProtocolDetectionResult<HAProxyProtocolVersion> = HAProxyMessageDecoder.detectProtocol(msg) if (msg is ByteBuf) {
if (result.state() == ProtocolDetectionState.DETECTED) { // Since the builtin `HAProxyMessageDecoder` will break non Proxy Protocol requests
ctx.pipeline().addAfter("proxyProtocol", null, HAProxyMessageDecoder()) // we need to use its detection capabilities to only add it when needed.
ctx.pipeline().remove(this) val result: ProtocolDetectionResult<HAProxyProtocolVersion> = HAProxyMessageDecoder.detectProtocol(msg)
if (result.state() == ProtocolDetectionState.DETECTED) {
ctx.pipeline().addAfter("proxyProtocol", null, HAProxyMessageDecoder())
ctx.pipeline().remove(this)
}
} }
super.channelRead(ctx, msg)
} }
super.channelRead(ctx, msg)
} }
} )
) ch.pipeline().addLast(
ch.pipeline().addLast( "saveOriginalIp",
"saveOriginalIp", object : SimpleChannelInboundHandler<HAProxyMessage>() {
object : SimpleChannelInboundHandler<HAProxyMessage>() { override fun channelRead0(ctx: ChannelHandlerContext, msg: HAProxyMessage) {
override fun channelRead0(ctx: ChannelHandlerContext, msg: HAProxyMessage) { // Store proxy IP in an attribute for later use after HTTP request is extracted.
(ctx as AttributeMap).attr(HAPROXY_SOURCE).set(msg.sourceAddress()) // Using an attribute ensures the value is scoped to this channel.
(ctx as AttributeMap).attr(HAPROXY_SOURCE).set(msg.sourceAddress())
}
} }
} )
) }
ch.pipeline().addLast( ch.pipeline().addLast(
"ssl", "ssl",
SniHandler(DomainWildcardMappingBuilder(sslContext).build()) SniHandler(DomainWildcardMappingBuilder(sslContext).build())
@ -239,19 +245,25 @@ class Netty(
ch.pipeline().addLast("keepAlive", HttpServerKeepAliveHandler()) ch.pipeline().addLast("keepAlive", HttpServerKeepAliveHandler())
ch.pipeline().addLast("aggregator", HttpObjectAggregator(65536)) ch.pipeline().addLast("aggregator", HttpObjectAggregator(65536))
ch.pipeline().addLast( if (serverSettings.enableProxyProtocol) {
"setForwardHeader", ch.pipeline().addLast(
object : SimpleChannelInboundHandler<FullHttpRequest>(false) { "setForwardHeader",
override fun channelRead0(ctx: ChannelHandlerContext, request: FullHttpRequest) { object : SimpleChannelInboundHandler<FullHttpRequest>(false) {
if ((ctx as AttributeMap).hasAttr(HAPROXY_SOURCE)) { override fun channelRead0(ctx: ChannelHandlerContext, request: FullHttpRequest) {
val addr = (ctx as AttributeMap).attr(HAPROXY_SOURCE).get() // The geo location code already supports the `Forwarded header so setting
request.headers().set("Forwarded", addr) // it is the easiest way to introduce the original IP downstream.
if ((ctx as AttributeMap).hasAttr(HAPROXY_SOURCE)) {
val addr = (ctx as AttributeMap).attr(HAPROXY_SOURCE).get()
request.headers().set("Forwarded", addr)
}
// Since we're modifying the request without handling it, we must
// call retain to ensure it will still be available downstream.
ReferenceCountUtil.retain(request)
ctx.fireChannelRead(request)
} }
ReferenceCountUtil.retain(request)
ctx.fireChannelRead(request)
} }
} )
) }
ch.pipeline().addLast("burstLimiter", burstLimiter) ch.pipeline().addLast("burstLimiter", burstLimiter)

View file

@ -43,6 +43,7 @@ data class ServerSettings(
val externalIp: String? = null, val externalIp: String? = null,
val port: Int = 443, val port: Int = 443,
val threads: Int = 0, val threads: Int = 0,
val enableProxyProtocol: Boolean = false,
) )
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class)