Last active
March 22, 2019 07:38
-
-
Save thediveo/d0834baacc92a7ab25300fd8c7468b61 to your computer and use it in GitHub Desktop.
TAP client supporting specifying TAP ifname and TAP client network namespace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* modified from: https://github.com/a34729t/exp/blob/master/tunclient.c */ | |
#define _GNU_SOURCE | |
#include <sched.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <net/if.h> | |
#include <linux/if_tun.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <sys/ioctl.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <arpa/inet.h> | |
#include <sys/select.h> | |
#include <sys/time.h> | |
#include <errno.h> | |
#include <stdarg.h> | |
int tun_alloc(char *dev, int flags) { | |
struct ifreq ifr; | |
int fd, err; | |
char *clonedev = "/dev/net/tun"; | |
/* Arguments taken by the function: | |
* | |
* char *dev: the name of an interface (or '\0'). MUST have enough | |
* space to hold the interface name if '\0' is passed | |
* int flags: interface flags (eg, IFF_TUN etc.) | |
*/ | |
/* open the clone device */ | |
if( (fd = open(clonedev, O_RDWR)) < 0 ) { | |
return fd; | |
} | |
/* preparation of the struct ifr, of type "struct ifreq" */ | |
memset(&ifr, 0, sizeof(ifr)); | |
ifr.ifr_flags = flags; /* IFF_TUN or IFF_TAP, plus maybe IFF_NO_PI */ | |
if (*dev) { | |
/* if a device name was specified, put it in the structure; otherwise, | |
* the kernel will try to allocate the "next" device of the | |
* specified type */ | |
strncpy(ifr.ifr_name, dev, IFNAMSIZ); | |
} | |
/* try to create the device */ | |
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) { | |
close(fd); | |
return err; | |
} | |
/* if the operation was successful, write back the name of the | |
* interface to the variable "dev", so the caller can know | |
* it. Note that the caller MUST reserve space in *dev (see calling | |
* code below) */ | |
strcpy(dev, ifr.ifr_name); | |
/* this is the special file descriptor that the caller will use to talk | |
* with the virtual interface */ | |
return fd; | |
} | |
int main(int argc, char *argv[]) { | |
char tun_name[IFNAMSIZ]; | |
int tun_fd, nread; | |
char buffer[2000]; | |
/* Connect to the device */ | |
if (argc < 2) { | |
strcpy(tun_name, ""); | |
} else { | |
strcpy(tun_name, argv[1]); | |
} | |
tun_fd = tun_alloc(tun_name, IFF_TAP | IFF_NO_PI); /* tun interface */ | |
if(argc >= 3) { | |
int netnsfd; | |
netnsfd = open(argv[2], O_RDONLY); | |
if(netnsfd < 0){ | |
perror("Network namespace reference"); | |
exit(1); | |
} | |
if(setns(netnsfd, CLONE_NEWNET) < 0){ | |
perror("Switching network namespace"); | |
exit(1); | |
} | |
printf("Switched into network namespace %s\n", argv[2]); | |
} | |
if(tun_fd < 0){ | |
perror("Allocating interface"); | |
exit(1); | |
} | |
printf("Reading from interface %s\n", tun_name); | |
/* Now read data coming from the kernel */ | |
while(1) { | |
/* Note that "buffer" should be at least the MTU size of the interface, eg 1500 bytes */ | |
nread = read(tun_fd,buffer,sizeof(buffer)); | |
if(nread < 0) { | |
perror("Reading from interface"); | |
close(tun_fd); | |
exit(1); | |
} | |
/* Do whatever with the data */ | |
printf("Read %d bytes from device %s\n", nread, tun_name); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# remove stale tapclient(s) | |
for PID in $(ps a|grep "tapclient"|grep -v "grep"|awk '{print $1}'); do | |
echo "Killing tapclient $PID" | |
kill $PID | |
done | |
# remove stale netns | |
for NETNS in $(findmnt -n -t nsfs|awk '/\/run\/netns\//{n=split($1,P,"/");print P[n]}'|sort -u); do | |
echo "Removing old netns $NETNS" | |
ip netns del $NETNS | |
done | |
# set up netns | |
ip netns add ahh | |
ip netns add beh | |
# start tapclient, create TAP, move TAP to ahh, switch tapclient to beh | |
./tapclient tap123 /run/netns/beh >/dev/null & | |
export TAPPID=$! | |
ip link set tap123 netns ahh | |
# show results | |
echo "----" | |
echo host: $(readlink /proc/self/ns/net) | |
for NETNS in $(findmnt -n -t nsfs|awk '/\/run\/netns\//{n=split($1,P,"/");print P[n]}'|sort -u); do | |
echo $NETNS: $(findmnt -n /run/netns/$NETNS|sort -u|grep -o "net:\[[0-9]*\]") | |
done | |
echo tapclient: $(readlink /proc/$TAPPID/ns/net) | |
echo | |
grep -e "iff:" -e "netns:" /proc/$TAPPID/fdinfo/3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment