diff --git a/docker-compose.yml b/docker-compose.yml index 893d3631b..bf5eec208 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -128,8 +128,6 @@ services: - NET_ADMIN sysctls: - net.ipv6.conf.all.disable_ipv6=0 - devices: - - "/dev/net/tun:/dev/net/tun" depends_on: gateway: condition: "service_healthy" @@ -169,8 +167,6 @@ services: - net.ipv6.conf.all.disable_ipv6=0 - net.ipv6.conf.all.forwarding=1 - net.ipv6.conf.default.forwarding=1 - devices: - - "/dev/net/tun:/dev/net/tun" depends_on: api: condition: "service_healthy" diff --git a/elixir/apps/web/lib/web/live/relay_groups/new_token.ex b/elixir/apps/web/lib/web/live/relay_groups/new_token.ex index 8e340a294..640319391 100644 --- a/elixir/apps/web/lib/web/live/relay_groups/new_token.ex +++ b/elixir/apps/web/lib/web/live/relay_groups/new_token.ex @@ -265,7 +265,6 @@ defmodule Web.RelayGroups.NewToken do "--sysctl net.ipv6.conf.all.disable_ipv6=0", "--sysctl net.ipv6.conf.all.forwarding=1", "--sysctl net.ipv6.conf.default.forwarding=1", - "--device=\"/dev/net/tun:/dev/net/tun\"", Enum.map(env, fn {key, value} -> "--env #{key}=\"#{value}\"" end), "--env FIREZONE_NAME=$(hostname)", "#{Domain.Config.fetch_env!(:domain, :docker_registry)}/relay:#{major_minor_version()}" diff --git a/elixir/apps/web/lib/web/live/sites/new_token.ex b/elixir/apps/web/lib/web/live/sites/new_token.ex index 4230880e8..5574ae331 100644 --- a/elixir/apps/web/lib/web/live/sites/new_token.ex +++ b/elixir/apps/web/lib/web/live/sites/new_token.ex @@ -180,7 +180,6 @@ defmodule Web.Sites.NewToken do "--sysctl net.ipv6.conf.all.disable_ipv6=0", "--sysctl net.ipv6.conf.all.forwarding=1", "--sysctl net.ipv6.conf.default.forwarding=1", - "--device=\"/dev/net/tun:/dev/net/tun\"", Enum.map(env ++ [{"FIREZONE_ENABLE_MASQUERADE", "1"}], fn {key, value} -> "--env #{key}=\"#{value}\"" end), diff --git a/rust/connlib/tunnel/src/device_channel/tun_linux.rs b/rust/connlib/tunnel/src/device_channel/tun_linux.rs index dd5e0b2f7..4323059af 100644 --- a/rust/connlib/tunnel/src/device_channel/tun_linux.rs +++ b/rust/connlib/tunnel/src/device_channel/tun_linux.rs @@ -5,16 +5,21 @@ use futures_util::future::BoxFuture; use futures_util::FutureExt; use ip_network::IpNetwork; use libc::{ - close, fcntl, open, F_GETFL, F_SETFL, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TUN, O_NONBLOCK, O_RDWR, + close, fcntl, makedev, mknod, open, F_GETFL, F_SETFL, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TUN, + O_NONBLOCK, O_RDWR, S_IFCHR, }; use netlink_packet_route::RT_SCOPE_UNIVERSE; use parking_lot::Mutex; use rtnetlink::{new_connection, Error::NetlinkError, Handle}; use std::net::IpAddr; +use std::path::Path; use std::task::{Context, Poll}; use std::{ - fmt, io, - os::fd::{AsRawFd, RawFd}, + fmt, fs, io, + os::{ + fd::{AsRawFd, RawFd}, + unix::fs::PermissionsExt, + }, }; use tokio::io::unix::AsyncFd; @@ -25,6 +30,8 @@ pub(crate) const SIOCGIFMTU: libc::c_ulong = libc::SIOCGIFMTU; const IFACE_NAME: &str = "tun-firezone"; const TUNSETIFF: libc::c_ulong = 0x4004_54ca; const TUN_FILE: &[u8] = b"/dev/net/tun\0"; +const TUN_DEV_MAJOR: u32 = 10; +const TUN_DEV_MINOR: u32 = 200; const RT_PROT_STATIC: u8 = 4; const DEFAULT_MTU: u32 = 1280; const FILE_ALREADY_EXISTS: i32 = -17; @@ -82,6 +89,8 @@ impl Tun { } pub fn new(config: &InterfaceConfig, _: Vec, _: &impl Callbacks) -> Result { + create_tun_device()?; + let fd = match unsafe { open(TUN_FILE.as_ptr() as _, O_RDWR) } { -1 => return Err(get_last_error()), fd => fd, @@ -232,6 +241,31 @@ fn set_non_blocking(fd: RawFd) -> Result<()> { } } +fn create_tun_device() -> Result<()> { + let path = Path::new(std::str::from_utf8(TUN_FILE).unwrap()); + + if path.exists() { + return Ok(()); + } + + let parent_dir = path.parent().unwrap(); + fs::create_dir_all(parent_dir)?; + let permissions = fs::Permissions::from_mode(0o751); + fs::set_permissions(parent_dir, permissions)?; + if unsafe { + mknod( + TUN_FILE.as_ptr() as _, + S_IFCHR, + makedev(TUN_DEV_MAJOR, TUN_DEV_MINOR), + ) + } != 0 + { + return Err(get_last_error()); + } + + Ok(()) +} + /// Read from the given file descriptor in the buffer. fn read(fd: RawFd, dst: &mut [u8]) -> io::Result { // Safety: Within this module, the file descriptor is always valid. diff --git a/scripts/gateway-docker-upgrade.sh b/scripts/gateway-docker-upgrade.sh index b2f6df394..f8db17763 100755 --- a/scripts/gateway-docker-upgrade.sh +++ b/scripts/gateway-docker-upgrade.sh @@ -3,8 +3,6 @@ set -e TARGET_IMAGE="ghcr.io/firezone/gateway:1" -REPO=$(dirname "$TARGET_IMAGE") -IMAGE=$(basename "$TARGET_IMAGE") CURRENTLY_RUNNING=$(docker ps --format "{{.Names}} {{.Image}}" | grep -e "$TARGET_IMAGE" | awk '{print $1}') if [ "$CURRENTLY_RUNNING" == "" ]; then @@ -40,7 +38,6 @@ do --sysctl net.ipv6.conf.all.disable_ipv6=0 \ --sysctl net.ipv6.conf.all.forwarding=1 \ --sysctl net.ipv6.conf.default.forwarding=1 \ - --device="/dev/net/tun:/dev/net/tun" \ "$TARGET_IMAGE" rm variables.env echo "Container upgraded" diff --git a/terraform/modules/aws/gateway/templates/cloud-init.yaml b/terraform/modules/aws/gateway/templates/cloud-init.yaml index dfd13630a..2da61cae1 100644 --- a/terraform/modules/aws/gateway/templates/cloud-init.yaml +++ b/terraform/modules/aws/gateway/templates/cloud-init.yaml @@ -24,7 +24,7 @@ write_files: ExecStartPre=-/usr/bin/docker stop ${container_name} ExecStartPre=-/usr/bin/docker rm ${container_name} ExecStartPre=/usr/bin/docker pull ${container_image} - ExecStart=/bin/sh -c 'docker run --rm --name=${container_name} --cap-add=NET_ADMIN --volume /etc/firezone --sysctl net.ipv4.ip_forward=1 --sysctl net.ipv4.conf.all.src_valid_mark=1 --sysctl net.ipv6.conf.all.disable_ipv6=0 --sysctl net.ipv6.conf.all.forwarding=1 --sysctl net.ipv6.conf.default.forwarding=1 --device="/dev/net/tun:/dev/net/tun" --env FIREZONE_NAME=$(hostname) --env FIREZONE_ID=$(echo $RANDOM$(hostname) | md5sum | head -c 20; echo;) --env-file="/etc/firezone-gateway/env" ${container_image}' + ExecStart=/bin/sh -c 'docker run --rm --name=${container_name} --cap-add=NET_ADMIN --volume /etc/firezone --sysctl net.ipv4.ip_forward=1 --sysctl net.ipv4.conf.all.src_valid_mark=1 --sysctl net.ipv6.conf.all.disable_ipv6=0 --sysctl net.ipv6.conf.all.forwarding=1 --sysctl net.ipv6.conf.default.forwarding=1 --env FIREZONE_NAME=$(hostname) --env FIREZONE_ID=$(echo $RANDOM$(hostname) | md5sum | head -c 20; echo;) --env-file="/etc/firezone-gateway/env" ${container_image}' ExecStop=/usr/bin/docker stop gateway ExecStopPost=/usr/bin/docker rm gateway diff --git a/terraform/modules/gateway-google-cloud-compute/templates/cloud-init.yaml b/terraform/modules/gateway-google-cloud-compute/templates/cloud-init.yaml index c5fc60f69..61b65b2dc 100644 --- a/terraform/modules/gateway-google-cloud-compute/templates/cloud-init.yaml +++ b/terraform/modules/gateway-google-cloud-compute/templates/cloud-init.yaml @@ -107,7 +107,7 @@ write_files: TimeoutStartSec=0 Restart=always ExecStartPre=/usr/bin/docker pull ${container_image} - ExecStart=/bin/sh -c 'docker run --rm --name=${container_name} --cap-add=NET_ADMIN --volume /etc/firezone --device="/dev/net/tun:/dev/net/tun" --env FIREZONE_NAME=$(hostname) --env FIREZONE_ID=$(echo $RANDOM$(hostname) | md5sum | head -c 20; echo;) --env-file="/etc/firezone-gateway/.env" ${container_image}' + ExecStart=/bin/sh -c 'docker run --rm --name=${container_name} --cap-add=NET_ADMIN --volume /etc/firezone --env FIREZONE_NAME=$(hostname) --env FIREZONE_ID=$(echo $RANDOM$(hostname) | md5sum | head -c 20; echo;) --env-file="/etc/firezone-gateway/.env" ${container_image}' ExecStop=/usr/bin/docker stop gateway ExecStopPost=/usr/bin/docker rm gateway