Created
October 20, 2024 16:53
-
-
Save AdamsGH/d145a3249e3d5b708a9fe1796b865889 to your computer and use it in GitHub Desktop.
Automated installation and configuration of AmneziaWG for OpenWRT
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Colors | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[0;33m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# Function to print colored output | |
print_color() { | |
local color=$1 | |
shift | |
echo -e "${color}$@${NC}" | |
} | |
# Function to display usage information | |
show_usage() { | |
print_color $BLUE "Usage: $0 <path_to_cfg_file> [interface_name] [peer_description] [zone] [-t|--test-route]" | |
print_color $BLUE "Options:" | |
print_color $BLUE " -t, --test-route Create a test route to 49.12.234.183" | |
exit 1 | |
} | |
# Function to get parameter from config file | |
get_param() { | |
sed -n "/$1/{s/^[^=]*=//; s/^[[:space:]]*//; s/[[:space:]]*$//; p}" "$cfg_file" | |
} | |
# Function to add or update network interface | |
configure_interface() { | |
if ! uci show network | grep -q "network.${interface_name}=interface"; then | |
uci batch << EOI | |
set network.${interface_name}=interface | |
set network.${interface_name}.proto='amneziawg' | |
set network.${interface_name}.private_key='$(get_param 'PrivateKey')' | |
set network.${interface_name}.addresses='$(get_param 'Address')' | |
set network.${interface_name}.force_link='1' | |
set network.${interface_name}.delegate='0' | |
set network.${interface_name}.dns='$(get_param 'DNS' | tr ',' ' ')' | |
set network.${interface_name}.awg_jc='$(get_param 'Jc')' | |
set network.${interface_name}.awg_jmin='$(get_param 'Jmin')' | |
set network.${interface_name}.awg_jmax='$(get_param 'Jmax')' | |
set network.${interface_name}.awg_h1='$(get_param 'H1')' | |
set network.${interface_name}.awg_h2='$(get_param 'H2')' | |
set network.${interface_name}.awg_h3='$(get_param 'H3')' | |
set network.${interface_name}.awg_h4='$(get_param 'H4')' | |
EOI | |
print_color $GREEN "Interface ${interface_name} created." | |
else | |
print_color $YELLOW "Interface ${interface_name} already exists." | |
fi | |
} | |
# Function to add or update peer | |
configure_peer() { | |
local peer_exists=false | |
local peer_section="" | |
# Check if peer already exists | |
for peer in $(uci show network | grep "network.@amneziawg_${interface_name}\[" | cut -d. -f2 | cut -d= -f1); do | |
if [ "$(uci get network.${peer}.description)" = "${peer_description}" ]; then | |
peer_exists=true | |
peer_section="${peer}" | |
break | |
fi | |
done | |
local allowed_ips=$(get_param 'AllowedIPs') | |
IFS=',' read -ra ips <<< "$allowed_ips" | |
if [ "$peer_exists" = false ]; then | |
peer_section=$(uci add network amneziawg_${interface_name}) | |
uci batch << EOI | |
set network.${peer_section}.description='${peer_description}' | |
set network.${peer_section}.public_key='$(get_param 'PublicKey')' | |
set network.${peer_section}.route_allowed_ips='0' | |
set network.${peer_section}.persistent_keepalive='25' | |
set network.${peer_section}.endpoint_host='$(get_param 'Endpoint' | cut -d':' -f1)' | |
set network.${peer_section}.endpoint_port='$(get_param 'Endpoint' | cut -d':' -f2)' | |
set network.${peer_section}.persistent_keepalive='60' | |
EOI | |
print_color $GREEN "Peer ${peer_description} added to interface ${interface_name}." | |
else | |
uci batch << EOI | |
set network.${peer_section}.public_key='$(get_param 'PublicKey')' | |
set network.${peer_section}.endpoint_host='$(get_param 'Endpoint' | cut -d':' -f1)' | |
set network.${peer_section}.endpoint_port='$(get_param 'Endpoint' | cut -d':' -f2)' | |
set network.${peer_section}.persistent_keepalive='60' | |
delete network.${peer_section}.allowed_ips | |
EOI | |
print_color $YELLOW "Peer ${peer_description} updated in interface ${interface_name}." | |
fi | |
# Add allowed IPs | |
for ip in "${ips[@]}"; do | |
uci add_list network.${peer_section}.allowed_ips="${ip//[[:space:]]/}" | |
done | |
} | |
# Function to configure firewall | |
configure_firewall() { | |
print_color $BLUE "Configuring firewall..." | |
# Create or update the zone for the new interface | |
zone_config=$(uci show firewall | grep "@zone\[.*\].name='${zone_name}'") | |
if [ -z "$zone_config" ]; then | |
# Create new zone | |
new_zone=$(uci add firewall zone) | |
uci batch << EOI | |
set firewall.$new_zone.name='${zone_name}' | |
set firewall.$new_zone.input='REJECT' | |
set firewall.$new_zone.output='ACCEPT' | |
set firewall.$new_zone.forward='REJECT' | |
set firewall.$new_zone.masq='1' | |
set firewall.$new_zone.mtu_fix='1' | |
set firewall.$new_zone.network='${interface_name}' | |
EOI | |
print_color $GREEN "Created new firewall zone ${zone_name} for interface ${interface_name}." | |
else | |
# Update existing zone | |
existing_zone=$(echo "$zone_config" | cut -d. -f2 | cut -d= -f1) | |
uci set firewall.$existing_zone.network="${interface_name}" | |
print_color $YELLOW "Updated existing firewall zone ${zone_name} with interface ${interface_name}." | |
fi | |
# Remove all existing forwarding rules for this zone | |
existing_forwards=$(uci show firewall | grep "@forwarding\[[0-9]\+\]" | grep "\.dest='${zone_name}'") | |
if [ -n "$existing_forwards" ]; then | |
print_color $YELLOW "Removing existing forwarding rules for ${zone_name}..." | |
echo "$existing_forwards" | while read -r line; do | |
section=$(echo "$line" | cut -d. -f2 | cut -d= -f1) | |
uci delete firewall.$section | |
done | |
fi | |
# Add a single new forwarding rule | |
new_forward=$(uci add firewall forwarding) | |
uci set firewall.$new_forward.src='lan' | |
uci set firewall.$new_forward.dest="${zone_name}" | |
print_color $GREEN "Added new forwarding rule from LAN to ${zone_name}." | |
print_color $GREEN "Firewall settings for ${zone_name} zone have been configured." | |
} | |
# Function to create test route | |
create_test_route() { | |
local address=$(get_param 'Address') | |
local gateway=$(echo $address | awk -F'[./]' '{print $1"."$2"."$3".1"}') | |
uci batch << EOI | |
set network.test_route=route | |
set network.test_route.interface='${interface_name}' | |
set network.test_route.target='49.12.234.183/32' | |
set network.test_route.gateway='${gateway}' | |
EOI | |
print_color $GREEN "Test route created:" | |
print_color $BLUE " Target: 49.12.234.183/32" | |
print_color $BLUE " Gateway: ${gateway}" | |
print_color $BLUE " Interface: ${interface_name}" | |
print_color $YELLOW "You can test the connection using: ${NC}curl 49.12.234.183" | |
} | |
# Main execution | |
# Parse command line arguments | |
CREATE_TEST_ROUTE=false | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-t|--test-route) | |
CREATE_TEST_ROUTE=true | |
shift | |
;; | |
-h|--help) | |
show_usage | |
;; | |
*) | |
if [ -z "$cfg_file" ]; then | |
cfg_file="$1" | |
elif [ -z "$interface_name" ]; then | |
interface_name="$1" | |
elif [ -z "$peer_description" ]; then | |
peer_description="$1" | |
elif [ -z "$zone_name" ]; then | |
zone_name="$1" | |
else | |
print_color $RED "Unknown argument: $1" | |
show_usage | |
fi | |
shift | |
;; | |
esac | |
done | |
# Check for minimum required arguments | |
[ -z "$cfg_file" ] && show_usage | |
# Set default values if not provided | |
interface_name="${interface_name:-AWG}" | |
peer_description="${peer_description:-openwrt_router}" | |
zone_name="${zone_name:-awg}" | |
print_color $BLUE "Starting Amnezia WireGuard setup..." | |
configure_interface | |
configure_peer | |
uci commit network | |
configure_firewall | |
uci commit firewall | |
if [ "$CREATE_TEST_ROUTE" = true ]; then | |
create_test_route | |
uci commit network | |
fi | |
print_color $YELLOW "Restarting network..." | |
/etc/init.d/network restart | |
print_color $GREEN "Amnezia WireGuard setup completed." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Colors | |
RED='\033[0;31m' | |
GREEN='\033[0;32m' | |
YELLOW='\033[0;33m' | |
BLUE='\033[0;34m' | |
NC='\033[0m' # No Color | |
# Function to print colored output | |
print_color() { | |
local color=$1 | |
shift | |
echo -e "${color}$@${NC}" | |
} | |
# Function to get release info | |
get_release_info() { | |
curl -s "https://api.github.com/repos/Slava-Shchipunov/awg-openwrt/releases/latest" | |
} | |
# Function to extract version from release info | |
get_latest_version() { | |
echo "$1" | grep -o '"tag_name": "v[^"]*"' | sed 's/"tag_name": "v//;s/"//' | |
} | |
# Function to get available files | |
get_available_files() { | |
echo "$1" | grep -o '"browser_download_url": "[^"]*\.ipk"' | sed 's/"browser_download_url": "//;s/"//' | |
} | |
# Function to get all architecture groups and their options | |
get_all_arch_groups_and_options() { | |
echo "$AVAILABLE_FILES" | | |
sed -E 's/.*_v[^_]*_//; s/\.ipk$//' | | |
sort -u | | |
awk -F'_' '{ | |
group = $1; | |
option = $2; | |
for(i=3; i<=NF; i++) option = option "_" $i; | |
if(option == "") option = "generic"; | |
if(group == "x86" && option ~ /^64/) { | |
print group "|64"; | |
} else { | |
print group "|" option; | |
} | |
}' | | |
sort -t'|' -k1,1 -k2,2 | | |
uniq | |
} | |
# Function to print groups and options | |
print_groups_and_options() { | |
local current_group="" | |
while IFS='|' read -r group option; do | |
if [ "$group" != "$current_group" ]; then | |
if [ -n "$current_group" ]; then | |
echo | |
fi | |
print_color $YELLOW "Group: $group" | |
current_group="$group" | |
fi | |
if [ "$group" = "x86" ] && [ "$option" = "64" ]; then | |
echo " 64" | |
else | |
echo " $option" | |
fi | |
done | |
} | |
# Function to get all architecture groups | |
get_all_arch_groups() { | |
echo "$AVAILABLE_FILES" | sed -E 's/.*_v[^_]*_([^_]+)(_.*\.ipk|\.ipk)/\1/' | sort -u | |
} | |
# Function to get available options for a group | |
get_options() { | |
local arch_group=$1 | |
echo "$AVAILABLE_FILES" | grep -E "_v${LATEST_VERSION}_${arch_group}" | | |
sed -E "s/.*_v${LATEST_VERSION}_${arch_group}_//; s/\.ipk$//" | | |
sort -u | | |
sed '/^$/d' | |
} | |
# Function to install packages | |
install_packages() { | |
print_color $GREEN "Installing packages..." | |
for package in awg/*.ipk; do | |
if [ -f "$package" ]; then | |
print_color $BLUE "Installing $package" | |
opkg install "$package" | |
if [ $? -eq 0 ]; then | |
print_color $GREEN "Successfully installed $package" | |
else | |
print_color $RED "Failed to install $package" | |
fi | |
fi | |
done | |
} | |
# Function to display usage | |
usage() { | |
print_color $BLUE "Usage: $0 <arch_group> [arch_option] [-i|--install] [-k|--keep]" | |
print_color $BLUE "Example: $0 arm cortex-a9_neon_zynq_generic -i" | |
print_color $BLUE "Or: $0 x86_64 --install --keep" | |
print_color $BLUE "Use '$0 list' to see all available architecture groups and options" | |
print_color $BLUE "Options:" | |
print_color $BLUE " -i, --install Install packages after download" | |
print_color $BLUE " -k, --keep Keep the download directory after installation" | |
} | |
# Main script starts here | |
INSTALL=false | |
KEEP=false | |
ARCH_GROUP="" | |
ARCH_OPTION="" | |
# Parse command line arguments | |
while [[ $# -gt 0 ]]; do | |
case $1 in | |
-i|--install) | |
INSTALL=true | |
shift | |
;; | |
-k|--keep) | |
KEEP=true | |
shift | |
;; | |
list|-h|--help) | |
RELEASE_INFO=$(get_release_info) | |
LATEST_VERSION=$(get_latest_version "$RELEASE_INFO") | |
AVAILABLE_FILES=$(get_available_files "$RELEASE_INFO") | |
print_color $GREEN "Available architecture groups and options:" | |
get_all_arch_groups_and_options | print_groups_and_options | |
exit 0 | |
;; | |
*) | |
if [ -z "$ARCH_GROUP" ]; then | |
ARCH_GROUP="$1" | |
elif [ -z "$ARCH_OPTION" ]; then | |
ARCH_OPTION="$1" | |
else | |
print_color $RED "Unknown argument: $1" | |
usage | |
exit 1 | |
fi | |
shift | |
;; | |
esac | |
done | |
if [ -z "$ARCH_GROUP" ]; then | |
usage | |
exit 1 | |
fi | |
RELEASE_INFO=$(get_release_info) | |
LATEST_VERSION=$(get_latest_version "$RELEASE_INFO") | |
AVAILABLE_FILES=$(get_available_files "$RELEASE_INFO") | |
if [ -z "$LATEST_VERSION" ]; then | |
print_color $RED "Failed to extract version from release info." | |
exit 1 | |
fi | |
print_color $GREEN "Latest version: $LATEST_VERSION" | |
if [ -z "$ARCH_OPTION" ]; then | |
options=$(get_options $ARCH_GROUP) | |
if [ -z "$options" ]; then | |
FULL_ARCH="${ARCH_GROUP}" | |
else | |
print_color $YELLOW "Available options for $ARCH_GROUP:" | |
echo "$options" | |
exit 0 | |
fi | |
else | |
FULL_ARCH="${ARCH_GROUP}_${ARCH_OPTION}" | |
fi | |
# Download files | |
rm -rf awg | |
mkdir -p awg | |
for FILE in amneziawg-tools kmod-amneziawg luci-app-amneziawg; do | |
FULL_FILE=$(echo "$AVAILABLE_FILES" | grep "/${FILE}_v${LATEST_VERSION}_${FULL_ARCH}.ipk$") | |
if [ -n "$FULL_FILE" ]; then | |
OUTPUT_FILE="awg/${FILE}_v${LATEST_VERSION}_${FULL_ARCH}.ipk" | |
if curl -s -L -o "$OUTPUT_FILE" "$FULL_FILE"; then | |
print_color $GREEN "Downloaded: ${FILE}_v${LATEST_VERSION}_${FULL_ARCH}.ipk" | |
else | |
print_color $RED "Failed to download $FILE" | |
fi | |
else | |
print_color $YELLOW "File $FILE for architecture $FULL_ARCH not found" | |
fi | |
done | |
print_color $GREEN "Download completed." | |
if [ "$INSTALL" = true ]; then | |
install_packages | |
if [ "$KEEP" = false ]; then | |
print_color $YELLOW "Removing download directory..." | |
rm -rf awg | |
print_color $GREEN "Download directory removed." | |
fi | |
else | |
print_color $YELLOW "Packages downloaded but not installed. Use -i or --install to install packages." | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment