Skip to content
Merged
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
13 changes: 10 additions & 3 deletions .github/workflows/code-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
name: Build test
steps:
- uses: actions/checkout@v4

Expand All @@ -27,13 +28,13 @@ jobs:

meson setup build \
-Dprefix=/data/share \
-Dinit-script=monitd \
-Druntime-path=/data/local/tmp \
-Dinit-script=module \
-Druntime-path=/data/share/tmp \
-Dstrip=true \
-Dd_lto=true \
-Db_pie=false \
-Dlog-path=log/lxc \
-Ddata-path=/data/share/lib/lxc \
-Ddata-path=lib/lxc \
--localstatedir=/data/share/var \
-Dmemfd-rexec=true \
--buildtype debug \
Expand All @@ -54,3 +55,9 @@ jobs:
with:
name: android-aarch64-lxc-shared-api30
path: /data/share/*

- name: Upload artifacts lxc-module
uses: actions/upload-artifact@v4.3.1
with:
name: android-lxc-module
path: lxc-module.zip
13 changes: 10 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ jobs:

meson setup build \
-Dprefix=/data/share \
-Dinit-script=monitd \
-Druntime-path=/data/local/tmp \
-Dinit-script=module \
-Druntime-path=/data/share/tmp \
-Dstrip=true \
-Dd_lto=true \
-Dlog-path=log/lxc \
-Ddata-path=/data/share/lib/lxc \
-Ddata-path=lib/lxc \
--localstatedir=/data/share/var \
-Db_pie=false \
-Dmemfd-rexec=false \
Expand Down Expand Up @@ -92,6 +92,12 @@ jobs:
name: android-${{ github.event.inputs.target_arch || 'aarch64' }}-lxc
path: /data/share/*

- name: Upload artifacts lxc-module
uses: actions/upload-artifact@v4.3.1
with:
name: android-lxc-module
path: lxc-module.zip

- name: Create a TAR file for artifact
run: |
tar -czvf android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-lxc.tar.gz -C /data/share .
Expand All @@ -108,3 +114,4 @@ jobs:
files: |
android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-lxc.tar.gz
android-${{ github.event.inputs.target_arch || 'aarch64' }}-api30-sysroot.tar.gz
lxc-module.zip
234 changes: 234 additions & 0 deletions config/init/common/lxc-net-builtin.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#!/bin/sh -

distrosysconfdir="@LXC_DISTRO_SYSCONF@"
varrun="@RUNTIME_PATH@/lxc"
varlib="@LOCALSTATEDIR@/lib"

# These can be overridden in @LXC_DISTRO_SYSCONF@/lxc
# or in @LXC_DISTRO_SYSCONF@/lxc-net-builtin

# This source code has been copied and modified
# from "lxc-net.in" and is protected by the same
# license as the original file.

# For Android built-in dnsmasq, IPv6 support is incomplete and conflicts
# with Android hotspots, as they attempt to bind to all addresses simultaneously.
# So we recommend using a more complete and higher version of dnsmasq, such
# as Termux's dnsmasq in root-repo or others.

LXC_BRIDGE="lxcbr0"
LXC_BRIDGE_MAC="10:66:6a:00:00:00"
LXC_ADDR="10.0.3.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.3.0/24"
LXC_DHCP_RANGE="10.0.3.2,10.0.3.254,24"
LXC_DHCP_MAX="253"
LXC_DHCP_CONFILE=""
LXC_DHCP_PING="true"
LXC_DOMAIN=""
LXC_USE_NFT="false"
DNSMASQ_USER="nobody"
LXC_IPV4_DNS1="8.8.8.8"
LXC_IPV4_DNS2="8.8.4.4"

[ ! -f $distrosysconfdir/lxc ] || . $distrosysconfdir/lxc

use_nft() {
[ -n "$NFT" ] && nft list ruleset > /dev/null 2>&1 && [ "$LXC_USE_NFT" = "true" ]
}

NFT="$(command -v nft)"
if ! use_nft; then
use_iptables_lock="-w"
iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock=""
fi

_netmask2cidr ()
{
# Assumes there's no "255." after a non-255 byte in the mask
local x=${1##*255.}
set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
x=${1%%$3*}
echo $(( $2 + (${#x}/4) ))
}

_ifdown() {
ip addr flush dev ${LXC_BRIDGE}
ip link set dev ${LXC_BRIDGE} down
}

_ifup() {
MASK=$(_netmask2cidr ${LXC_NETMASK})
CIDR_ADDR="${LXC_ADDR}/${MASK}"
ip addr add ${CIDR_ADDR} broadcast + dev ${LXC_BRIDGE}
ip link set dev ${LXC_BRIDGE} address $LXC_BRIDGE_MAC
ip link set dev ${LXC_BRIDGE} up
}

start_iptables() {
iptables -P FORWARD ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
iptables $use_iptables_lock -I INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
iptables $use_iptables_lock -I FORWARD -i ${LXC_BRIDGE} -j ACCEPT
iptables $use_iptables_lock -I FORWARD -o ${LXC_BRIDGE} -j ACCEPT
iptables $use_iptables_lock -t nat -A POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE
iptables $use_iptables_lock -t mangle -A POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
}

start_nftables() {
NFT_RULESET=""
NFT_RULESET="${NFT_RULESET};
add table inet lxc;
flush table inet lxc;
add chain inet lxc input { type filter hook input priority 0; };
add rule inet lxc input iifname ${LXC_BRIDGE} udp dport { 53, 67 } accept;
add rule inet lxc input iifname ${LXC_BRIDGE} tcp dport { 53, 67 } accept;
add chain inet lxc forward { type filter hook forward priority 0; };
add rule inet lxc forward iifname ${LXC_BRIDGE} accept;
add rule inet lxc forward oifname ${LXC_BRIDGE} accept;
add table ip lxc;
flush table ip lxc;
add chain ip lxc postrouting { type nat hook postrouting priority 100; };
add rule ip lxc postrouting ip saddr ${LXC_NETWORK} ip daddr != ${LXC_NETWORK} counter masquerade"
nft "${NFT_RULESET}"
}

start() {
[ ! -f "${varrun}/network_up" ] || { echo "lxc-net-builtin is already running"; exit 1; }

if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
stop force || true
fi

FAILED=1

cleanup() {
set +e
if [ "$FAILED" = "1" ]; then
echo "Failed to setup lxc-net-builtin." >&2
stop force
exit 1
fi
}

trap cleanup EXIT HUP INT TERM
set -e

# set up the lxc network
[ ! -d /sys/class/net/${LXC_BRIDGE} ] && ip link add dev ${LXC_BRIDGE} type bridge
echo 1 > /proc/sys/net/ipv4/ip_forward

# if we are run from systemd on a system with selinux enabled,
# the mkdir will create /run/lxc as init_var_run_t which dnsmasq
# can't write its pid into, so we restorecon it (to var_run_t)
if [ ! -d "${varrun}" ]; then
mkdir -p "${varrun}"
if command -v restorecon >/dev/null 2>&1; then
restorecon "${varrun}"
fi
fi

_ifup

if use_nft; then
start_nftables
else
start_iptables
fi

LXC_DOMAIN_ARG=""
if [ -n "$LXC_DOMAIN" ]; then
LXC_DOMAIN_ARG="-s $LXC_DOMAIN -S /$LXC_DOMAIN/"
fi

# lxc's dnsmasq should be hermetic and not read `/etc/dnsmasq.conf` (which
# it does by default if `--conf-file` is not present
LXC_DHCP_CONFILE_ARG="--conf-file=${LXC_DHCP_CONFILE:-/dev/null}"

LXC_DHCP_PING_ARG=""
if [ "x$LXC_DHCP_PING" = "xfalse" ]; then
LXC_DHCP_PING_ARG="--no-ping"
fi

DNSMASQ_MISC_DIR="$varlib/misc"
if [ ! -d "$DNSMASQ_MISC_DIR" ]; then
mkdir -p "$DNSMASQ_MISC_DIR"
fi

/system/bin/dnsmasq $LXC_DHCP_CONFILE_ARG $LXC_DOMAIN_ARG $LXC_DHCP_PING_ARG -u ${DNSMASQ_USER} \
--strict-order --bind-interfaces --pid-file="${varrun}"/dnsmasq.pid \
--listen-address ${LXC_ADDR} --dhcp-range ${LXC_DHCP_RANGE} \
--dhcp-lease-max=${LXC_DHCP_MAX} --dhcp-no-override \
--except-interface=lo --interface=${LXC_BRIDGE} \
--dhcp-leasefile="${DNSMASQ_MISC_DIR}"/dnsmasq.${LXC_BRIDGE}.leases \
--dhcp-authoritative --server=${LXC_IPV4_DNS1} --server=${LXC_IPV4_DNS2} || cleanup

touch "${varrun}"/network_up
FAILED=0
}

stop_iptables() {
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 67 -j ACCEPT
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 67 -j ACCEPT
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p udp --dport 53 -j ACCEPT
iptables $use_iptables_lock -D INPUT -i ${LXC_BRIDGE} -p tcp --dport 53 -j ACCEPT
iptables $use_iptables_lock -D FORWARD -i ${LXC_BRIDGE} -j ACCEPT
iptables $use_iptables_lock -D FORWARD -o ${LXC_BRIDGE} -j ACCEPT
iptables $use_iptables_lock -t nat -D POSTROUTING -s ${LXC_NETWORK} ! -d ${LXC_NETWORK} -j MASQUERADE
iptables $use_iptables_lock -t mangle -D POSTROUTING -o ${LXC_BRIDGE} -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
}

stop_nftables() {
# Adding table before removing them is just to avoid
# delete error for non-existent table
NFT_RULESET="add table inet lxc;
delete table inet lxc;
add table ip lxc;
delete table ip lxc;
"
nft "${NFT_RULESET}"
}

stop() {
[ -f "${varrun}/network_up" ] || [ "$1" = "force" ] || { echo "lxc-net-builtin isn't running"; exit 1; }

if [ -d /sys/class/net/${LXC_BRIDGE} ]; then
_ifdown
if use_nft; then
stop_nftables
else
stop_iptables
fi

pid=$(cat "${varrun}"/dnsmasq.pid 2>/dev/null) && kill -9 $pid
rm -f "${varrun}"/dnsmasq.pid
# if $LXC_BRIDGE has attached interfaces, don't destroy the bridge
ls /sys/class/net/${LXC_BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete ${LXC_BRIDGE}
fi

rm -f "${varrun}"/network_up
}

# See how we were called.
case "$1" in
start)
start
;;

stop)
stop
;;

restart|reload|force-reload)
$0 stop
$0 start
;;

*)
echo "Usage: $0 {start|stop|restart|reload|force-reload}"
exit 2
esac

exit $?
7 changes: 7 additions & 0 deletions config/init/common/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ lxc_net = configure_file(
output: 'lxc-net',
install: true,
install_dir: lxclibexec)

lxc_net_builtin = configure_file(
configuration: conf,
input: 'lxc-net-builtin.in',
output: 'lxc-net-builtin',
install: true,
install_dir: lxclibexec)
12 changes: 12 additions & 0 deletions config/init/module/boot-completed.sh.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh

export LD_LIBRARY_PATH=/system/lib64:/system/lib:@LIBDIR@:/data/sysroot/lib64:/data/sysroot/lib

# lxc-autostart
mkdir -p @LOCALSTATEDIR@/lock
@LIBEXECDIR@/lxc/lxc-containers start

while true do
@LXCHOOKDIR@/android-network
sleep 5
done
65 changes: 65 additions & 0 deletions config/init/module/customize.sh.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/sh

ui_print "- [I] Checking env..."

if [ -n $KSU ]; then
ui_print "- [D] Su manager is KernelSU."
fi

if [ $ARCH = "arm64" ]; then
continue
else
abort "- [E] Unsupported arch: $ARCH."
fi

if [ $API -ge 30 ]; then
continue
else
ui_print "- [W] Func memfd_create() required API 30(R)."
fi

ui_print "- [D] Fetching download link..."

DOWNLOAD_URLS=$(curl -s https://api.github.com/repos/Container-On-Android/lxc/releases/latest | grep browser_download_url | cut -d'"' -f4 | grep -E 'gz$')

URL_LXC=$(echo "$DOWNLOAD_URLS" | sed -n '1p')
URL_SYSROOT=$(echo "$DOWNLOAD_URLS" | sed -n '2p')

if [ -z $URL_LXC ] && [ -z $URL_SHARE ]; then
abort "- [E] Error: URL_LXC: $URL_LXC URL_SHARE: $URL_SHARE."
else
ui_print "- [D] Fetch ok..."
fi

ui_print "- [I] Downloading lxc..."

wget -q $URL_LXC -O /data/local/tmp/lxc.tar.gz

if [ $? -eq 0 ]; then
ui_print "- [I] Download lxc ok..."
else
rm /data/local/tmp/lxc.tar.gz
abort "- [E] Failed to download lxc. ($URL_LXC)"
fi

ui_print "- [I] Downloading lxc-sysroot..."

wget -q $URL_SYSROOT -O /data/local/tmp/lxc-sysroot.tar.gz

if [ $? -eq 0 ]; then
ui_print "- [D] Download lxc-sysroot ok..."
else
rm /data/local/tmp/lxc-sysroot.tar.gz
abort "- [E] Failed to download lxc-sysroot. ($URL_SYSROOT)"
fi

ui_print "- [I] Installing lxc..."
mkdir -p @PREFIXDIR@
mkdir -p /data/sysroot
tar zxf /data/local/tmp/lxc.tar.gz -C @PREFIXDIR@
tar zxf /data/local/tmp/lxc-sysroot.tar.gz -C /data/sysroot
ui_print "- [I] OK!"

ui_print "- [I] Clean!"
rm /data/local/tmp/lxc.tar.gz
rm /data/local/tmp/lxc-sysroot.tar.gz
Loading