Skip to content

Commit

Permalink
Network NS && Refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
whokilleddb committed Feb 9, 2022
1 parent f0fd512 commit 2c537fc
Show file tree
Hide file tree
Showing 14 changed files with 565 additions and 211 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ obj/
bin/
isolate
test*
rootfs
rootfs
a.out
49 changes: 42 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,66 @@ ROOTFSIMAGEURL := https://dl-cdn.alpinelinux.org/alpine/v3.15/releases/x86_64/al

# Target Binary
TARGET := isolate
USERNS := userns
MOUNTNS := mountns
UTILS := utils
MOUNTNS := mountns
PIDNS := pidns

# Directories
SRCDIR :=src
INCDIR := include
OBJDIR := obj
ROOTFSDIR := rootfs

# Compile Time Flags
CFLAGS := -Wall -Wextra -Werror=format-security -grecord-gcc-switches -fstack-clash-protection -pipe -g -O2 -D_GNU_SOURCE

#Defauilt Make
all: $(TARGET) rootfs
all: rootfs utils pidns mountns mountns userns $(TARGET)

rootfs:
@$(RM) -rf $(ROOTFSIMAGE) $(ROOTFSDIR)
@mkdir -p $(ROOTFSDIR)
@echo "Fetching Ubuntu rootfs image" && wget -q --show-progress $(ROOTFSIMAGEURL) -O $(ROOTFSIMAGE)
@echo "Extracting Rootfs" && tar -xzf $(ROOTFSIMAGE) -C $(ROOTFSDIR) && echo "Done!"
@echo "[+] Fetching Alpine rootfs image" && wget -q --show-progress $(ROOTFSIMAGEURL) -O $(ROOTFSIMAGE)
@echo "[+] Extracting Rootfs" && tar -xzf $(ROOTFSIMAGE) -C $(ROOTFSDIR) && echo "Done!"
@$(RM) -rf $(ROOTFSIMAGE)

$(TARGET): $(SRCDIR)/$(TARGET).c
$(CC) $(CFLAGS) -I $(INCDIR) -o $(TARGET) $(SRCDIR)/$(TARGET).c

utils: $(SRCDIR)/$(UTILS).c
@echo "[+] Compiling Program Utils"
@mkdir -p $(OBJDIR)
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(UTILS).o $(SRCDIR)/$(UTILS).c


pidns: $(SRCDIR)/$(PIDNS).c
@mkdir -p $(OBJDIR)
@echo "[+] Compiling PID Namespace Program"
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(PIDNS).o $(SRCDIR)/$(PIDNS).c


mountns: $(SRCDIR)/$(MOUNTNS).c
@mkdir -p $(OBJDIR)
@echo "[+] Compiling Mount Namespace Program"
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(MOUNTNS).o $(SRCDIR)/$(MOUNTNS).c

userns: $(SRCDIR)/$(USERNS).c
@mkdir -p $(OBJDIR)
@echo "[+] Compiling User Namespace Program"
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(USERNS).o $(SRCDIR)/$(USERNS).c


$(TARGET): $(SRCDIR)/$(TARGET).c $(OBJDIR)/$(USERNS).o $(OBJDIR)/$(MOUNTNS).o $(OBJDIR)/$(UTILS).o
@echo "[+] Compiling"
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(TARGET).o $(SRCDIR)/$(TARGET).c
$(CC) $(CFLAGS) $(OBJDIR)/$(USERNS).o $(OBJDIR)/$(MOUNTNS).o $(OBJDIR)/$(TARGET).o $(OBJDIR)/$(UTILS).o $(OBJDIR)/$(PIDNS).o -o $(TARGET)




#Non-File Targets
.PHONY: clean rootfs
.PHONY: clean rootfs

#Clean only Objecst
clean:
@$(RM) -rf $(TARGET) $(ROOTFSDIR)
@$(RM) -rf $(TARGET) $(ROOTFSDIR) $(OBJDIR)
61 changes: 0 additions & 61 deletions include/isolate.h

This file was deleted.

51 changes: 9 additions & 42 deletions include/mountns.h
Original file line number Diff line number Diff line change
@@ -1,46 +1,13 @@
#pragma once
#include <sys/syscall.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include "proc_ns.h"
#include "utils.h"
#ifndef __MOUNT_NS
#define __MOUNT_NS

static void prepare_mount_ns(char* rootfs){
const char *mnt = rootfs;
#include <stdlib.h>
#include <stdio.h>

// mount --bind rootfs rootfs
if(mount(rootfs, mnt, FSTYPE, MS_BIND,"") < 0){
exit_on_error("Failed to mount rootfs");
}
#define ROOTFS "rootfs" // Name of rootfs directory
#define FSTYPE "ext4" // FS Type

int prepare_mountns(void);

// cd rootfs
if(chdir(mnt) < 0){
exit_on_error("Failed to change directory");
}

// mkdir put_old
const char *put_old = ".put_old";
if((mkdir(put_old,0777) != 0) && (errno != EEXIST)){
exit_on_error("Could not create .put_old");
}

// pivot_root . .put_old
if(syscall(SYS_pivot_root,".",put_old)<0){
exit_on_error("Could Not Pivot Root");
}

// cd /
if (chdir("/") < 0){
exit_on_error("Could not change directory to /");
}

//prepare proc fs
prepare_procfs();

//umount .put_old
if(umount2(put_old, MNT_DETACH)){
exit_on_error("Failed to umount .put_old");
}
}
#endif
172 changes: 172 additions & 0 deletions include/networkns.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* The Holy Bible which helped me through this:
https://maz-programmersdiary.blogspot.com/2011/09/netlink-sockets.html
God protect the precious soul who wrote this
*/
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <libnetlink.h>
#include <linux/veth.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <sys/uio.h>
#include <string.h>

#include "utils.h"

// Netlink Message Payload
#define MAX_PAYLOAD 1024

/*
Struct referencing the Netlink message
See https://github.com/shemminger/iproute2/blob/main/ip/ip_common.h
*/
struct iplink_req{
// See:https://datatracker.ietf.org/doc/html/rfc3549#section-2.3.2
struct nlmsghdr n; // Netlink message header
// See https://elixir.bootlin.com/linux/v4.9/source/include/uapi/linux/rtnetlink.h#L481
struct ifinfomsg i;
char buf[MAX_PAYLOAD];
};

// Check response from Kernel
void check_response(int sock_fd){
struct iovec iov;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1
};

}


// send Netlink message
static void send_nlmsg(int sock_fd, struct nlmsghdr *n){
struct iovec iov = {
.iov_base = n, /* Starting address */
.iov_len = n->nlmsg_len /* Starting address */
};

struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1
};

n->nlmsg_seq++;

if (sendmsg(sock_fd, &msg, 0) < 0){
exit_on_error("[-] Netlink Request Failed");
}

check_response(sock_fd);
}

// Create veth device
static int create_veth(int sock_fd, char *ifname, char *peername){
/* Taken from source code of ip command
See Link 1060: https://github.com/shemminger/iproute2/blob/main/ip/iplink.c
*/
struct iplink_req req = {
/* From netlink(3)
NLMSG_LENGTH()
Given the payload length, len, this macro returns the aligned length to store
in the nlmsg_len field of the nlmsghdr.
*/

.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
/* From netlink(7)
NLM_F_REQUEST: Must be set on all request messages
NLM_F_ACK: Request for an acknowledgement on success.
NLM_F_CREATE: Create new device if it doesn't already exist
NLM_F_EXCL: Don't replace if the object already exists
*/
.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
/* From rtnetlink(7)
RTM_NEWLINK: Create a specific network interface.
*/
.n.nlmsg_type = RTM_NEWLINK,

// Set socket type to Netlink
.i.ifi_family = PF_NETLINK,
};


struct nlmsghdr *n = &req.n;
int maxlen = sizeof(req);

/* From libnetlink(3):
int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
Add a variable length attribute of type type and with value data and alen length to netlink message n,
which is part of a buffer of length maxlen. data is copied.
From https://www.infradead.org/~tgr/libnl/doc/route.html:
IFLA_IFNAME: Used to add link name attribute
*/
if (addattr_l(n, maxlen, IFLA_IFNAME, ifname, strlen(ifname)+1) <0){
exit_on_error("Could Not Setup veth pair");
}

/* Create a network bridge
Add Attribute
See: https://unix.stackexchange.com/questions/441877/identify-if-a-network-interface-is-a-veth-using-sys-class-net
Also, I highly recommend refering to the Bible mentioned at the start of this code for the upcoming sections
*/
struct rtattr *linkinfo;
struct rtattr *linkdata;
struct rtattr *peerinfo;
linkinfo = addattr_nest(n, maxlen, IFLA_LINKINFO);

// Specify a veth type device
if (addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, DEVICETYPE, strlen(DEVICETYPE)+1) < 0 ){
addattr_nest_end(n, linkinfo);
exit_on_error("[-] Could not create veth device :(");
}

// Add another nested attribute data
linkdata = addattr_nest(n, maxlen, IFLA_INFO_DATA);

// Add nested attribute containing peer name
peerinfo = addattr_nest(n, maxlen, VETH_INFO_PEER);
n->nlmsg_len += sizeof(struct ifinfomsg);

if (addattr_l(n, maxlen, IFLA_IFNAME, peername, strlen(peername) + 1)<0){
addattr_nest_end(n, linkdata);
exit_on_error("[-] Could not add peer");
}

// End attributes
addattr_nest_end(n, peerinfo);
addattr_nest_end(n, linkdata);
addattr_nest_end(n, linkinfo);

// Send message
send_nlmsg(sock_fd, n);
return 0;
}

// Prepare Network Namespace
static int prepare_network_ns(){
/*
PF_NETLINK: Netlink socket
SOCK_RAW: Raw Socket, requires sudo privileges
SOCK_CLOEXEC: Avoids a race condition between getting a new socket from accept and setting the FD_CLOEXEC flag afterwards.
NETLINK_ROUTE: Communication channel between user-space routing dæmon and kernel packet forwarding module.
PS: PF_NETLINK and AF_NETLINK point to the same value as can be seen in socket.h:
#define PF_NETLINK AF_NETLINK
*/
int s = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if(s < 0){
exit_on_error("Failed to create Netlink socket");
}

if (create_veth(s, VETH0, VETH1)!= 0){
exit_on_error("Could not create interface pair");
}

return 0;
}
10 changes: 10 additions & 0 deletions include/pidns.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once
#ifndef __PROC_NS
#define __PROC_NS
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include "utils.h"

int prepare_pidns(void);
#endif
Loading

0 comments on commit 2c537fc

Please sign in to comment.