Skip to content

Commit cdcb69f

Browse files
committed
Pong tweaks, debug logging, IPv6 support
1 parent 269e0f4 commit cdcb69f

File tree

8 files changed

+120
-40
lines changed

8 files changed

+120
-40
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ a few seconds. If not, you did something wrong. Or I did ;)
3434
Usage: ./phantom-<os> [options] -server <server-ip>
3535
3636
Options:
37+
-6 Optional: Enables IPv6 support on port 19133 (experimental)
3738
-bind string
3839
Optional: IP address to listen on. Defaults to all interfaces. (default "0.0.0.0")
3940
-bind_port int
4041
Optional: Port to listen on. Defaults to 0, which selects a random port.
4142
Note that phantom always binds to port 19132 as well, so both ports need to be open.
43+
-debug
44+
Optional: Enables debug logging
45+
-remove_ports
46+
Optional: Forces ports to be excluded from pong packets (experimental)
4247
-server string
4348
Required: Bedrock/MCPE server IP address and port (ex: 1.2.3.4:19132)
4449
-timeout int

cmd/phantom.go

+17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"time"
99

1010
"github.com/jhead/phantom/internal/proxy"
11+
"github.com/rs/zerolog"
12+
"github.com/rs/zerolog/log"
1113
)
1214

1315
var bindAddressString string
@@ -22,6 +24,9 @@ func main() {
2224
bindArg := flag.String("bind", "0.0.0.0", "Optional: IP address to listen on. Defaults to all interfaces.")
2325
bindPortArg := flag.Int("bind_port", 0, "Optional: Port to listen on. Defaults to 0, which selects a random port.\nNote that phantom always binds to port 19132 as well, so both ports need to be open.")
2426
timeoutArg := flag.Int("timeout", 60, "Optional: Seconds to wait before cleaning up a disconnected client")
27+
debugArg := flag.Bool("debug", false, "Optional: Enables debug logging")
28+
ipv6Arg := flag.Bool("6", false, "Optional: Enables IPv6 support on port 19133 (experimental)")
29+
removePortsArg := flag.Bool("remove_ports", false, "Optional: Forces ports to be excluded from pong packets (experimental)")
2530

2631
flag.Usage = usage
2732
flag.Parse()
@@ -36,13 +41,25 @@ func main() {
3641
idleTimeout := time.Duration(*timeoutArg) * time.Second
3742
bindPortInt = uint16(*bindPortArg)
3843

44+
logLevel := zerolog.InfoLevel
45+
if *debugArg {
46+
logLevel = zerolog.DebugLevel
47+
}
48+
3949
fmt.Printf("Starting up with remote server IP: %s\n", serverAddressString)
4050

51+
// Configure logging output
52+
log.Logger = log.
53+
Output(zerolog.ConsoleWriter{Out: os.Stdout}).
54+
Level(logLevel)
55+
4156
proxyServer, err := proxy.New(proxy.ProxyPrefs{
4257
bindAddressString,
4358
bindPortInt,
4459
serverAddressString,
4560
idleTimeout,
61+
*ipv6Arg,
62+
*removePortsArg,
4663
})
4764

4865
if err != nil {

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module github.com/jhead/phantom
33
go 1.12
44

55
require (
6+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
67
github.com/libp2p/go-reuseport v0.0.1
8+
github.com/rs/zerolog v1.18.0
79
github.com/stretchr/testify v1.3.0
810
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5
911
)

go.sum

+14
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1+
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
12
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
23
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
5+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
36
github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=
47
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
58
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
69
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
710
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
811
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
12+
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
13+
github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
14+
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
915
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
1016
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
1117
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
1218
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=
1319
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0=
20+
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
21+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
22+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
23+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
24+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
1425
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2Vd4msMcrDECFxS+tL9c=
1526
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
27+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
28+
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
29+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

internal/clientmap/clientmap.go

+5-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"sync"
66
"time"
77

8-
"github.com/jhead/phantom/internal/logging"
8+
"github.com/rs/zerolog/log"
99
"github.com/tevino/abool"
1010
)
1111

@@ -27,8 +27,6 @@ type clientEntry struct {
2727

2828
type ServerConnHandler func(*net.UDPConn)
2929

30-
var logger = logging.Get()
31-
3230
func New(idleTimeout time.Duration, idleCheckInterval time.Duration) *ClientMap {
3331
clientMap := ClientMap{
3432
idleTimeout,
@@ -63,7 +61,7 @@ func (cm *ClientMap) Close() {
6361
// Cleans up clients and remote connections that have not been used in a while.
6462
// Blocks until the ClientMap has been closed.
6563
func (cm *ClientMap) idleCleanupLoop() {
66-
logger.Println("Starting idle connection handler")
64+
log.Info().Msg("Starting idle connection handler")
6765

6866
// Loop forever using a channel that emits every IdleCheckInterval
6967
for currentTime := range time.Tick(cm.IdleCheckInterval) {
@@ -75,7 +73,7 @@ func (cm *ClientMap) idleCleanupLoop() {
7573
cm.mutex.Lock()
7674
for key, client := range cm.clients {
7775
if client.lastActive.Add(cm.IdleTimeout).Before(currentTime) {
78-
logger.Printf("Cleaning up idle connection: %s", key)
76+
log.Info().Msgf("Cleaning up idle connection: %s", key)
7977
cm.clients[key].conn.Close()
8078
delete(cm.clients, key)
8179
}
@@ -106,7 +104,7 @@ func (cm *ClientMap) Get(
106104
}
107105

108106
// New connection needed
109-
logger.Printf("Opening connection to %s for new client %s!\n", remote, clientAddr)
107+
log.Info().Msgf("Opening connection to %s for new client %s!", remote, clientAddr)
110108
newServerConn, err := newServerConnection(remote)
111109
if err != nil {
112110
return nil, err
@@ -125,7 +123,7 @@ func (cm *ClientMap) Get(
125123

126124
// Creates a UDP connection to the remote address
127125
func newServerConnection(remote *net.UDPAddr) (*net.UDPConn, error) {
128-
logger.Printf("Opening connection to %s\n", remote)
126+
log.Info().Msgf("Opening connection to %s", remote)
129127

130128
conn, err := net.DialUDP("udp", nil, remote)
131129
if err != nil {

internal/logging/logging.go

-12
This file was deleted.

internal/proto/proto.go

+11-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"encoding/binary"
66
"fmt"
7+
"regexp"
78
"strings"
89

910
"github.com/jhead/phantom/internal/util"
@@ -29,11 +30,12 @@ type PongData struct {
2930
SubMOTD string
3031
GameType string
3132
NintendoLimited string
32-
// Specifically omit these two because they cause issues
33-
// Port4 string
34-
// Port6 string
33+
Port4 string
34+
Port6 string
3535
}
3636

37+
var dupeSemicolonRegex = regexp.MustCompile(";{2,}$")
38+
3739
func ReadUnconnectedReply(in []byte) (reply *UnconnectedReply, err error) {
3840
reply = &UnconnectedReply{}
3941
buf := bytes.NewBuffer(in)
@@ -114,8 +116,12 @@ func writePong(pong PongData) string {
114116
var pongDataFields []string
115117
pongDataFieldsRaw := util.MapStructToFields(&pong)
116118
for _, value := range pongDataFieldsRaw {
117-
pongDataFields = append(pongDataFields, fmt.Sprintf("%v", value))
119+
stringValue := fmt.Sprintf("%v", value)
120+
pongDataFields = append(pongDataFields, stringValue)
118121
}
119122

120-
return strings.Join(pongDataFields, ";")
123+
// Ensure that there aren't a bunch of ; on the end, but at least one
124+
joined := strings.Join(pongDataFields, ";")
125+
joined = dupeSemicolonRegex.ReplaceAllString(joined, "")
126+
return fmt.Sprintf("%s;", joined)
121127
}

0 commit comments

Comments
 (0)