【问题标题】:Abuse cURL to communicate with Redis滥用 cURL 与 Redis 通信
【发布时间】:2016-01-19 11:52:05
【问题描述】:

我想向 Redis 发送 PING 以检查连接是否正常,现在我可以安装 redis-cli,但我不想安装 curl 已经在那里。那么我该如何滥用curl 来做到这一点呢?基本上我需要关闭这里发送的内容:

> GET / HTTP/1.1
> User-Agent: curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3
> Host: localhost:6379
> Accept: */*
> 
-ERR wrong number of arguments for 'get' command
-ERR unknown command 'User-Agent:'
-ERR unknown command 'Host:'
-ERR unknown command 'Accept:'

我可以通过添加-A "" 完全摆脱User-Agent,但我找不到其他任何东西。知道我该怎么做吗?

【问题讨论】:

标签: linux http curl tcp redis


【解决方案1】:

当你想使用 curl 时,你需要 REST over RESP,比如 webdis、tinywebdis 或 turbowebdis。见https://github.com/markuman/tinywebdis#turbowebdis-tinywebdis--cherrywebdis

$ curl -w '\n' http://127.0.0.1:8888/ping
{"ping":"PONG"}

如果没有redis的REST接口,可以使用netcat为例。

$ (printf "PING\r\n";) | nc <redis-host> 6379 
+PONG

对于受密码保护的 redis,您可以像这样使用 netcat:

$ (printf "AUTH <password>\r\n";) | nc <redis-host> 6379
+PONG

使用 netcat,您必须自己构建 RESP 协议。见http://redis.io/topics/protocol

更新 2018-01-09

我已经构建了一个强大的 bash 函数,它可以通过 tcp 不惜一切代价 ping redis 实例

    function redis-ping() {
            # ping a redis server at any cost
            redis-cli -h $1 ping 2>/dev/null || \
                    echo $((printf "PING\r\n";) | nc $1 6379 2>/dev/null || \
                    exec 3<>/dev/tcp/$1/6379 && echo -e "PING\r\n" >&3 && head -c 7 <&3)
    }

用法redis-ping localhost

【讨论】:

  • 整个 printf 对我没有任何帮助,但是当我运行 nc 命令并输入 PING 时,我的 PONG 恢复了。
  • 只是 echo PING | nc localhost 6379 对我来说很好。
  • @LinusArver 我的脚本在使用时停止
  • @markus 是否有密码保护的 redis 实例的解决方法?因为在这里它给了我-NOAUTH Authentication required.
  • sh -c 'printf "AUTH &lt;password&gt; \r\nPING" | nc redis 6379'
【解决方案2】:

我需要在@Markus 提供的 nc 中添加一个睡眠功能,以使其能够从远程系统工作:

(printf "PING\r\n"; sleep 1) | nc remote.redis.hostname 6379

详情请见Request/Response protocols and RTT: Redis Pipelining

【讨论】:

  • 在 AWS EC2 到 AWS ElastiCache Redis 上,sleep 1 对我来说是必需的,尽管 echo PINGprintf 工作得一样好
【解决方案3】:

不是 curl,但不需要 HTTP 接口或 nc(非常适合您没有安装 nc 的容器之类的东西)

exec 3&lt;&gt;/dev/tcp/127.0.0.1/6379 &amp;&amp; echo -e "PING\r\n" &gt;&amp;3 &amp;&amp; head -c 7 &lt;&amp;3

应该给你

+PONG

您可以从this fantastic article 了解更多关于正在发生的事情。

【讨论】:

  • 太棒了!这让我很开心
  • 这对我有用,非常有帮助。你能解释一下这些尖括号是怎么回事吗?我不知道该从什么开始谷歌搜索以找出那些是什么。
  • @EricHu 3&lt;&gt; 正在打开文件描述符 3 作为对文件 /dev/tcp/127.0.0.1/6379 的读写操作,然后 &gt;&amp;3 将 stdout 从 echo 重定向到 FD3,&lt;&amp;3 将 stdin 从 FD3 重定向到 head。
  • 哇,这速度真快! :o)
【解决方案4】:

详细阐述@Joel B 的出色答案。我需要在 docker 容器中的 shell 脚本中使用它,没有 curl、redis-cli 和 nc... 我正在测试的 REDIS 是来自这里的 kubernetes 的公共 redis-ha Helm 图表:https://github.com/helm/charts/tree/master/stable/redis-ha

要设置的变量是:

  • REDIS_HOST = 包含 redis master 和 sentinel 的主机名(DNS 地址或 IP) (如果它们是分开的,则将其分成单独的主机,并更改端口 如果您需要 - 但在掌舵图中,主/从和哨兵是 在同一个 pod 中并使用标准端口)

  • REDIS_STARTUP_TIMEOUT = 放弃前等待的最大秒数 - 默认为 10 分钟

  • REDIS_STARTUP_RETRY = 测试之间等待的秒数 - 默认为 15 秒

  • DEBUG = 将此设置为 true 以回显失败的响应

在 cmets 中描述了该技术的复杂性(我建议您保留 cmets 以使您的同事和未来的自己在尝试破译尖括号时免于疯狂)

# wait for 10 mins and check again every 15 seconds
let n=${REDIS_STARTUP_TIMEOUT:-600}
let m=${REDIS_STARTUP_RETRY:-15}
ready=false
while ((n > 0)); do
    # These scripts are the best way to check if redis is running without having access to nc, curl or redis-cli
    # They write a "PING" to the redis and sentinel ports on the hostname "dc-ecm-redis-ha"
    # and look for a "PONG+" in return.
    #
    # Detailed explanation:
    # -  3<>/dev/tcp... opens a file handle identified as #3 for input and output on the tcp host and port
    #    The host $REDIS_HOST is defined in DNS by the Kubernetes _service_, and the port is for redis or sentinel
    #    (Uses linux's low-level network-as-filesystem support. Think of it as a sort of poor-man's telnet)
    # -  "PING" followed by carriage-return is sent to the port by redirecting to the handle with >&3
    # -  The response from the port is sent to the head command with <&3
    # -  The first 5 bytes of the response are captured with -c 5. This removes the linebreak (\r) from the response
    # -  Standard shell $() around the whole thing stores the result in a variable (master or sentinel)
    # -  When Redis is NOT ready, the result is generally a failure in the exec or some other error, which goes
    #    to stderr, so we wrap it in  { } > 2>&1 to capture that error in the variable too.
    # -  Success is measured by "+PONG" being in the variable
    # -  If you set the variable DEBUG to "true" (or "TRUE" -> the {,,} lower-cases it) the failed responses are echoed
    # -  (There are easier ways to do this if you have redis-cli installed or nc, but typically you don't on a docker container)
    # -  The whole thing waits n seconds for Redis to be ready, checking every m seconds
    #
    master=$( { exec 3<>/dev/tcp/${REDIS_HOST}/6379 && echo -e "PING\r\n" >&3 && head -c 5 <&3; } 2>&1 )
    sentinel=$( { exec 3<>/dev/tcp/${REDIS_HOST}/26379 && echo -e "PING\r\n" >&3 && head -c 5 <&3; } 2>&1 )
    if [ "$sentinel" = "+PONG" -a "$master" = "+PONG" ]; then ready=true;
       break;
   else echo "$(date) : Waiting $n more seconds for Redis master and sentinel to respond to PING"
        [[ "${DEBUG,,}" = "true" ]] && echo "master response was [$master]";
        [[ "${DEBUG,,}" = "true" ]] && echo "sentinel response was [$sentinel]";
        sleep $m
        ((n-=m))
    fi
done

if [ "$ready" = true ]
    then echo "$(date) : REDIS is ready"
    # do something when Redis is ready
else
    echo "$(date) : ERROR: REDIS is still not ready. Giving up waiting"
    # do something when Redis fails
fi

【讨论】:

    【解决方案5】:

    您也可以使用telnet localhost 6379,如果连接成功,请输入ping

    外出使用quit

    【讨论】:

      【解决方案6】:

      我让 docker 在 mac (Catalina) 上运行。 我使用

      运行了一个 redis 容器
      docker run --name redis-mac -p 6379:6379 -d redis
      

      然后我用电脑的IP测试了连接

      echo PING | nc 192.168.1.100 6379
      

      收到

      +PONG
      

      使用来自docker inspect redis-mac 的 IP 不起作用。

      实际上,我正在测试使用 redis 作为缓存提供程序的 Spring Boot 应用程序。所以我需要测试连接。 如果你是 docker 新手,这里是对第一个命令的一些解释: 将 redis 作为容器运行,主机端口 6379 和 docker 端口 6379 ,并将容器命名为 redis-mac 。现在,如果镜像已经可用,docker daemon 将创建一个容器,否则它将从 docker hub 拉取镜像,然后运行容器。 您可以通过docker ps 来检查容器是否正在运行。

      【讨论】:

        【解决方案7】:

        如果 Redis 实例需要通过,这可能会有所帮助:

        $ exec 3<>/dev/tcp/127.0.0.1/6379 && echo -e "AUTH {requirepass-string-from-redis-config} \r\n PING\r\n" >&3 && head -c 12 <&3
        +OK
        +PONG
        

        将 {requirepass-string-from-redis-config} 替换为 'requirepass' redis.conf 中的字符串

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-05-08
          • 2015-11-12
          • 2014-02-28
          • 2020-10-04
          • 1970-01-01
          • 2016-09-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多