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:
- There are already existing applications, which are not good to change;
- you need / want to make an application that can work both with Redis and without it;
- 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
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.environ
displayed 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.