Skip to content

Commit

Permalink
Complete Draft 1 - Not compiled or Tested
Browse files Browse the repository at this point in the history
  • Loading branch information
whokilleddb committed Feb 10, 2022
1 parent 2c537fc commit 44666fc
Show file tree
Hide file tree
Showing 7 changed files with 450 additions and 187 deletions.
12 changes: 7 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ MOUNTNS := mountns
UTILS := utils
MOUNTNS := mountns
PIDNS := pidns
NETNS := networkns

# Directories
SRCDIR :=src
Expand All @@ -23,7 +24,7 @@ ROOTFSDIR := rootfs
CFLAGS := -Wall -Wextra -Werror=format-security -grecord-gcc-switches -fstack-clash-protection -pipe -g -O2 -D_GNU_SOURCE

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

rootfs:
@$(RM) -rf $(ROOTFSIMAGE) $(ROOTFSDIR)
Expand Down Expand Up @@ -55,14 +56,15 @@ userns: $(SRCDIR)/$(USERNS).c
@echo "[+] Compiling User Namespace Program"
$(CC) $(CFLAGS) -I ${INCDIR} -c -o $(OBJDIR)/$(USERNS).o $(SRCDIR)/$(USERNS).c

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

$(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)



$(CC) $(CFLAGS) $(OBJDIR)/$(USERNS).o $(OBJDIR)/$(MOUNTNS).o $(OBJDIR)/$(TARGET).o $(OBJDIR)/$(UTILS).o $(OBJDIR)/$(PIDNS).o $(OBJDIR)/$(NETNS).o -o $(TARGET)

#Non-File Targets
.PHONY: clean rootfs
Expand Down
184 changes: 17 additions & 167 deletions include/networkns.h
Original file line number Diff line number Diff line change
@@ -1,172 +1,22 @@
/* 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>
#ifndef __NETWORK_NS
#define __NETWORK_NS

#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;
}
#define VETH0 "veth0" // The interface facing the root namespace
#define VETH1 "veth1" // The interface facing the network namespace
#define IP0 "10.1.1.1" // IP address associated with VETH0
#define IP1 "10.1.1.2" // IP address associated with VETH1
#define NETMASK "255.255.255.0" // Netmask of our virtual network
#define DEVICETYPE "veth"

int check_response(int sock_fd);
int send_nlmsg(int sock_fd, struct nlmsghdr *n);
int create_veth(int sock_fd, char *ifname, char *peername);
int interface_up(char *ifname, char *ip, char *netmask);
int ns_fd(int pid);
int move_interface_to_ns(int sock_fd, char *ifname, int netns);
int prepare_networkns(int child_pid);
#endif
5 changes: 3 additions & 2 deletions include/userns.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#pragma once
#ifndef __PREPARE_USER_NS
#ifndef __USER_NS
#define __USER_NS
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <linux/limits.h>

#include "utils.h"

int prepare_user_ns(int pid);
int prepare_userns(int pid);

#endif
8 changes: 0 additions & 8 deletions include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,6 @@
#define MAGENTA(string) "\x1b[35m" string "\x1b[0m"
#define CYAN(string) "\x1b[36m" string "\x1b[0m"

#define UID 1000
#define VETH0 "veth0" // The interface facing the root namespace
#define VETH1 "veth1" // The interface facing the network namespace
#define IP_0 "10.1.1.1" // IP address associated with VETH0
#define IP_1 "10.1.1.2" // IP address associated with VETH1
#define NETMASK "255.255.255.0" // Netmask of our virtual network
#define DEVICETYPE "veth"

void exit_on_error(const char *format, ...);

#endif
14 changes: 10 additions & 4 deletions src/isolate.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include "utils.h"
#include "mountns.h"
#include "userns.h"
//#include "networkns.h"
#include "networkns.h"


// Flags used in name space creation
Expand Down Expand Up @@ -67,6 +67,7 @@ int cmd_exec(void *arg){
return -1;
}

// Prepare MOUNT namespace
if (prepare_mountns() != 0){
fprintf(stderr,"[" RED("!") "] Failed to create "RED("Mount") "namespace\n");
return -1;
Expand Down Expand Up @@ -159,15 +160,20 @@ int main(int argc, char* argv[]){
free(stack);
exit_on_error("[" RED("!") "] The function " RED("clone()") " failed\n");
}
fprintf(stdout,"[" GREEN("i") "] Successfully created " GREEN("Hostname") " namespace\n");
fprintf(stdout,"[" GREEN("i") "] Successfully created " GREEN("UTS") " namespace\n");


// Prepare User Namespace
if (prepare_user_ns(cmd_pid) != 0){
// Prepare USER Namespace
if (prepare_userns(cmd_pid) != 0){
exit_on_error("[" RED("!") "] Failed to create " RED("User") " namespace\n");
}
fprintf(stdout,"[" GREEN("i") "] Successfully created " GREEN("User") " namespace\n");

// Prepare Network Namespace
if (prepare_networkns(cmd_pid) != 0){
exit_on_error("[" RED("!") "] Failed to create " RED("Network") " namespace\n");
}
fprintf(stdout,"[" GREEN("i") "] Successfully created " GREEN("Network") " namespace\n");

// Send 'setup done' signal to Child process
if (write(cli_params.fd[1],"OK",2)!=2){
Expand Down
Loading

0 comments on commit 44666fc

Please sign in to comment.