Правила форума Гаранты форума
Размещение рекламы AMX-X компилятор

Здравствуйте, гость Вход | Регистрация

Наши новости:

14-дек
24-апр
10-апр
11-апр

MyRCON

, управление сервером CS1.6,...
Статус пользователя Gecko
сообщение 12.5.2022, 22:26
Сообщение #1
Стаж: 7 лет 4 месяца

Сообщений: 1247
Благодарностей: 518
Полезность: 346

Написал простую но функциональную консольную утилиту для управления сервером через RCON.
Прикрепленное изображение
Запускать нужно в консоле:
На Linux
Код
./myrcon


На Windows
Код
C:\Program Files\myrcon\myrcon.exe


Прикрепленное изображение
Данная программа будет работать как на Linux так и на Windows.
В тандеме с sh-скриптом может мониторить сервер а sh-скрипт будет выполнять те или иные действия.
Нет необходимости вводить каждый раз rcon-пароль, программа собирается под конкретный сервер.
Ну а дальше
Код
ln -s  ${HOME}/myrcon /usr/bin/cs1


и достаточно ввести cs1 чтобы получить управление сервером по RCON.

сборка под Windows:
Код
GOOS=windows GOARCH=amd64 go build -o myrcon.exe


под Linux:
Код
go build myrcon.go


myrcon.go
Код
package main

import (
    "flag"
    "fmt"
    "net"
    "os"
    "os/exec"
    "regexp"
    "runtime"

    "github.com/common-nighthawk/go-figure"
)

// Адрес вашего сервера
var host   string = "localhost:27015"
// RCON пароль сервера
var passwd string = "123123"
// Команда по умолчанию
var command string = "status"

var app_name string = "MyRCON"

var clear map[string]func()

func init() {
    clear = make(map[string]func())
    clear["linux"] = func() {
        cmd := exec.Command("clear")
        cmd.Stdout = os.Stdout
        cmd.Run()
    }
    clear["windows"] = func() {
        cmd := exec.Command("cmd", "/c", "cls")
        cmd.Stdout = os.Stdout
        cmd.Run()
    }
}

func CallClear() {
    value, ok := clear[runtime.GOOS]
    if ok {
        value()
    } else {
        panic("Your platform is unsupported! I can't clear terminal screen :(")
    }
}

func main() {
    CallClear()
  
    myFigure := figure.NewColorFigure(app_name, "", "red", true)
    myFigure.Print()
    fmt.Println("\n")
    
    rconHost := flag.String("s", host, "server host")
    rconPassword := flag.String("r", passwd, "rcon password")
    rconCommand := flag.String("c", command, "remote command")
    flag.Usage = usageHelp
    flag.Parse()

    if len(os.Args) <= 0 {
        usageHelp()
        return
    }

    serverConnection, err := net.Dial("udp", *rconHost)
    if err != nil {
        fmt.Errorf("Error trying to connect to %v ==> %v", *rconHost, err.Error())
        return
    }
    defer serverConnection.Close()

    fmt.Println(sendRCON(serverConnection, *rconPassword, *rconCommand))

}

func prepareCommand(command string) []byte {
    var bytesSequence []byte
    bytesSequence = append(bytesSequence, []byte{255, 255, 255, 255}...)
    bytesSequence = append(bytesSequence, []byte(command)...)
    return bytesSequence
}

func sendRCON(serverConnection net.Conn, rconPassword string, rconCommand string) string {
    bufferSend := prepareCommand("challenge rcon\n")
    _, err := serverConnection.Write(bufferSend)
    if err != nil {
        fmt.Errorf("Error trying to request challenge to %v ==> %v",serverConnection.RemoteAddr().String(), err.Error())
        return "Error"
    }

    var bufferReceive [4000]byte
    _, err = serverConnection.Read(bufferReceive[:])
    if err != nil {
        fmt.Errorf("Error trying to receive challenge from %v ==> %v",
            serverConnection.RemoteAddr().String(), err.Error())
        return "Error"
    }

    challengeRCON := string(bufferReceive[:])
    challengeRCONSplitted := regexp.MustCompile("[^\\d]").Split(challengeRCON, -1)[:]
    challengeRCON = ""
    for i := 0; i < len(challengeRCONSplitted); i++ {
        challengeRCON += challengeRCONSplitted[i]
    }

    commandToSend := "rcon \"" + challengeRCON + "\" " + rconPassword + " " + rconCommand + "\n"

    bufferSend = prepareCommand(commandToSend)

    _, err = serverConnection.Write(bufferSend)
    if err != nil {
        fmt.Errorf("Error trying to send the command to %v ==> %v",
            serverConnection.RemoteAddr().String(), err.Error())
        return "Error"
    }

    _, err = serverConnection.Read(bufferReceive[:])
    if err != nil {
        fmt.Errorf("Error trying to get the command result from %v ==> %v",
            serverConnection.RemoteAddr().String(), err.Error())
        return "Error"
    }

    var stringResponse string
    if bufferReceive[0] == 255 && bufferReceive[1] == 255 &&
        bufferReceive[2] == 255 && bufferReceive[3] == 255 && bufferReceive[4] == 'l' {
        stringResponse = string(bufferReceive[5:])
    } else {
        stringResponse = string(bufferReceive[:])
    }
    return stringResponse
}


func usageHelp() {
    //flag.PrintDefaults()
    fmt.Println(" Default server: " + host + "\n")
    fmt.Println(" Usage: -s [server:port] -r [rcon_password] -c [command]\n")
    
}


Всё что нужно сделать, это отредактировать следующие переменные до сборки программы:
Код
// Адрес вашего сервера
var host   string = "localhost:27015"
// RCON пароль сервера
var passwd string = "123123"
// Команда по умолчанию
var command string = "status"


Если у кого будут проблемы со сборкой, напишу и опубликую скрипт для автоматической сборки и установки данной программы.

На тупые вопросы, отвечать в этой теме уже не буду.



Не отвечаю на ЛС.
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 4 раз
   Цитировать сообщение
Статус пользователя Gecko
сообщение 13.5.2022, 0:10
Сообщение #2
Стаж: 7 лет 4 месяца

Сообщений: 1247
Благодарностей: 518
Полезность: 346

А вот пример скрипта который можно повесть на cron либо как демона для мониторинга и выполнения тех или иных команд к примеру с интенсивностью 30 сек.

Код
#!/bin/bash

MyRCON="./myrcon"
RCON_LOG="/tmp/myrcon.log"
USER="Утилизатор"
STATS=$(cat ${RCON_LOG} | sed -n 10,10p | grep [0-9] | awk '{print $7}')
MAP="de_dust2"
MAP_C=$(${MyRCON} -c status | sed -n 12,12p | grep ${MAP})

# Если на сервер зашел игрок под ником Утилизатор, меняем карту на ${MAP} при условии что карта неактивна.
if [[ ${MAP_C} != ${MAP} ]]; then
    ${MyRCON} -c status | grep "${USER}" >/dev/null
        if [ $? -eq 0 ]; then
            ${MyRCON} -с amx_map ${MAP}
            exit
        fi
fi

# Если на сервере никого нет, то меняем карту на ${MAP} при условии что карта неактивна.
${MyRCON} -c stats > ${RCON_LOG}
if [[ ${MAP_C} != ${MAP} ]]; then
        if [[ ${STATS} == 0 ]]; then
            ${MyRCON} -с amx_map ${MAP}
            exit
        fi
fi

## В ЭТОМ СКРИПТЕ МОГУТ БЫТЬ МЕЛКИЕ ОШИБКИ И Я ЕГО НЕ ПРОВЕРЯЛ, НО РАБОТАТЬ ОН ПО ИДЕЕ ДОЛЖЕН!

Плюсы такого подхода в том, что это будет работать независимо от ваших сборок и серверов.
Плюс, это очень быстро и экономно в плане ресурсов, sh-скрипт не имеет границ в задачах в отличие от amxx-плагина.

Отредактировал: Gecko, - 13.5.2022, 1:20


Не отвечаю на ЛС.
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 1 раз
   + Цитировать сообщение
Статус пользователя Metal Messiah
сообщение 13.5.2022, 2:38
Сообщение #3


Иконка группы

Стаж: 13 лет

Сообщений: 2457
Благодарностей: 1482
Полезность: 770

HostGame.cf
На PHP подобное писал, только уже не использую.

То что дольше всего прожило (с 2013 по этот год) это когда в пачке серверов, объединенных в проект, при смене карты на одном сервере на остальных в чате выводится сообщение что на таком-то сервере карта теперь такая-то, чтобы игроки кому текущая карта не нравится могли перейти. Реализация - при смене карты отстук на PHP, PHP скрипт в цикле запускает Rcon команду, команду обрабатывает amxx плагин и выводит сообщение. Реализация не самая идеальная, но работает.


Полезные публикации - ссылки у меня в профиле. Ссылка на плагин против спама на сервере StopServerSpam там же.
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 1 раз
   + Цитировать сообщение
Статус пользователя Gecko
сообщение 13.5.2022, 7:47
Сообщение #4
Стаж: 7 лет 4 месяца

Сообщений: 1247
Благодарностей: 518
Полезность: 346

Metal Messiah, Главное ведь результат, хотя в первую очередь всегда лучше подумать о безопасности и быстродействии при написании любой программы. Я вот к примеру сейчас всё меньше стараюсь писать на php, даже чтобы к примеру собрать банальную карту сайта я лучше запущу отдельный сервис на *.go. Вообще заметил сейчас в тренде переписывать backend (где это возможно) с php на golang.
Хотя, микрозадачи на php имеют место быть...

Про безопасность
Конкретно в данном примере программа абсолютно безопасная и быстрая с открытым исходным кодом, rcon-пароль для администрируемого сервера вшит в программу при переводе исходного кода в бинарный.
Единственное, если есть возможность используйте её на сервере а доступ к rcon заблокируйте по ip.

Код
MyIP=192.168.0.8
iptables -I INPUT ! -s  ${MyIP}  -p udp -m multiport --ports 27015:27019 -m string --string "rcon" --algo bm --to 65535 -j DROP


Если вы используете стороннее приложение для управлением сервером которое вы не собирали лично, типа HLSW (она вообще без исходников) или софтина на андроиде, то в 99% ваш RCON уже слит!!!

По поводу скрипта во втором посте, он работает идеально, я его проверил, более того, разного рода боты не будут портить значение онлайна. По этому скрипт считывает онлайн из реальных подключений игроков.

Правда мелкие ошибки как всегда оказались, без этого никуда.

rcon.sh
Код
#!/bin/bash

# set -e

MyRCON="./myrcon"
RCON_LOG="/tmp/myrcon.log"
USER="Утилизатор"
MAP="de_dust2"
MAP_C=$(${MyRCON} -c status | sed -n 12,12p | grep ${MAP})

if [[ ! -f ${RCON_LOG} ]]; then
touch ${RCON_LOG}
fi

# Если на сервер зашел игрок под ником Утилизатор, меняем карту на ${MAP} при условии что карта неактивна.
if [[ ${MAP_C} != ${MAP} ]]; then
    ${MyRCON} -c status | grep "${USER}" >/dev/null
        if [ $? -eq 0 ]; then
            ${MyRCON} -с amx_map ${MAP}
            exit
        fi
fi

# Если на сервере никого нет, то меняем карту на ${MAP} при условии что карта неактивна.
${MyRCON} -c stats > ${RCON_LOG}
STATS=$(cat ${RCON_LOG} | sed -n 10,10p | grep [0-9] | awk '{print $7}')

if [[ ${MAP_C} != ${MAP} ]]; then
        if [[ ${STATS} == 0 ]]; then
            ${MyRCON} -с amx_map ${MAP}
            exit
        fi
fi


Отредактировал: Gecko, - 13.5.2022, 13:13


Не отвечаю на ЛС.
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
  Ответить в данную темуНачать новую тему
 
0 пользователей и 1 гостей читают эту тему: