Display environment variables in Redis


    Redis is such a key-value view repository. Environment variables - resemble the same. But what if it is somehow combined?


    For lovers of Friday posts, uncomplicated hacking and strange desires - I ask for a cut


    There is an impressive list of client libraries for Redis in almost all programming languages. But what if:


    1. There are already existing applications, which are not good to change;
    2. you need / want to make an application that can work both with Redis and without it;
    3. simpler is better. Quite often, working with the cache is purely auxiliary in nature and brings unnecessary complexity to the application.

    In my case, the task arose after the creation of the next CGI-like service, which needed to maintain state. At the same time, the execution of this script can occur on different machines.


    Since it was about an hour at 2 am and it was already Friday for me, it was decided to relax and do something simple and interesting.


    Question and idea


    Is it possible to intercept system calls so that when writing to environment variables ( setenv), data is
    written to Redis, and when reading ( getenv), on the contrary, they are taken from the cache?


    Schematically looks like this:


    Application <-- [syscall]--> [Wrapper] <-- [GET/DEL/...] --> [Redis]

    Study


    Is it possible?


    Yes, there is a good article that describes how to make system call interceptors.


    Someone needs to initialize the connection ...


    There is a little popular opportunity to specify the functions of initialization (constructor) and finalization (destructor) in a shared library. We will be connected to them.


    Implementation


    I had to study the specifications of POSIX'a and Linux'a on this topic.


    Functions to be intercepted:


    • putenv
    • setenv
    • getenv
    • secure_getenv
    • clearenv
    • unsetenv

    The code is here .


    Dependencies


    • C11
    • hiredis 0.13

    Assembly


    There are no tricks - a typical CMake with Github


    Dependencies


    sudo apt install libhiredis-dev cmake build-essential

    Assembly


    git clone https://github.com/reddec/envredis.git
    cd envredis
    mkdir build && cd build
    cmake -DCMAKE_BUILD_TYPE=Release ../  && make

    Using


    An important point: some applications do not change environment variables, but only an internal array. In such applications, data from Redis will be retrieved, but not displayed back.


    A good option is python. According to the documentation , a change in is os.environdisplayed in the environment variables.


    Let's say Redis is already raised on the local machine.


    • Let's execute a variable output XYZ

    $ python -c 'import os; print("XYZ=" + os.environ.get("XYZ", ""))'
    # вывод будет такой:
    # XYZ=

    • Set a variable in Redis

    $ redis-cli SET XYZ "Hello world"
    # вывод будет такой:
    # OK

    • Run along with the interceptor

    LD_PRELOAD=/path/to/libenvredis.so python -c 'import os; print("XYZ=" + os.environ.get("XYZ", ""))'
    # вывод будет
    # XYZ=Hello world

    • Now let's try to set a variable

    LD_PRELOAD=/path/to/libenvredis.so python -c 'import os; os.environ["SAY"] = "Bye!"'

    • Check that it appears in Redis

    redis-cli GET SAY
    # вывод будет
    # "Bye!"

    PS


    The task took about two hours, taking into account the study of the subject area. More done for the fan than for real purposes.


    Nevertheless, someone may come in handy.



    Also popular now: