Posts for: #Routing

NAT between identical networks using VRF

NAT between identical networks using VRF

Last week, Oskar Stenberg asked on Unix & Linux if it were possible to configure connectivity between two networks, both using the same address range, without involving network namespaces. That is, given this high level view of the network…

two networks with the same address range connected by a host named “middleman”

…can we set things up so that hosts on the “inner” network can communicate with hosts on the “outer” network using the range 192.168.3.0/24, and similarly for communication in the other direction?

[read more]

Packet, packet, who’s got the packet?

Packet, packet, who's got the packet?

In this question, August Vrubel has some C code that sets up a tun interface and then injects a packet, but the packet seemed to disappear into the ether. In this post, I’d like to take a slightly extended look at my answer because I think it’s a great opportunity for learning a bit more about performing network diagnostics.

The original code looked like this:



#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <netinet/in.h>
#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static int tunAlloc(void) {
  int fd;
  struct ifreq ifr = {.ifr_name = "tun0", .ifr_flags = IFF_TUN | IFF_NO_PI};

  fd = open("/dev/net/tun", O_RDWR);
  ioctl(fd, TUNSETIFF, (void *)&ifr);
  ioctl(fd, TUNSETOWNER, geteuid());
  return fd;
}

// this is a test
static void bringInterfaceUp(void) {
  int sock;
  struct sockaddr_in addr = {.sin_family = AF_INET};
  struct ifreq ifr = {.ifr_name = "tun0"};

  inet_aton("172.30.0.1", &addr.sin_addr);
  memcpy(&ifr.ifr_addr, &addr, sizeof(struct sockaddr));

  sock = socket(AF_INET, SOCK_DGRAM, 0);
  ioctl(sock, SIOCSIFADDR, &ifr);
  ioctl(sock, SIOCGIFFLAGS, &ifr);
  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
  ioctl(sock, SIOCSIFFLAGS, &ifr);
  close(sock);
}

static void emitPacket(int tap_fd) {
  unsigned char packet[] = {
      0x45, 0x00, 0x00, 0x3c, 0xd8, 0x6f, 0x40, 0x00, 0x3f, 0x06, 0x08, 0x91,
      172,  30,   0,    1,    192,  168,  255,  8,    0xa2, 0x9a, 0x27, 0x11,
      0x80, 0x0b, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0,
      0x89, 0xd8, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a,
      0x5b, 0x76, 0x5f, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07};

  write(tap_fd, packet, sizeof(packet));
}

int main() {
  int tap_fd;

  tap_fd = tunAlloc();
  bringInterfaceUp();
  emitPacket(tap_fd);
  close(tap_fd);

  return 0;
}



A problem with the original code is that it creates the interface, sends the packet, and tears down the interface with no delays, making it very difficult to inspect the interface configuration, perform packet captures, or otherwise figure out what’s going on.

[read more]