Abuse cURL to communicate with Redis
Asked Answered
B

9

65

I want to send a PING to Redis to check if the connection is working, now I could just install redis-cli, but I don't want to and curl is already there. So how can I abuse curl to do that? Basically I need to turn off what's send here:

> 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:'

I was able to get rid of the User-Agent altogether by adding -A "", but I can't find anything else for the rest. Any idea how I can do that?

By answered 20/10, 2015 at 17:31 Comment(1)
Redis is a TCP server so either use netcat or set up a HTTP interface like github.com/voidfiles/lark or github.com/nicolasff/webdis (if you really want to to do that!).Nainsook
E
92

When you want to use curl, you need REST over RESP, like webdis, tinywebdis or turbowebdis. See https://github.com/markuman/tinywebdis#turbowebdis-tinywebdis--cherrywebdis

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

Without a REST interface for redis, you can use netcat for example.

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

For password protected redis you can use netcat like this:

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

With netcat you have to build the RESP protocol by your self. See http://redis.io/topics/protocol

update 2018-01-09

I've build a powerfull bash function which pings the redis instance at any cost over tcp

    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)
    }

usage redis-ping localhost

Endearment answered 20/10, 2015 at 20:30 Comment(6)
The whole printf thing didn't do anything for me, but when I just ran the nc command and typed in the PING I got my PONG back.Sessile
Just echo PING | nc localhost 6379 worked fine for me.Glutenous
@LinusArver My script stops when using thatCurtain
@markus is there any workaround for password protected redis instance? because in here it's giving me -NOAUTH Authentication required.Richard
sh -c 'printf "AUTH <password> \r\nPING" | nc redis 6379'Rivard
This command would work too: nc <redis_host> 6379 <<<PINGPrevision
S
77

Not curl, but doesn't require a HTTP interface or nc (great for something like a container where you don't have nc installed)

exec 3<>/dev/tcp/127.0.0.1/6379 && echo -e "PING\r\n" >&3 && head -c 7 <&3

Should give you

+PONG

You can read more about what's going on from this fantastic article.

Springhead answered 29/8, 2016 at 20:38 Comment(5)
awesome! this just made my dayBeniamino
This worked for me, super helpful. Can you explain what's going on with those angle brackets? I'm not sure what to begin googling to find out what those are.Tokyo
@EricHu 3<> Is opening file descriptor 3 as read-write to the file /dev/tcp/127.0.0.1/6379 then >&3 redirects stdout from the echo to FD3 and <&3 redirects stdin from FD3 into head.Jentoft
Wow, this is fast! :o)Eliseelisee
See answer from @igorium which tacks onto this by adding the password often required to connect to your Redis instanceOralee
P
20

I needed to add a sleep to the nc provided by @Markus to get it to work from a remote system:

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

See Request/Response protocols and RTT: Redis Pipelining for details.

Priester answered 25/2, 2016 at 20:11 Comment(1)
On AWS EC2 to AWS ElastiCache Redis, the sleep 1 was necessary for me, although echo PING works equally well as the printfEspino
M
7

You can also use telnet localhost 6379 and if the connection is successful, type ping

To go out use quit

Mareld answered 28/11, 2019 at 8:43 Comment(0)
C
7

To only check if the host is up an responding I have used this:

echo "quit" | curl -v telnet://HOST:PORT

Result

*   Trying..
* TCP_NODELAY set
* Connected to ..
+OK
* Closing connection 0

Expanding on the the netcat solution, if you need to close the connection, this worked for me:

(printf "AUTH <password>\r\nPING\r\nQUIT\r\n";) | nc HOST PORT

Output

+OK
+PONG
+OK
Colan answered 21/2, 2022 at 8:54 Comment(0)
T
3

I had docker running on mac (Catalina). I ran a redis container using

docker run --name redis-mac -p 6379:6379 -d redis

Then I tested the connection using the computer's IP

echo PING | nc 192.168.1.100 6379

Recieved

+PONG

Using the IP from docker inspect redis-mac didn't work.

Actually I was testing Spring boot application having redis as cache provider. So I needed to test the connection . If your'e new to docker, here's a bit explanation of the first command : Run redis as a container , with host port 6379 and docker port 6379 , and name the container as redis-mac . Now docker daemon will create a container if the image is already available , else it will pull the image from docker hub and then run the container. You can do docker ps to check if the container is running.

Trunks answered 4/5, 2020 at 23:6 Comment(0)
S
3

In case Redis instance requires pass this might help:

$ 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

Replace {requirepass-string-from-redis-config} with string from 'requirepass' redis.conf

Scutcheon answered 22/6, 2020 at 12:34 Comment(0)
G
2

Elaborating on @Joel B's great answer. I needed this in a shell script in docker container, with no curl, no redis-cli and no nc... The REDIS I'm testing is the public redis-ha Helm chart for kubernetes from here: https://github.com/helm/charts/tree/master/stable/redis-ha

Variables to set are:

  • REDIS_HOST = host name (DNS address or IP) containing the redis master and sentinel (break this into separate hosts if they're separate, and change the ports if you need to - but in the helm chart the master/slave and sentinel are in the same pod and use the standard ports)

  • REDIS_STARTUP_TIMEOUT = maximum seconds to wait before giving up - default to 10 mins

  • REDIS_STARTUP_RETRY = seconds to wait between tests - default to 15 seconds

  • DEBUG = set this to true to echo the failed responses

The intricacies of the technique are described in the comments (I suggest you keep the comments in place to save your colleagues - and future self - from certain madness when trying to decipher the angle brackets)

# 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
Gwendolin answered 15/2, 2019 at 14:42 Comment(0)
A
0

Running the following, even if your Redis is on Docker, worked for me:

echo PING | nc 127.0.0.1 6379

Got the following response when OK:

+PONG
Arillode answered 25/2, 2023 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.