chore(inputs.minecraft): Migrate plugin to new maintained version of rcon (#14868)
This commit is contained in:
parent
d1ed7e82a4
commit
4111cee421
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/minecraft/internal/rcon"
|
"github.com/gorcon/rcon"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -40,22 +40,12 @@ type connector struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *connector) Connect() (Connection, error) {
|
func (c *connector) Connect() (Connection, error) {
|
||||||
p, err := strconv.Atoi(c.port)
|
client, err := rcon.Dial(c.hostname+":"+c.port, c.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := rcon.NewClient(c.hostname, p)
|
return client, nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = client.Authorize(c.password)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &connection{client: client}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newClient(connector Connector) *client {
|
func newClient(connector Connector) *client {
|
||||||
|
|
@ -110,18 +100,6 @@ func (c *client) Scores(player string) ([]Score, error) {
|
||||||
return parseScores(resp), nil
|
return parseScores(resp), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type connection struct {
|
|
||||||
client *rcon.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *connection) Execute(command string) (string, error) {
|
|
||||||
packet, err := c.client.Execute(command)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return packet.Body, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parsePlayers(input string) []string {
|
func parsePlayers(input string) []string {
|
||||||
parts := strings.SplitAfterN(input, ":", 2)
|
parts := strings.SplitAfterN(input, ":", 2)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
|
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
// Package rcon implements the communication protocol for communicating
|
|
||||||
// with RCON servers. Tested and working with Valve game servers.
|
|
||||||
package rcon
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PacketPaddingSize uint8 = 2 // Size of Packet's padding.
|
|
||||||
PacketHeaderSize uint8 = 8 // Size of Packet's header.
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TerminationSequence = "\x00" // Null empty ASCII string suffix.
|
|
||||||
)
|
|
||||||
|
|
||||||
// Packet type constants.
|
|
||||||
// https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Packet_Type
|
|
||||||
const (
|
|
||||||
Exec int32 = 2
|
|
||||||
Auth int32 = 3
|
|
||||||
AuthResponse int32 = 2
|
|
||||||
ResponseValue int32 = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// Rcon package errors.
|
|
||||||
var (
|
|
||||||
ErrInvalidWrite = errors.New("failed to write the payload correctly to remote connection")
|
|
||||||
ErrInvalidRead = errors.New("failed to read the response correctly from remote connection")
|
|
||||||
ErrInvalidChallenge = errors.New("server failed to mirror request challenge")
|
|
||||||
ErrUnauthorizedRequest = errors.New("client not authorized to remote server")
|
|
||||||
ErrFailedAuthorization = errors.New("failed to authorize to the remote server")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Host string // The IP address of the remote server.
|
|
||||||
Port int // The Port the remote server's listening on.
|
|
||||||
Authorized bool // Has the client been authorized by the server?
|
|
||||||
Connection net.Conn // The TCP connection to the server.
|
|
||||||
}
|
|
||||||
|
|
||||||
type Header struct {
|
|
||||||
Size int32 // The size of the payload.
|
|
||||||
Challenge int32 // The challenge ths server should mirror.
|
|
||||||
Type int32 // The type of request being sent.
|
|
||||||
}
|
|
||||||
|
|
||||||
type Packet struct {
|
|
||||||
Header Header // Packet header.
|
|
||||||
Body string // Body of packet.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compile converts a packets header and body into its appropriate
|
|
||||||
// byte array payload, returning an error if the binary packages
|
|
||||||
// Write method fails to write the header bytes in their little
|
|
||||||
// endian byte order.
|
|
||||||
func (p Packet) Compile() (payload []byte, err error) {
|
|
||||||
var size = p.Header.Size
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
var padding [PacketPaddingSize]byte
|
|
||||||
|
|
||||||
if err = binary.Write(&buffer, binary.LittleEndian, &size); nil != err {
|
|
||||||
return nil, err
|
|
||||||
} else if err = binary.Write(&buffer, binary.LittleEndian, &p.Header.Challenge); nil != err {
|
|
||||||
return nil, err
|
|
||||||
} else if err = binary.Write(&buffer, binary.LittleEndian, &p.Header.Type); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.WriteString(p.Body)
|
|
||||||
buffer.Write(padding[:])
|
|
||||||
|
|
||||||
return buffer.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPacket returns a pointer to a new Packet type.
|
|
||||||
func NewPacket(challenge, typ int32, body string) (packet *Packet) {
|
|
||||||
size := int32(len([]byte(body)) + int(PacketHeaderSize+PacketPaddingSize))
|
|
||||||
return &Packet{Header{size, challenge, typ}, body}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authorize calls Send with the appropriate command type and the provided
|
|
||||||
// password. The response packet is returned if authorization is successful
|
|
||||||
// or a potential error.
|
|
||||||
func (c *Client) Authorize(password string) (response *Packet, err error) {
|
|
||||||
if response, err = c.Send(Auth, password); nil == err {
|
|
||||||
if response.Header.Type != AuthResponse {
|
|
||||||
return nil, ErrFailedAuthorization
|
|
||||||
}
|
|
||||||
c.Authorized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute calls Send with the appropriate command type and the provided
|
|
||||||
// command. The response packet is returned if the command executed successfully
|
|
||||||
// or a potential error.
|
|
||||||
func (c *Client) Execute(command string) (response *Packet, err error) {
|
|
||||||
return c.Send(Exec, command)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send accepts the commands type and its string to execute to the clients server,
|
|
||||||
// creating a packet with a random challenge id for the server to mirror,
|
|
||||||
// and compiling its payload bytes in the appropriate order. The response is
|
|
||||||
// decompiled from its bytes into a Packet type for return. An error is returned
|
|
||||||
// if send fails.
|
|
||||||
func (c *Client) Send(typ int32, command string) (*Packet, error) {
|
|
||||||
if typ != Auth && !c.Authorized {
|
|
||||||
return nil, ErrUnauthorizedRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a random challenge for the server to mirror in its response.
|
|
||||||
var challenge int32
|
|
||||||
if err := binary.Read(rand.Reader, binary.LittleEndian, &challenge); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the packet from the challenge, typ and command
|
|
||||||
// and compile it to its byte payload
|
|
||||||
packet := NewPacket(challenge, typ, command)
|
|
||||||
payload, err := packet.Compile()
|
|
||||||
if nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := c.Connection.Write(payload)
|
|
||||||
if nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n != len(payload) {
|
|
||||||
return nil, ErrInvalidWrite
|
|
||||||
}
|
|
||||||
|
|
||||||
var header Header
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Size); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Challenge); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Type); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if packet.Header.Type == Auth && header.Type == ResponseValue {
|
|
||||||
// Discard, empty SERVERDATA_RESPONSE_VALUE from authorization.
|
|
||||||
if _, err := c.Connection.Read(make([]byte, header.Size-int32(PacketHeaderSize))); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reread the packet header.
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Size); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Challenge); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := binary.Read(c.Connection, binary.LittleEndian, &header.Type); nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.Challenge != packet.Header.Challenge {
|
|
||||||
return nil, ErrInvalidChallenge
|
|
||||||
}
|
|
||||||
|
|
||||||
body := make([]byte, header.Size-int32(PacketHeaderSize))
|
|
||||||
n, err = c.Connection.Read(body)
|
|
||||||
for n < len(body) {
|
|
||||||
var nBytes int
|
|
||||||
nBytes, err = c.Connection.Read(body[n:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
n += nBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shouldn't this be moved up to the first read?
|
|
||||||
if nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if n != len(body) {
|
|
||||||
return nil, ErrInvalidRead
|
|
||||||
}
|
|
||||||
|
|
||||||
response := new(Packet)
|
|
||||||
response.Header = header
|
|
||||||
response.Body = strings.TrimRight(string(body), TerminationSequence)
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient creates a new Client type, creating the connection
|
|
||||||
// to the server specified by the host and port arguments. If
|
|
||||||
// the connection fails, an error is returned.
|
|
||||||
func NewClient(host string, port int) (client *Client, err error) {
|
|
||||||
client = new(Client)
|
|
||||||
client.Host = host
|
|
||||||
client.Port = port
|
|
||||||
client.Connection, err = net.Dial("tcp", fmt.Sprintf("%v:%v", client.Host, client.Port))
|
|
||||||
return client, err
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue