.is_root_rw = false,
.is_silent = false,
.skip_setsid = false,
- .iface = NULL,
.inside_uid = getuid(),
.inside_gid = getgid(),
.outside_uid = getuid(),
.max_conns_per_ip = 0,
.tmpfs_size = 4 * (1024 * 1024),
.mount_proc = true,
+ .iface = NULL,
+ .iface_lo_up = false,
.sbinip_fd = -1,
};
/* *INDENT-OFF* */
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind (rw) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'"},
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times. Supports 'dest' syntax"},
{{"iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVTAP) and put inside the subprocess' namespace"},
+ {{"iface_lo_up", no_argument, NULL, 0x700}, "Bring up the 'lo' interface"},
{{"tmpfs_size", required_argument, NULL, 0x0602}, "Number of bytes to allocate for tmpfsmounts (default: 4194304)"},
{{"disable_proc", no_argument, NULL, 0x0603}, "Disable mounting /proc in the jail"},
{{0, 0, 0, 0}, NULL},
case 'I':
nsjconf->iface = optarg;
break;
+ case 0x700:
+ nsjconf->iface_lo_up = true;
+ break;
default:
cmdlineUsage(argv[0], custom_opts);
return false;
bool is_root_rw;
bool is_silent;
bool skip_setsid;
- char *iface;
uid_t outside_uid;
gid_t outside_gid;
uid_t inside_uid;
unsigned int max_conns_per_ip;
size_t tmpfs_size;
bool mount_proc;
+ char *iface;
+ bool iface_lo_up;
int sbinip_fd;
TAILQ_HEAD(envlist, charptr_t) envs;
TAILQ_HEAD(pidslist, pids_t) pids;
#include <unistd.h>
#include "log.h"
+#include "net.h"
#include "util.h"
+bool containInitNetNs(struct nsjconf_t * nsjconf)
+{
+ if (nsjconf->iface_lo_up) {
+ if (netIfaceUp("lo") == false) {
+ return false;
+ }
+ }
+ return true;
+}
+
static bool containSetGroups(pid_t pid)
{
/*
#include "common.h"
bool containInitUserNs(struct nsjconf_t *nsjconf, pid_t pid);
+bool containInitNetNs(struct nsjconf_t *nsjconf);
bool containDropPrivs(struct nsjconf_t *nsjconf);
bool containPrepareEnv(struct nsjconf_t *nsjconf);
bool containMountFS(struct nsjconf_t *nsjconf);
#include <arpa/inet.h>
#include <errno.h>
-#include <linux/if.h>
+#include <net/if.h>
#include <sched.h>
#include <stdio.h>
#include <stdint.h>
#include <strings.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
+#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "log.h"
-bool netSystemSbinIp(struct nsjconf_t *nsjconf, char *const *argv)
+static bool netSystemSbinIp(struct nsjconf_t *nsjconf, char *const *argv)
{
+ if (nsjconf->clone_newnet == false) {
+ LOG_W
+ ("CLONE_NEWNET not enabled. All changes would affect the global networking namespace");
+ return false;
+ }
+
int pid = fork();
if (pid == -1) {
PLOG_E("fork()");
LOG_W("'/sbin/ip' killed with signal: %d", WTERMSIG(status));
return false;
}
- LOG_E("Unknown exit status for '/sbin/ip' (pid=%d): %d", pid, status);
+ LOG_W("Unknown exit status for '/sbin/ip' (pid=%d): %d", pid, status);
kill(pid, SIGKILL);
}
}
return true;
}
- char iface[IFNAMSIZ];
+ char iface[IF_NAMESIZE];
snprintf(iface, sizeof(iface), "NS.TAP.%d", pid);
char *const argv_add[] =
snprintf(buf, s, "[%s]:%hu", tmp, ntohs(addr.sin6_port));
return;
}
+
+bool netIfaceUp(const char *ifacename)
+{
+ int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+ if (sock == -1) {
+ PLOG_E("socket(AF_INET, SOCK_STREAM, IPPROTO_IP)");
+ return false;
+ }
+
+ struct ifreq ifr;
+ snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", ifacename);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) == -1) {
+ PLOG_E("ioctl(iface='%s', SIOCGIFFLAGS, IFF_UP", ifacename);
+ close(sock);
+ return false;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
+
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
+ PLOG_E("ioctl(iface='%s', SIOCSIFFLAGS, IFF_UP", ifacename);
+ close(sock);
+ return false;
+ }
+
+ close(sock);
+ return true;
+}
#include "common.h"
-bool netSystemSbinIp(struct nsjconf_t *nsjconf, char *const *argv);
bool netCloneMacVtapAndNS(struct nsjconf_t *nsjconf, int pid);
bool netLimitConns(struct nsjconf_t *nsjconf, int connsock);
int netGetRecvSocket(const char *bindhost, int port);
int netAcceptConn(int listenfd);
void netConnToText(int fd, bool remote, char *buf, size_t s, struct sockaddr_in6 *addr_or_null);
+bool netIfaceUp(const char *ifacename);
#endif /* _NET_H */
if (containMountFS(nsjconf) == false) {
exit(1);
}
+ if (containInitNetNs(nsjconf) == false) {
+ exit(1);
+ }
if (containDropPrivs(nsjconf) == false) {
exit(1);
}