Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the most accurate way to test the networking code on Linux?

I want to cover my code with unit-tests. That's a good thing. But I have a problem - I have a networking code. The code does resolve IPv4 and IPv6 addresses from hostnames, binds to interfaces, listens, connects, etc.

I assume that there exists some C/C++ test framework that can be deployed on almost any workstation or some programming technique that allows me to:

  • set up and tear down custom network interfaces with IPv4 and IPv6 addresses
  • emulate different jamming behavior, like losing packets, timeouting, connection dropping, etc.
  • bind hostnames to interfaces and resolve them.

The main goal is not to interact or mess with a real network interfaces on machine.


What can you advise?

like image 711
abyss.7 Avatar asked Dec 03 '14 18:12

abyss.7


People also ask

What is the command to check network in Linux?

ifconfig. The ifconfig command was/is a staple in many sysadmin's tool belt for configuring and troubleshooting networks.

How do I find network details in Linux?

netstat command – It is used to display network connections, routing tables, interface statistics, masquerade connections, and multicast memberships. ifconfig command – It is used to display or configure a network interface. nmcli command – A command to show or configure a network interface on Linux.


1 Answers

On ELF systems you can use elf_hook to temporarily replace the real versions of various functions with your own mocked versions.

It allows you to redirect calls to any function from within a shared library to your own arbitrary function.

  • Create a shared library containing the code under test
  • In your test load the shared library dynamically (dlopen)
  • Redirect the symbols you want to mock to your test functions (elf_hook)
  • Now any calls to the real function within the library (the code under test) will be redirected to your mocked function

A plus for this method is that you can still call the original function when required.

  • If for some tests you want to have the call to, eg getaddrinfo, succeed, you can call the system version.
  • In other tests you can use your own mocked version, eg mocked_getaddrinfo, and have it return whatever you want.
  • You can create as many mocked_getaddrinfo functions as you want, to test multiple scenarios

elf_hook has the following signature:

void* elf_hook(char const* library_filename, 
               void const* library_address, 
               char const* function_name, 
               void const* substitution_address);

You would use it like this:

#include <dlfcn.h>
#include "elf_hook.h"

void do_stuff(); // from the library under test (do_stuff calls getaddrinfo)

// our mocked function which will alter the behaviour inside do_stuff()
int mocked_getaddrinfo(const char* node, 
                       const char* service,
                       const struct addrinfo* hints,
                       struct addrinfo** res)
{
    // return a broken value to test a getaddrinfo failure
    return 42;
}

// another version which actually calls the real function
int real_getaddrinfo(const char* node, 
                     const char* service,
                     const struct addrinfo* hints,
                     struct addrinfo** res)
{
    // the real getaddrinfo is available to us here, we only replace it in the shared lib
    return getaddrinfo(node, service, hints, res);
}

int main()
{
    const char* lib_path = "path/to/library/under/test.so";

    // load the library under test
    void* lib_handle = dlopen(lib_path, RTLD_LAZY);

    // test 1: getraddrinfo is broken
    //--------------------------------
    // replace getaddrinfo with our 'mocked_getaddrinfo' version
    elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle), 
             "getaddrinfo", mocked_getaddrinfo);

    // call a function in the library under test where getaddrinfo fails
    do_stuff();

    // test 2: getraddrinfo is the system version
    //--------------------------------
    // replace getaddrinfo with our 'real_getaddrinfo' version 
    elf_hook(lib_path, LIBRARY_ADDRESS_BY_HANDLE(lib_handle), 
             "getaddrinfo", real_getaddrinfo);

    // call the same function in the library, now getaddrinfo works
    do_stuff();

    dlclose(lib_handle);
    return 0;
}

Any call to getaddrinfo from within the library under test will now call mocked_getaddrinfo.

A comprehensive article by the elf_hook author, Anthony Shoumikhin, is here.

like image 114
Steve Lorimer Avatar answered Sep 23 '22 18:09

Steve Lorimer