From e669dbee639c4956430bc90345e1f05687c9d50a Mon Sep 17 00:00:00 2001 From: netblue30 Date: Mon, 11 Jan 2016 19:52:15 -0500 Subject: IPv6 support --- RELNOTES | 1 + src/firejail/firejail.h | 2 ++ src/firejail/main.c | 21 +++++++++++++++ src/firejail/network.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++- src/firejail/sandbox.c | 3 +++ src/firejail/usage.c | 1 + src/man/firejail.txt | 10 +++++++ 7 files changed, 107 insertions(+), 1 deletion(-) diff --git a/RELNOTES b/RELNOTES index 6a561765a..a51fb1afb 100644 --- a/RELNOTES +++ b/RELNOTES @@ -2,6 +2,7 @@ firejail (0.9.37) baseline; urgency=low * development version * security profiles fixes * dynamic allocation of noblacklist buffer + * --ip6 option - IPv6 support -- netblue30 firejail (0.9.36) baseline; urgency=low diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 3ffb2b527..15110607d 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -75,6 +75,7 @@ typedef struct bridge_t { // inside the sandbox char *devsandbox; // name of the device inside the sandbox uint32_t ipsandbox; // ip address inside the sandbox + char *ip6sandbox; // ipv6 address inside the sandbox uint8_t macsandbox[6]; // mac address inside the sandbox uint32_t iprange_start;// iprange arp scan start range uint32_t iprange_end; // iprange arp scan end range @@ -251,6 +252,7 @@ void net_dns_print(pid_t pid); void net_if_up(const char *ifname); void net_if_down(const char *ifname); void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); +void net_if_ip6(const char *ifname, const char *addr6); int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu); int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); void net_ifprint(void); diff --git a/src/firejail/main.c b/src/firejail/main.c index 3f7a26b64..7b493a351 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -1095,6 +1095,27 @@ int main(int argc, char **argv) { } } } + else if (strncmp(argv[i], "--ip6=", 6) == 0) { + Bridge *br = last_bridge_configured(); + if (br == NULL) { + fprintf(stderr, "Error: no network device configured\n"); + return 1; + } + if (br->arg_ip_none || br->ip6sandbox) { + fprintf(stderr, "Error: cannot configure the IP address twice for the same interface\n"); + return 1; + } + + // configure this IP address for the last bridge defined + // todo: verify ipv6 syntax + br->ip6sandbox = argv[i] + 6; +// if (atoip(argv[i] + 5, &br->ipsandbox)) { +// fprintf(stderr, "Error: invalid IP address\n"); +// return 1; +// } + } + + else if (strncmp(argv[i], "--defaultgw=", 12) == 0) { if (atoip(argv[i] + 12, &cfg.defaultgw)) { fprintf(stderr, "Error: invalid IP address\n"); diff --git a/src/firejail/network.c b/src/firejail/network.c index ece406fc8..72bc5e7c6 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c @@ -274,7 +274,75 @@ void net_if_down(const char *ifname) { close(sock); } -// configure interface +struct ifreq6 { + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; +// configure interface ipv6 address +// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64 +void net_if_ip6(const char *ifname, const char *addr6) { + if (strchr(addr6, ':') == NULL) { + fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6); + exit(1); + } + + // extract prefix + unsigned long prefix; + char *ptr; + if ((ptr = strchr(addr6, '/'))) { + prefix = atol(ptr + 1); + if ((prefix < 0) || (prefix > 128)) { + fprintf(stderr, "Error: invalid prefix for IPv6 address %s\n", addr6); + exit(1); + } + *ptr = '\0'; // mark the end of the address + } + else + prefix = 128; + + // extract address + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr); + if (rv <= 0) { + fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6); + exit(1); + } + + // open socket + int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) { + fprintf(stderr, "Error: IPv6 is not supported on this system\n"); + exit(1); + } + + // find interface index + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { + perror("ioctl SIOGIFINDEX"); + exit(1); + } + + // configure address + struct ifreq6 ifr6; + memset(&ifr6, 0, sizeof(ifr6)); + ifr6.ifr6_prefixlen = prefix; + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr)); + if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { + perror("ioctl SIOCSIFADDR"); + exit(1); + } + + close(sock); +} + +// configure interface ipv4 address void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) { if (strlen(ifname) > IFNAMSIZ) { fprintf(stderr, "Error: invalid network device name %s\n", ifname); diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 25662d90e..ac0f62dab 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -107,6 +107,9 @@ static void sandbox_if_up(Bridge *br) { net_if_ip(dev, br->ipsandbox, br->mask, br->mtu); net_if_up(dev); } + + if (br->ip6sandbox) + net_if_ip6(dev, br->ip6sandbox); } static void chk_chroot(void) { diff --git a/src/firejail/usage.c b/src/firejail/usage.c index e4a5f1ff0..5eab05076 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c @@ -106,6 +106,7 @@ void usage(void) { printf("\t--ip=none - no IP address and no default gateway address are configured\n"); printf("\t\tin the new network namespace. Use this option in case you intend\n"); printf("\t\tto start an external DHCP client in the sandbox.\n\n"); + printf("\t--ip6=address - set interface IPv6 address.\n\n"); printf("\t--iprange=address,address - configure an IP address in this range\n\n"); printf("\t--ipc-namespace - enable a new IPC namespace if the sandbox was started\n"); printf("\t\tas a regular user. IPC namespace is enabled by default only if\n"); diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 9f834011e..c8dd7d786 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -461,6 +461,16 @@ Example: .br $ firejail \-\-net=eth0 \-\-\ip=none +.TP +\fB\-\-ip6=address +Assign IPv6 addresses to the last network interface defined by a \-\-net option. +.br + +.br +Example: +.br +$ firejail \-\-net=eth0 \-\-ip6=2001:0db8:0:f101::1/64 firefox + .TP \fB\-\-iprange=address,address Assign an IP address in the provided range to the last network interface defined by a \-\-net option. A -- cgit v1.2.3-70-g09d2