Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduced named network namespace for replayshell #106

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions src/frontend/replayshell.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

#include <net/route.h>
#include <fcntl.h>

#include <vector>
#include <set>
#include <string>
#include <net/route.h>
#include <fcntl.h>

#include "util.hh"
#include "netdevice.hh"
Expand All @@ -16,6 +15,7 @@
#include "http_response.hh"
#include "dns_server.hh"
#include "exception.hh"
#include "network_namespace.hh"

#include "http_record.pb.h"

Expand Down Expand Up @@ -61,22 +61,31 @@ int main( int argc, char *argv[] )
/* get working directory */
const string working_directory { get_working_directory() };


/* chdir to result of getcwd just in case */
SystemCall( "chdir", chdir( working_directory.c_str() ) );

const string netns_name = string("mahimahi.") + to_string( getpid() );

NetworkNamespace network_namespace;

/* Setup our own resolvconf with nameserver 8.8.8.8 */
network_namespace.create_resolvconf( "8.8.8.8" );

/* Switch to the newly created network namespace */
network_namespace.enter();

/* what command will we run inside the container? */
vector< string > command;
if ( argc == 2 ) {
command.push_back( shell_path() );
} else {

for ( int i = 2; i < argc; i++ ) {
command.push_back( argv[ i ] );
}
}

/* create a new network namespace */
SystemCall( "unshare", unshare( CLONE_NEWNET ) );

/* bring up localhost */
interface_ioctl( SIOCSIFFLAGS, "lo",
[] ( ifreq &ifr ) { ifr.ifr_flags = IFF_UP; } );
Expand Down Expand Up @@ -143,7 +152,6 @@ int main( int argc, char *argv[] )
const string interface_name = "nameserver" + to_string( server_num );
add_dummy_interface( interface_name, nameservers.at( server_num ) );
}

/* start dnsmasq */
event_loop.add_child_process( start_dnsmasq( dnsmasq_args ) );

Expand Down
3 changes: 2 additions & 1 deletion src/util/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ noinst_LIBRARIES = libutil.a

libutil_a_SOURCES = exception.hh ezio.cc ezio.hh \
file_descriptor.hh file_descriptor.cc netdevice.cc netdevice.hh \
timestamp.cc timestamp.hh \
timestamp.cc timestamp.hh \
network_namespace.cc network_namespace.hh \
child_process.hh child_process.cc signalfd.hh signalfd.cc \
socket.cc socket.hh address.cc address.hh \
system_runner.hh system_runner.cc nat.hh nat.cc \
Expand Down
92 changes: 92 additions & 0 deletions src/util/network_namespace.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#include "network_namespace.hh"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sched.h>

#include <memory>

#include "config.h"
#include "system_runner.hh"
#include "exception.hh"
#include "file_descriptor.hh"

using namespace std;

NetworkNamespace::NetworkNamespace( )
: has_own_resolvconf_(false), resolvconf_file_(nullptr), has_entered_(false)
{
}


NetworkNamespace::~NetworkNamespace()
{
/* If we want to cleanup resolv.conf tempfile we need to make sure it is unmounted first */
if ( has_entered_ && has_own_resolvconf_ ) {

if ( umount( "/etc/resolv.conf" ) < 0 ) {
//TODO (worenga): proper RAII for mounts
std::cerr << string("Unmounting... ") << resolvconf_file_->name() << " -> " << "/etc/resolv.conf" << " failed: " << strerror(errno) << "\n" << std::endl;
}
}

//TODO (worenga): How can we redo the (mount/bind) namespace in a RAII manner?

}


void NetworkNamespace::create_resolvconf( const std::string & nameserver )
{
if ( has_entered_ ) {
throw runtime_error( string("Cannot create resolvconf after namespace has been entered.\n") );
}

resolvconf_file_.reset( std::move( new TempFile( "resolvconf" ) ) );
has_own_resolvconf_ = true;

char mode[] = "0644";
if ( chmod (resolvconf_file_->name().c_str(), strtol(mode, 0, 8) ) < 0 ) {
throw runtime_error( string("chmod ") + mode + " for " + resolvconf_file_->name() +" failed: " + strerror(errno) + "\n " );
}

resolvconf_file_->write( "# Ephemeral resolv.conf(5) file for glibc resolver(3) generated by mahimahi\n" );
resolvconf_file_->write( "# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE LOST\n" );
resolvconf_file_->write( "nameserver " + nameserver + "\n" );
}


void NetworkNamespace::enter()
{

if ( unshare(CLONE_NEWNS) < 0 ) {
throw runtime_error( string("unshare failed: ") + strerror(errno) + "\n " );
}


/* Don't let any mounts propagate back to the parent */
if ( mount( "", "/", "none", MS_SLAVE | MS_REC, NULL ) ) {
throw runtime_error( string("\"mount --make-rslave /\" failed: ") + strerror(errno) + "\n " );
}

if ( unshare(CLONE_NEWNET) < 0 ) {
throw runtime_error( string("unshare failed: ") + strerror(errno) + "\n " );
}

has_entered_ = true;

if ( has_own_resolvconf_ ) {

if ( mount( resolvconf_file_->name().c_str() , "/etc/resolv.conf" , "none", MS_BIND, NULL ) < 0 ) {
throw runtime_error( string("Bind ") + resolvconf_file_->name() + " -> " + "/etc/resolv.conf" + " failed: " + strerror(errno) + "\n" );
}

}

}
32 changes: 32 additions & 0 deletions src/util/network_namespace.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* -*-mode:c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */

#ifndef NETNAMESPACE_HH
#define NETNAMESPACE_HH

#include <string>
#include <memory>

#include "temp_file.hh"

class NetworkNamespace
{

private:
bool has_own_resolvconf_;
std::unique_ptr<TempFile> resolvconf_file_;

bool has_entered_;

public:

const std::string NETNS_DIR = "/var/run/netns";
const std::string NETNS_ETC_DIR = "/etc/netns";

NetworkNamespace();
~NetworkNamespace();

void create_resolvconf( const std::string & nameserver );
void enter( void );
};

#endif