Skip to content

Commit

Permalink
feat(Lite): Add modifyVirtualHost route option (closes #180)
Browse files Browse the repository at this point in the history
  • Loading branch information
robinbraemer committed Jul 28, 2023
1 parent acb3c57 commit 429c59a
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 16 deletions.
27 changes: 26 additions & 1 deletion .web/docs/guide/lite.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Gate Lite Mode


## What is Lite mode?

Gate has a `Lite` mode that makes Gate act as an ultra-thin lightweight reverse proxy between
Expand Down Expand Up @@ -71,7 +72,8 @@ Note that routes can configure multiple random backends and each backend has its

Setting the TTL to `-1` disables response caching for this route only.

```yaml
::: code-group
```yaml [config.yml]
config:
lite:
enabled: true
Expand All @@ -80,6 +82,7 @@ config:
backend: 10.0.0.3:25568
cachePingTTL: -1 // [!code ++]
```
:::

## Fallback status for offline backends

Expand All @@ -106,6 +109,28 @@ config:
```
:::

## Modify virtual host

Modifies the virtual host to match the backend address in the handshake request.
This is useful when backends require players to connect with a specific domain to
prevent players from using third party domains.

To work around this limitation, simply enable this on your route:

::: code-group
```yaml [config.yml]
config:
lite:
enabled: true
routes:
- host: localhost
backend: play.example.com
modifyVirtualHost: true // [!code ++]
```
:::

Lite will modify the player's handshake packet's virtual host field from `localhost` -> `play.example.com`
before forwarding the connection to the backend.

## Sample config

Expand Down
8 changes: 7 additions & 1 deletion config-lite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ config:
- host: localhost
# The backend server to connect to if matched.
backend: localhost:25566
# The optional fallback status response when backend of this route are offline.
# The optional fallback status response when all backends of this route are offline.
fallback:
motd: |
§cLocalhost server is offline.
Expand All @@ -48,6 +48,12 @@ config:
# To disable motd caching set it to -1.
# Default: 10s
cachePingTTL: 60s
# Modifies the virtual host to match the backend address in the handshake request.
# This is useful when backends require players to connect with a specific domain.
# Lite will modify the player's handshake packet's virtual host field from `localhost` -> `backend.example.com`
# before forwarding the connection to the backend.
# Default: false
modifyVirtualHost: true
# Match all as last item routes any other host to a default backend.
- host: '*'
backend: 10.0.0.10:25565
Expand Down
8 changes: 7 additions & 1 deletion config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ config:
- host: localhost
# The backend server to connect to if matched.
backend: localhost:25566
# The optional fallback status response when backend of this route are offline.
# The optional fallback status response when all backends of this route are offline.
fallback:
motd: |
§cLocalhost server is offline.
Expand All @@ -156,6 +156,12 @@ config:
# To disable motd caching set it to -1.
# Default: 10s
cachePingTTL: 60s
# Modifies the virtual host to match the backend address in the handshake request.
# This is useful when backends require players to connect with a specific domain.
# Lite will modify the player's handshake packet's virtual host field from `localhost` -> `backend.example.com`
# before forwarding the connection to the backend.
# Default: false
modifyVirtualHost: true
# Match all as last item routes any other host to a default backend.
- host: '*'
backend: 10.0.0.10:25565
Expand Down
13 changes: 7 additions & 6 deletions pkg/edition/java/lite/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ type (
Routes []Route
}
Route struct {
Host configutil.SingleOrMulti[string] `json:"host" yaml:"host"`
Backend configutil.SingleOrMulti[string] `json:"backend" yaml:"backend"`
CachePingTTL configutil.Duration `json:"cachePingTTL,omitempty" yaml:"cachePingTTL,omitempty"` // 0 = default, < 0 = disabled
Fallback *Status `json:"fallback,omitempty" yaml:"fallback,omitempty"` // nil = disabled
ProxyProtocol bool `json:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty"`
RealIP bool `json:"realIP,omitempty" yaml:"realIP,omitempty"`
Host configutil.SingleOrMulti[string] `json:"host" yaml:"host"`
Backend configutil.SingleOrMulti[string] `json:"backend" yaml:"backend"`
CachePingTTL configutil.Duration `json:"cachePingTTL,omitempty" yaml:"cachePingTTL,omitempty"` // 0 = default, < 0 = disabled
Fallback *Status `json:"fallback,omitempty" yaml:"fallback,omitempty"` // nil = disabled
ProxyProtocol bool `json:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty"`
RealIP bool `json:"realIP,omitempty" yaml:"realIP,omitempty"`
ModifyVirtualHost bool `json:"modifyVirtualHost,omitempty" yaml:"modifyVirtualHost,omitempty"`
}
Status struct {
MOTD string `yaml:"motd,omitempty" json:"motd,omitempty"`
Expand Down
22 changes: 16 additions & 6 deletions pkg/edition/java/lite/forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"io"
"net"
"strings"
"time"

"github.com/go-logr/logr"
Expand Down Expand Up @@ -184,24 +185,24 @@ func dialRoute(
dialTimeout time.Duration,
srcAddr net.Addr,
route *config.Route,
routeAddr string,
backendAddr string,
handshake *packet.Handshake,
pc *proto.PacketContext,
handshakeCtx *proto.PacketContext,
forceUpdatePacketContext bool,
) (dst net.Conn, err error) {
dialCtx, cancel := context.WithTimeout(ctx, dialTimeout)
defer cancel()

var dialer net.Dialer
dst, err = dialer.DialContext(dialCtx, "tcp", routeAddr)
dst, err = dialer.DialContext(dialCtx, "tcp", backendAddr)
if err != nil {
v := 0
if dialCtx.Err() != nil {
v++
}
return nil, &errs.VerbosityError{
Verbosity: v,
Err: fmt.Errorf("failed to connect to backend %s: %w", routeAddr, err),
Err: fmt.Errorf("failed to connect to backend %s: %w", backendAddr, err),
}
}
defer func() {
Expand All @@ -217,17 +218,26 @@ func dialRoute(
}
}

if route.ModifyVirtualHost {
clearedHost := ClearVirtualHost(handshake.ServerAddress)
backendHost := netutil.HostStr(backendAddr)
if !strings.EqualFold(clearedHost, backendHost) {
// Modify the handshake packet to use the backend host as virtual host.
handshake.ServerAddress = strings.ReplaceAll(handshake.ServerAddress, clearedHost, backendHost)
forceUpdatePacketContext = true
}
}
if route.RealIP && IsRealIP(handshake.ServerAddress) {
// Modify the handshake packet to use RealIP of the client.
handshake.ServerAddress = RealIP(handshake.ServerAddress, srcAddr)
forceUpdatePacketContext = true
}
if forceUpdatePacketContext {
update(pc, handshake)
update(handshakeCtx, handshake)
}

// Forward handshake packet as is.
if err = writePacket(dst, pc); err != nil {
if err = writePacket(dst, handshakeCtx); err != nil {
return nil, fmt.Errorf("failed to write handshake packet to backend: %w", err)
}

Expand Down
7 changes: 6 additions & 1 deletion pkg/util/netutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import (

// Host returns the host of net.Addr.
func Host(addr net.Addr) string {
host, _, _ := splitHostPort(addr.String())
return HostStr(addr.String())
}

// HostStr returns the host of the address.
func HostStr(addr string) string {
host, _, _ := splitHostPort(addr)
return host
}

Expand Down

0 comments on commit 429c59a

Please sign in to comment.