I recently had to intercept function calls to my C socket library in order to implement a prototype for a Multi-source Multipath network protocol. That is why in this post I want to give a simple introduction on how to use the
LD_PRELOAD environment variable to override shared C libraries. Further, I am going to show how to use
dlsym to make calls to the original C functions from within our hooks.
Simple socket call interception
Lets create a simple program that opens a socket.
The only thing this program does is creating a socket without binding it to an address. Compiling and running this program gives us:
$ gcc -Wall simple_client.c -o simple_client $ ./simple_client Socket successfully created $
Now we want to intercept the
socket() function to change the behavior on each call. For this, we first have to write a shared library that will override the
With the help of
LD_PRELOAD we can now let our
socket_hook.so library get loaded before the standard C libraries, meaning the first occurrence of the
socket() function is in our shared library. This results in the following:
$ gcc -Wall -fPIC -shared socket_hook.c -o socket_hook.so $ LD_PRELOAD=./socket_hook.so ./simple_client socket() call intercepted Error : Could not create socket $
Please note, that the Error message is due to the fact that we return -1 in our shared library, but our client code expects a non-negative return value. So far, we could override a standard
socket() call with our own function from our shared library.
Calling the original socket library from inside our hook
In a next step we also want to call the original
socket() function from our shared library. This will enable us to easily add additional functionalities to existing standard C libraries without changing or rewriting the original libraries. Also, when implemented properly, we could achieve total transparency to the calling layer. Lets change our previous socket hook.
<dlfcn.h> to find the next occurrence of the
socket() function and store the location in
o_socket. Hence, in our example
o_socket can from then on be used to call the original
_GNU_SOURCE has to be defined in order to be able to use
RTLD_NEXT. We now have to compile our shared library differently from before:
$ gcc -Wall -fPIC -shared socket_hook.c -o socket_hook.so -ldl
Using our new shared library gives us the following:
$ LD_PRELOAD=./socket_hook.so ./simple_client socket() call intercepted Socket successfully created $
That’s it! We have successfully intercepted the socket function and made a call to the original socket library. We could now simply add some additional behavior to the
socket() call. We could also easily intercept further functions such as
write(), to be able to build a new transparent layer on top of the socket library - ideal for writing quick networking prototypes.