Linux Network Stack Flow

Tuxology team June 16th, 2008

A wonderful article, describing the control flow and the associated data types of the Linux networking stack of kernel 2.6, written by Arnout Vandecappelle of Mind, is available via the kind folks at the Linux Foundation.

Accompanying the article itself, an elaborate graphic schema of the network stack and data type, is also included. Looks like it will make a great cubicle poster!

The Tuxology Team

Forcing connections through a specific interface

Gilad Ben-Yossef May 15th, 2008

It can sometime be very useful to force an application to force to use a specific network interface for routing traffic, the regular routing tables not withstanding.

An example for such cases is where an embedded Linux system has a management network interface and a separate regular network interface where regular traffic should go:

So long as the two interfaces use two different IP addresses from non overlapping network it is very easy - simply bind the management application socket to the management IP and let the routing table do the rest.

What to do, however, if product definition calls for supporting two different and separate, default gateway settings for management and media traffic? Although we can assign multiple default gateway routing table entries, how to make sure the management applications use one and all other traffic use another?

This is where the SO_BINDTODEVICE socket option comes to our rescue. We will install two default gateway entries: a normal one for the media traffic and another one for the management traffic, for which we will define a high metric so it will normally will not be used.

Then, we will set the SO_BINDTODEVICE socket option on sockets opened in management application, thus forcing the Linux networking stack to disregard any routing table entries not going through the specific device, but only for those specific sockets.

It looks something like this:

#include <sys/socket.h>
#include <net/if.h>
struct ifreq interface;
struct socket sock;
/* Management net interface name */
#define IFNAME "eth3"
 
/* Acquire socket here ... */
 
strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
  IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
  (char *)&interface, sizeof(interface))  < 0) {
       perror("SO_BINDTODEVICE failed");
      /* Deal with error... */
}

But wait! this is all well and good when we have the management application source code. This however is not always the case. Fear not! this too can be dealt with by hijacking the socket library call:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#define __USE_GNU // Get RTLD_NEXT definition
#include <dlfcn.h>
 
/* Management interface */
#define IFNAME "eth3"
 
int socket(int domain, int type, int protocol) {
 
int (*origsock)(int domain, int type, int protocol);
char * error;
int sock;
 
origsock = dlsym(RTLD_NEXT, "socket");
if ((error = dlerror()) != NULL) {
fprintf (stderr, "%s\n", error);
exit(1);
}
 
sock = origsock(domain, type, protocol);
if(sock != -1) {
  struct ifreq interface;
  strncpy(interface.ifr_ifrn.ifrn_name, IFNAME, \
  IFNAMSIZ);
  if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, \
    (char *)&interface, sizeof(interface)) < 0) {
      perror("sendpacket: setting SO_BINDTODEVICE");
      exit(1);
   }
}
 
return sock;
}

Compile this small library with (or create a proper Makefile)

$ gcc sendto.c -fPIC -o sendto.so -ldl -shared

To use:

LD_PRELOAD=sendto.so ./management_app

This post originally appeared in the Codefidence Technoblog