如何在bash中存储32位Little-Endian Signed Integer?

时间:2018-10-05 13:36:53

标签: linux bash minecraft

(*在以下文章中,所有IP,端口和密码均已更改。很抱歉,本文的格式,编辑者似乎并不喜欢换行。)

问题:如何将整数存储为带符号的32位小字节序?

背景:我试图使用RCon在bash中连接到Minecraft服务器。到目前为止,服务器显示已接收到连接,但无法正确格式化数据包。我可以使用mcrcon连接到服务器,并在Wireshark中查看数据包,但是当我尝试使用bash脚本时,数据包长度,requestid和类型值看起来不正确。

以下是我的一些资料来源,难以解决的数据和代码,可能有助于回答问题。

来源:https://wiki.vg/RCON

https://developer.valvesoftware.com/wiki/Source_RCON_Protocol

的实现

服务器控制台:

  

[22:24:09 WARN]:跟不上!服务器过载了吗?运行3190毫秒或落后63刻

     

[22:24:23 INFO]:Rcon连接来自:/164.256.8.10

     

[22:24:34 WARN]:跟不上!服务器过载了吗?向后运行9961毫秒或199个滴答声

     

[22:24:55 WARN]:跟不上!服务器过载了吗?运行2006毫秒或落后40刻

     

[22:25:12 INFO]:Rcon连接来自:/164.256.8.10

Wireshark:(mcrcon数据) mcrcon packets

代码:

#!/bin/bash

# Length    int     Length of remainder of packet
# Request ID    int     Client-generated ID
# Type  int     3 for login, 2 to run a command, 0 for a multi-packet response
# Payload   byte[]  ASCII text
# 2-byte pad    byte, byte  Two null bytes 

# Connection details
RCON_HEADER=$(echo -e "\xff\xff\xff\xff")
HOST="192.168.0.173"
PORT=12345  
LENGTH=0 # Length of packet
REQUESTID=$RANDOM
PASSWORD="$1"
RES=0
COM=2
AUTH=3
NULL="\0"
COMMAND=${@:2}
echo "command: $COMMAND"



## Packet Format as per docs
#Packet Size in Bytes
#Request ID any int
#Type as above
#Body null terminated ascii string
#Empty string null terminated

build_packet()
{
    local TYPE="$1";
    $([ "$TYPE" == "$AUTH" ]) && local BODY="$PASSWORD" || local BODY=$COMMAND;
    local DATA="$REQUESTID$TYPE$BODY";    
    local LENGTH=${#DATA};
    local PACKET="$LENGTH$DATA";    
    echo $PACKET;
}



send()
{
    #local PACKET="$1"
    echo "sending: $PACKET"
    printf "$PACKET%s\0%s\0" >&5 &
}

read ()
{
    LENGTH="$1"
    RETURN=`dd bs=$1 count=1 <&5 2> /dev/null`
}


echo "trying to open socket"
# try to connect
if ! exec 5<> /dev/tcp/$HOST/$PORT; then
  echo "`basename $0`: unable to connect to $HOST:$PORT"
  exit 1
fi
echo "socket is open"


PACKET=$(build_packet $AUTH $PASSWORD);
echo "Command: $COMMAND"
echo "Packet: $PACKET"

send $PACKET

read 7
echo "RETURN: $RETURN"


PACKET=$(build_packet $COM $COMMAND);
echo "Command: $COMMAND"
echo "Packet: $PACKET"


send $PACKET

read 7
echo "RETURN: $RETURN"

参考代码:https://blog.chris007.de/using-bash-for-network-socket-operation/

2 个答案:

答案 0 :(得分:1)

解决方案是如下进行十六进制编码和解码:

build_packet()
{
    local TYPE="$1"
    local BODY=""
    $([ "$TYPE" == "$AUTH" ]) && BODY="$PASSWORD" || BODY="$COMMAND"

    # Add null chars "\0" and hex encode to preserve them "xxd -p".
    # David C Rankin also mentioned, you could possibly printf them in using flags.
    local DATA=`echo -ne "$ID\0\0\0\0$TYPE\0\0\0$BODY\0\0" | xxd -p | tr -d '\n'`

    local LEN="${#DATA}"
    LEN=$((LEN / 2))
    LEN="$(asc $LEN)"  
    LEN=`echo -ne "$LEN\0\0\0" | xxd -p | tr -d '\n'`
    local PACKET="$LEN$DATA"    
    echo $PACKET
}

注意:#(asc)是将LEN转换为ascii char的自定义函数。我不知道为什么数据包长度必须是ascii char,但是类型(也是整数)却没有。也许其他人可以回答。

在传输时,十六进制被解码为“ echo -ne“ $ PACKET” | xxd -r -p>&5&“。

答案 1 :(得分:0)

对于 class Car(db.Entity): _table_ = ('A', 'car') id_car = PrimaryKey(int, auto=True) name = Required(str, 45) driver = Set('Driver', table=('A', 'car_driver')) # like this class Driver(db.Entity): _table_ = ('A', 'driver') id_driver = PrimaryKey(int, auto=True) name = Required(str, 45) surname = Required(str, 45) car = Set(Car) ,有一种的方式。但是由于无法存储空字符(build_pkt)是bash字符串,因此必须使用printf开发字符串:

\0

由于我的declare -i REQUESTID=1 build_pkt() { local pkt='' len case $1 in AUTH ) local TYPE=3 BODY="$PASSWORD" ;; CMD ) local TYPE=2 BODY="${@:2}" ;; * ) return 1;; esac addtopkt() { local i v c printf -v v "%08x" $1 for i in {3..0..-1};do printf -v c %03o 0x${v:2*i:2} pkt+=\\$c done } len=$(( ${#BODY} >0 ? ${#BODY}+10 : 10 )) addtopkt $len REQUESTID+=1 addtopkt $REQUESTID addtopkt $TYPE pkt+="$BODY\0\0" printf "$pkt" } 版本无法识别bash,为此,我使用/dev/tcp/(1个派生到后台任务):

netcat

然后使用一个快速的脏脚本来转储答案:

TMPFIFO=/tmp/.mcrcon-$$
mkfifo $TMPFIFO
exec 8> >(exec stdbuf -i 0 -o 0 nc $HOST $PORT >$TMPFIFO 2>&1)
exec 9<$TMPFIFO
rm $TMPFIFO

走吧:

readrawanswer() {
     local foo LANG=C
     while IFS= read -u 9 -t .01 -r foo ;do
         printf "%q\n" "$foo"
     done
}

在连接到 readrawanswer build_pkt AUTH >&8 readrawanswer build_pkt CMD "help" >&8 readrawanswer 服务器的主机上,将打印:

spigot

然后我可以:

$'\272\001\'\302\247e--------- \302\247fHelp: Index (1/10) \302\247e--------------------'
$'\302\2477Use /help [n] to get page n of help.'
$'\302\2476Aliases: \302\247fLists command aliases'
$'\302\2476Bukkit: \302\247fAll commands for Bukkit'
$'\302\2476Minecraft: \302\247fAll commands for Minecraft'
$'\302\2476/advancement: \302\247fA Mojang provided command.'
$'\302\2476/ban: \302\247fA Mojang provided command.'
$'\302\2476/ban-ip: \302\247fA Mojang provided command.'
$'\302\2476/banlist: \302\247fA Mojang provided command.'
$'\302\2476/bossbar: \302\247fA Mojang provided command.'

最后:

build_pkt >&8 CMD "help 2" && readrawanswer

$'\307\001)\302\247e--------- \302\247fHelp: Index (2/10) \302\247e--------------------'
$'\302\2476/clear: \302\247fA Mojang provided command.'
$'\302\2476/clone: \302\247fA Mojang provided command.'
$'\302\2476/data: \302\247fA Mojang provided command.'
$'\302\2476/datapack: \302\247fA Mojang provided command.'
$'\302\2476/debug: \302\247fA Mojang provided command.'
$'\302\2476/defaultgamemode: \302\247fA Mojang provided command.'
$'\302\2476/deop: \302\247fA Mojang provided command.'
$'\302\2476/difficulty: \302\247fA Mojang provided command.'
$'\302\2476/effect: \302\247fA Mojang provided command.'

在我的主机上,这将呈现:

for i in {1..10};do
    build_pkt >&8 CMD "help $i" && readrawanswer
done |
    sed 's/^.*[0-9]\/\([a-z:-]\+\): .*$/\1/p;d' |
    xargs |
    fold -s

为了娱乐:

advancement ban ban-ip banlist bossbar clear clone data datapack debug 
defaultgamemode deop difficulty effect enchant execute experience fill 
forceload function gamemode gamerule give help kick kill list locate loot me 
minecraft:help minecraft:reload msg op pardon pardon-ip particle playsound 
plugins publish recipe reload replaceitem restart save-all save-off save-on say 
schedule scoreboard seed setblock setidletimeout setworldspawn spawnpoint 
spigot spreadplayers stop stopsound summon tag team teammsg teleport tell 
tellraw time timings title tm tp tps trigger version w weather whitelist 
worldborder xp

那么mcrcmd() { build_pkt CMD "$@" 1>&8 && readrawanswer } mcrcmds=($( for i in {1..10};do build_pkt >&8 CMD "help $i" && readrawanswer done | sed 's/^.*[0-9]\/\([a-z:-]\+\): .*$/\1/p;d' )) complete -W "${mcrcmds[*]}" mcrcmd 现在是具有 bash补全;-)

的函数

感谢链接:

  

Source RCON Protocol

此外,转到Classic server protocolmcrcmd转换为终端颜色... enter image description here

关闭$'\302\247'[0-f]

nc

但是,如果没有,请考虑在中这样做