commit 3e4d53d9d38758dc0824600a3265ad356667677c Author: William Petit Date: Fri Feb 3 16:40:47 2023 +0100 feat: initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e46366d --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/tmp +/imagebuilder +/packages +/packages.zip +/bin +/tools +/gitea-dl +/files/etc/emissary +/files/usr/local/bin/emissary +/files/var/lib/emissary +/files/usr/share/emissary +/.gitea-release \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..968370a --- /dev/null +++ b/Makefile @@ -0,0 +1,166 @@ +OPENWRT_DEVICE ?= 192.168.1.1 +BACKUP_DATE ?= + +GIT_VERSION := $(shell git describe --always) + +OPENWRT_VERSION ?= 22.03.2 +OPENWRT_TARGET ?= mvebu/cortexa9 +OPENWRT_TARGET_DASHED ?= $(shell echo $(OPENWRT_TARGET) | sed 's|/|-|') +OPENWRT_PROFILE ?= linksys_wrt1200ac +OPENWRT_PACKAGES ?= $(shell cat packages.txt) +EXTRA_IMAGE_NAME ?= emissary-$(GIT_VERSION) +BIN_DIR_NAME_SUFFIX ?= + +IMAGEBUILDER_URL ?= https://downloads.openwrt.org/releases/$(OPENWRT_VERSION)/targets/$(OPENWRT_TARGET)/openwrt-imagebuilder-$(OPENWRT_VERSION)-$(OPENWRT_TARGET_DASHED).Linux-x86_64.tar.xz + +IMAGEBUILDER_ARCHIVE_PATH := tmp/imagebuilder-$(OPENWRT_VERSION)-$(OPENWRT_TARGET_DASHED).tar.xz +IMAGEBUILDER_DIR_PATH := $(PWD)/imagebuilder/$(OPENWRT_VERSION)/$(OPENWRT_TARGET) +IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH := $(IMAGEBUILDER_DIR_PATH)/packages +IMAGEBUILDER_CUSTOM_FILES_DIR_PATH := $(IMAGEBUILDER_DIR_PATH)/files + +BIN_DIR := "$(shell readlink -f bin)/$(OPENWRT_VERSION)/$(OPENWRT_TARGET)/$(OPENWRT_PROFILE)$(BIN_DIR_NAME_SUFFIX)" + +GITEA_DOWNLOAD_RELEASE_NAME ?= latest +EMISSARY_ARCH ?= armv6 + +EMISSARY_RECONCILIATION_INTERVAL ?= +EMISSARY_SERVER_URL ?= + +include targets/*.mk + +all: + +build: $(IMAGEBUILDER_DIR_PATH) $(IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH) $(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH) + # Create artefacts directory + mkdir -p "$(BIN_DIR)" + + # Add local packages to repositories + sed -i -n -e '/^src imagebuilder file:packages/!p' -e '$$asrc imagebuilder file:packages' -e 's/^option check_signature//' "$(IMAGEBUILDER_DIR_PATH)/repositories.conf" + + # Cleanup old packages signature + rm -f $(IMAGEBUILDER_DIR_PATH)/Packages $(IMAGEBUILDER_DIR_PATH)/Packages.gz $(IMAGEBUILDER_DIR_PATH)/Packages.sig + + # Build firmware + $(MAKE) \ + -C "$(IMAGEBUILDER_DIR_PATH)" \ + EXTRA_IMAGE_NAME="$(EXTRA_IMAGE_NAME)" \ + PROFILE="$(OPENWRT_PROFILE)" \ + PACKAGES="$(OPENWRT_PACKAGES)" \ + CONFIG_IPV6=n \ + FILES="$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)" \ + BIN_DIR="$(BIN_DIR)" \ + clean image + +$(IMAGEBUILDER_DIR_PATH): $(IMAGEBUILDER_ARCHIVE_PATH) + mkdir -p "$(IMAGEBUILDER_DIR_PATH)" + tar -xf "$(IMAGEBUILDER_ARCHIVE_PATH)" --strip-components 1 -C "$(IMAGEBUILDER_DIR_PATH)" + +$(IMAGEBUILDER_ARCHIVE_PATH): + mkdir -p $(shell dirname "$(IMAGEBUILDER_ARCHIVE_PATH)") + wget -O "$(IMAGEBUILDER_ARCHIVE_PATH)" "$(IMAGEBUILDER_URL)" + +.PHONY: $(IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH) +$(IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH): + rm -rf "$(IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH)" + mkdir -p packages + ln -fs "$(shell readlink -f packages)" "$(IMAGEBUILDER_CUSTOM_PACKAGES_DIR_PATH)" + +.PHONY: $(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH) +$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH): + rm -rf "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)" + mkdir -p "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/etc" + + echo "# Firmware built with https://forge.cadoles.com/Cadoles/emissary-firmware" > "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/etc/emissary_firmware" + echo "BUILD_DATE=$(shell date --iso-8601=seconds)" >> "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/etc/emissary_firmware" + echo "GIT_VERSION=$(GIT_VERSION)" >> "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/etc/emissary_firmware" + echo "OPENWRT_PROFILE=$(OPENWRT_PROFILE)" >> "$(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/etc/emissary_firmware" + + $(MAKE) copy-emissary-files + + cp -rf files/* $(IMAGEBUILDER_CUSTOM_FILES_DIR_PATH)/ + +flash: + OPENWRT_DEVICE=$(OPENWRT_DEVICE) OPENWRT_PROFILE=$(OPENWRT_PROFILE) OPENWRT_VERSION=$(OPENWRT_VERSION) misc/script/flash.sh + +restore: + OPENWRT_DEVICE=$(OPENWRT_DEVICE) BACKUP_DATE=$(BACKUP_DATE) misc/script/restore.sh + +gitea-release: tools/gitea-release/bin/gitea-release.sh + mkdir -p .gitea-release + rm -rf .gitea-release/* + + find bin \ + \( -name '*.img.gz' \ + -or -name '*.bin' \ + -or -name '*.img' \ + \) -exec cp {} .gitea-release/ \; + + GITEA_RELEASE_PROJECT="emissary-firmware" \ + GITEA_RELEASE_ORG="arcad" \ + GITEA_RELEASE_BASE_URL="https://forge.cadoles.com" \ + GITEA_RELEASE_VERSION="$(GIT_VERSION)" \ + GITEA_RELEASE_NAME="$(GIT_VERSION)" \ + GITEA_RELEASE_COMMITISH_TARGET="$(GIT_VERSION)" \ + GITEA_RELEASE_IS_DRAFT="false" \ + GITEA_RELEASE_BODY="" \ + GITEA_RELEASE_ATTACHMENTS="$(shell find .gitea-release/* -type f)" \ + tools/gitea-release/bin/gitea-release.sh + +.PHONY: download-emissary-release +download-emissary-release: tools/gitea-download/bin/gitea-download.sh + rm -rf gitea-dl + GITEA_DOWNLOAD_PROJECT="emissary" \ + GITEA_DOWNLOAD_ORG="arcad" \ + GITEA_DOWNLOAD_BASE_URL="https://forge.cadoles.com" \ + GITEA_DOWNLOAD_RELEASE_NAME="$(GITEA_DOWNLOAD_RELEASE_NAME)" \ + tools/gitea-download/bin/gitea-download.sh + +.PHONY: copy-emissary-files +copy-emissary-files: download-emissary-release tools/yq/bin/yq tools/upx/bin/upx + mkdir -p gitea-dl/emissary-agent_linux_$(EMISSARY_ARCH) + cd gitea-dl && tar -xzf emissary-agent_*_linux_$(EMISSARY_ARCH).tar.gz -C emissary-agent_linux_$(EMISSARY_ARCH) + + # Copy agent config + mkdir -p files/etc/emissary + cp gitea-dl/emissary-agent_linux_$(EMISSARY_ARCH)/misc/packaging/common/config-agent.yml files/etc/emissary/agent.yml + + # Patch agent config + tools/yq/bin/yq -i '.agent.controllers.spec.serverUrl = "$${EMISSARY_SERVER_URL}"' files/etc/emissary/agent.yml + tools/yq/bin/yq -i '.agent.reconciliationInterval = "$${EMISSARY_RECONCILIATION_INTERVAL}"' files/etc/emissary/agent.yml + + # Copy emissary binary + mkdir -p files/usr/local/bin + cp gitea-dl/emissary-agent_linux_$(EMISSARY_ARCH)/emissary files/usr/local/bin/emissary + chmod +x files/usr/local/bin/emissary + + # Set defaults + mkdir -p files/etc/emissary + rm -rf files/etc/emissary/default.conf + echo "EMISSARY_RECONCILIATION_INTERVAL='$(EMISSARY_RECONCILIATION_INTERVAL)'" > files/etc/emissary/default.conf + echo "EMISSARY_SERVER_URL='$(EMISSARY_SERVER_URL)'" >> files/etc/emissary/default.conf + + # Compress emissary binary + tools/upx/bin/upx -9 files/usr/local/bin/emissary + +tools/gitea-release/bin/gitea-release.sh: + mkdir -p tools/gitea-release/bin + curl --output tools/gitea-release/bin/gitea-release.sh https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/gitea/gitea-release.sh + chmod +x tools/gitea-release/bin/gitea-release.sh + +tools/gitea-download/bin/gitea-download.sh: + mkdir -p tools/gitea-download/bin + curl --output tools/gitea-download/bin/gitea-download.sh https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/gitea/gitea-download.sh + chmod +x tools/gitea-download/bin/gitea-download.sh + +tools/yq/bin/yq: + mkdir -p tools/yq/bin + curl -L --output tools/yq/bin/yq https://github.com/mikefarah/yq/releases/download/v4.31.1/yq_linux_amd64 + chmod +x tools/yq/bin/yq + +UPX_VERSION := 4.0.2 + +tools/upx/bin/upx: + mkdir -p tools/upx/bin + curl -L --output tools/upx/upx-$(UPX_VERSION)-amd64_linux.tar.xz https://github.com/upx/upx/releases/download/v$(UPX_VERSION)/upx-$(UPX_VERSION)-amd64_linux.tar.xz + cd tools/upx && tar -xJf upx-$(UPX_VERSION)-amd64_linux.tar.xz + ln -s $(shell readlink -f tools/upx/upx-$(UPX_VERSION)-amd64_linux/upx) tools/upx/bin/upx \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..266bbd9 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Emissary - Firmware + +Recette de construction de firmwares OpenWRT personnalisés intégrant les binaires Emissary. + +## Documentation + +[Voir `doc/`](./doc/README.md) \ No newline at end of file diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000..f1f0c91 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,6 @@ +# Documentation + +## Tutoriels + +- [Compiler un firmware](./tutorials/firmware-compilation.md) +- [Flasher une borne](./tutorials/device-flashing.md) \ No newline at end of file diff --git a/doc/tutorials/device-flashing.md b/doc/tutorials/device-flashing.md new file mode 100644 index 0000000..d71947c --- /dev/null +++ b/doc/tutorials/device-flashing.md @@ -0,0 +1,9 @@ +# Flasher une borne + +```shell +# Construire le firmware +make + +# Flasher la borne avec le firmware correspondant à son modèle +make OPENWRT_DEVICE= OPENWRT_PROFILE= flash +``` \ No newline at end of file diff --git a/doc/tutorials/firmware-compilation.md b/doc/tutorials/firmware-compilation.md new file mode 100644 index 0000000..7599023 --- /dev/null +++ b/doc/tutorials/firmware-compilation.md @@ -0,0 +1,16 @@ +# Compiler un firmware + +> TODO + +```shell +# Exemple: construire un firmware OpenWRT + +# Pour le routeur Linksys WRT1200AC +make linksys-wrt1200ac + +# Pour le routeur Linksys WRT1900AC +make linksys-wrt1900ac + +# Pourt le router Linksys WRT3200ACM +make linksys-wrt3200acm +``` \ No newline at end of file diff --git a/files/etc/config/emissary b/files/etc/config/emissary new file mode 100644 index 0000000..a262cc9 --- /dev/null +++ b/files/etc/config/emissary @@ -0,0 +1,5 @@ +package emissary + +config main 'agent' + option reconciliation_interval '60' + option server_url 'https://emissary.cadol.es' \ No newline at end of file diff --git a/files/etc/init.d/emissary-agent b/files/etc/init.d/emissary-agent new file mode 100755 index 0000000..4a8c176 --- /dev/null +++ b/files/etc/init.d/emissary-agent @@ -0,0 +1,35 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=50 +STOP=50 + +start_service() { + config_load emissary + + mkdir -p /usr/share/emissary + mkdir -p /var/lib/emissary + + config_get emissary_reconciliation_interval agent 'reconciliation_interval' "60" + config_get emissary_server_url agent 'server_url' "https://emissary.cadol.es" + + local config_file="/etc/emissary/agent.yml" + procd_open_instance emissary-agent + procd_set_param env EMISSARY_SERVER_URL="$emissary_server_url" EMISSARY_RECONCILIATION_INTERVAL="$emissary_reconciliation_interval" + procd_set_param command /usr/local/bin/emissary + procd_append_param command --workdir /usr/share/emissary + procd_append_param command --config "$config_file" + procd_append_param command agent run + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} + procd_set_param file "$config_file" + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_set_param pidfile /var/run/emissary-agent.pid + procd_close_instance +} + +service_triggers() +{ + # Reload service (restart) on emissary config changes + procd_add_reload_trigger "emissary" +} \ No newline at end of file diff --git a/files/etc/uci-defaults/99-emissary.sh b/files/etc/uci-defaults/99-emissary.sh new file mode 100644 index 0000000..88917b3 --- /dev/null +++ b/files/etc/uci-defaults/99-emissary.sh @@ -0,0 +1,30 @@ +#/bin/sh + +set -e + +main() { + local default_config="/etc/emissary/default.conf" + + if [ ! -f "${default_config}" ]; then + exit 0 + fi + + source "${default_config}" + + if [ ! -z "${EMISSARY_RECONCILIATION_INTERVAL}" ]; then + uci set "emissary.agent.reconciliation_interval=${EMISSARY_RECONCILIATION_INTERVAL}" + fi + if [ ! -z "${EMISSARY_SERVER_URL}" ]; then + uci set "emissary.agent.server_url=${EMISSARY_SERVER_URL}" + fi + + # Commit modifications + uci commit + + # Delete file + rm -f "${default_config}" + + /etc/init.d/emissary-agent enable +} + +main \ No newline at end of file diff --git a/files/etc/uci-defaults/99-machine-id.sh b/files/etc/uci-defaults/99-machine-id.sh new file mode 100755 index 0000000..28e0489 --- /dev/null +++ b/files/etc/uci-defaults/99-machine-id.sh @@ -0,0 +1,24 @@ +#/bin/sh + +set -e + +main() { + local machine_id_file="/etc/machine-id" + + if [ -f "$machine_id_file" ]; then + echo "Machine ID already generated. Doing nothing." + exit 0 + fi + + # Accumulate data to create unique machine id + local mac_addresses=$(cat /sys/class/net/*/address | uniq | sort) + local device_model=$(cat /sys/firmware/devicetree/base/model) + + # Ensure destination directory + mkdir -p "$(dirname "$machine_id_file")" + + # Generate SHA256 hash of data and save it to $machine_id_file + echo "$mac_adresses $device_model" | sha256sum | cut -d ' ' -f1 > "$machine_id_file" +} + +main \ No newline at end of file diff --git a/misc/script/flash.sh b/misc/script/flash.sh new file mode 100755 index 0000000..cf4a715 --- /dev/null +++ b/misc/script/flash.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -xeo pipefail + +ssh-copy-id root@${OPENWRT_DEVICE} + +TARGET_ARCH=$(ssh root@${OPENWRT_DEVICE} source /etc/os-release \&\& echo \${OPENWRT_BOARD:-\$LEDE_BOARD}) + +FIRMWARE_FILE=bin/${OPENWRT_VERSION}/${TARGET_ARCH}/${OPENWRT_PROFILE}/openwrt-*-squashfs-factory.img +FIRMWARE_FILE=${CUSTOM_FIRMWARE_FILE:-$FIRMWARE_FILE} + +NOW=$(date +%Y-%m-%d) +BACKUP_FILENAME="backup_${OPENWRT_DEVICE}_${NOW}.tar.gz" + +ssh root@${OPENWRT_DEVICE} \ + rm -f "/tmp/${BACKUP_FILENAME}" \ + \&\& sysupgrade -b "/tmp/${BACKUP_FILENAME}" + +mkdir -p tmp/backups + +scp "root@${OPENWRT_DEVICE}:/tmp/${BACKUP_FILENAME}" ./tmp/backups/ + +ssh root@${OPENWRT_DEVICE} \ + mkdir -p /tmp/firmwares \ + \&\& rm /tmp/firmwares/* \|\| exit 0; + +scp $FIRMWARE_FILE root@${OPENWRT_DEVICE}:/tmp/firmwares/ + +ssh root@${OPENWRT_DEVICE} sysupgrade --force -p -v -n "/tmp/firmwares/$(basename $FIRMWARE_FILE)" \ No newline at end of file diff --git a/misc/script/restore.sh b/misc/script/restore.sh new file mode 100755 index 0000000..f4cdb9e --- /dev/null +++ b/misc/script/restore.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -o pipefail + +NOW=$(date +%Y-%m-%d) +BACKUP_DATE=${BACKUP_DATE:-${NOW}} +BACKUP_FILENAME="backup_${OPENWRT_DEVICE}_${NOW}.tar.gz" + +printf "%s" "Waiting for ${OPENWRT_DEVICE} ..." +while ! ping -c 1 -n -w 1 ${OPENWRT_DEVICE} &> /dev/null +do + printf "%c" "." +done +printf "\n%s\n" "Server is back online" + +scp "./tmp/backups/${BACKUP_FILENAME}" root@${OPENWRT_DEVICE}:/tmp/ + +ssh root@${OPENWRT_DEVICE} sysupgrade -r "/tmp/${BACKUP_FILENAME}" \ No newline at end of file diff --git a/packages.txt b/packages.txt new file mode 100644 index 0000000..9fe1252 --- /dev/null +++ b/packages.txt @@ -0,0 +1,3 @@ +luci +openssh-server +openssh-sftp-server \ No newline at end of file diff --git a/targets/linksys-wrtXXXXac.mk b/targets/linksys-wrtXXXXac.mk new file mode 100644 index 0000000..a744c64 --- /dev/null +++ b/targets/linksys-wrtXXXXac.mk @@ -0,0 +1,12 @@ +all: linksys-wrtXXXXac + +linksys-wrtXXXXac: linksys-wrt1200ac linksys-wrt1900ac linksys-wrt3200acm + +linksys-wrt1200ac: + $(MAKE) OPENWRT_TARGET="mvebu/cortexa9" EMISSARY_ARCH="armv6" OPENWRT_PROFILE="linksys_wrt1200ac" build + +linksys-wrt1900ac: + $(MAKE) OPENWRT_TARGET="mvebu/cortexa9" EMISSARY_ARCH="armv6" OPENWRT_PROFILE="linksys_wrt1900ac-v2" build + +linksys-wrt3200acm: + $(MAKE) OPENWRT_TARGET="mvebu/cortexa9" EMISSARY_ARCH="armv6" OPENWRT_PROFILE="linksys_wrt3200acm" build \ No newline at end of file diff --git a/targets/x86_generic.mk b/targets/x86_generic.mk new file mode 100644 index 0000000..938f20d --- /dev/null +++ b/targets/x86_generic.mk @@ -0,0 +1,18 @@ +all: x86_generic + +x86_generic: + $(MAKE) OPENWRT_TARGET="x86/generic" EMISSARY_ARCH="386" OPENWRT_PROFILE="generic" build + +run_x86_generic: bin/$(OPENWRT_VERSION)/x86/generic/generic/openwrt-$(OPENWRT_VERSION)-emissary-*-ext4-combined.img + qemu-system-x86_64 \ + -enable-kvm \ + -nographic \ + -drive file=$(shell ls bin/$(OPENWRT_VERSION)/x86/generic/generic/openwrt-$(OPENWRT_VERSION)-emissary-*-ext4-combined.img),id=d0,if=none \ + -device ide-hd,drive=d0,bus=ide.0 \ + -netdev bridge,br=virbr0,id=hn0 \ + -device e1000,netdev=hn0,id=nic1 \ + -netdev user,id=hn1 \ + -device e1000,netdev=hn1,id=nic2 + +bin/$(OPENWRT_VERSION)/x86/generic/generic/openwrt-$(OPENWRT_VERSION)-emissary-*-ext4-combined.img: + gunzip bin/$(OPENWRT_VERSION)/x86/generic/generic/openwrt-$(OPENWRT_VERSION)-emissary-*-ext4-combined.img.gz || exit 0