#!/usr/bin/env sh # define variables # enable proxychains? proxychains=true # wait for this many seconds before trying certificate issuance/renewal wait_before_renew=30 # bridge46 provider ipv4 address bridge46_ipv4="207.127.103.198" # mesh domain provider provider="mesh.cat" # whoami service whoami_url="https://ygg.mesh.cat/whoami" # mesh domain provider alternative dns port for acme challenge and bridge46 A records alternative_dns_port="53536" # acme challenge dnsmasq instance port acme_challenge_port="53537" # temporary working directory twd="/tmp" # internal function to check if a command exists _exists() { cmd="$1" if [ -z "$cmd" ] ; then echo "Usage: _exists cmd" return 1 fi if type command >/dev/null 2>&1 ; then command -v $cmd >/dev/null 2>&1 else type $cmd >/dev/null 2>&1 fi ret="$?" return $ret } # check if we got wget/curl _get="" _get_is="" if _exists curl && [ "${ACME_USE_WGET:-0}" = "0" ]; then _get="curl -s -L" _get_is="curl" elif _exists wget ; then _get="wget -O -" _get_is="wget" else echo "Sorry, you must have curl or wget installed first." echo "Please install either of them and try again." exit 1 fi # start echo Starting... # check if we got dnsmasq if _exists dnsmasq --help ; then echo "dnsmasq is available." else echo "Sorry, you must have dnsmasq installed first." echo "Please install dnsmasq and try again." exit 1 fi # get my domain domain=`$_get "$whoami_url"` if [ $? -ne 0 ]; then echo "Error: could not fetch my domain." exit 1 fi my_ygg_ip=`$_get "$whoami_url?ip=true"` if [ $? -ne 0 ]; then echo "Error: could not fetch my yggdrasil ip address." exit 1 fi provider_regex=`echo "$provider" | sed 's/\./\\\./g'` domain_regex="^[a-zA-Z0-9]+\\.$provider_regex$" echo $domain_regexp if echo "$domain" | grep -qE "$domain_regex"; then echo "Got domain: $domain" else echo "Error: Received string does not match the expected format." exit 1 fi # define acme.sh's url if [ -z "$BRANCH" ]; then BRANCH="master" fi _url="https://raw.githubusercontent.com/acmesh-official/acme.sh/$BRANCH/acme.sh" # if acme.sh does not exist install it if [ ! -e "$HOME/.acme.sh/acme.sh" ]; then cd $twd $_get "$_url" | sh -s -- --install-online --nocron fi # define acme.sh command acme_cmd="$HOME/.acme.sh/acme.sh --log" if [ "$proxychains" = true ] ; then if _exists proxychains ; then acme_cmd="proxychains -q $acme_cmd" else echo "Error: proxychains enabled but not found." exit 1 fi fi # register zerossl account $acme_cmd \ --register-account \ -m admin@$domain \ --server zerossl # get challenge timestamp=`date +"%Y%m%d%H%M%S"` long_flag="--yes-I-know-dns-manual-mode-enough-go-ahead-please" challenge_file=$twd/acme_challenge.$timestamp.txt $acme_cmd --issue --server letsencrypt \ -d "$domain" \ --dns $long_flag \ > $challenge_file cat $challenge_file echo "" # extract TXT value txt_value=`cat $challenge_file | grep 'TXT' | sed -n "s/.*\x27\(.*\)\x27$/\1/p"` rm $challenge_file if [ $txt_value != "" ] ; then echo TXT value is $txt_value echo "" else echo "Error: could not get an acme challenge TXT string." exit 1 fi tmp_conf_file=$twd/dnsmasq.$USER.tmp.cnf # launch acme challenge dnsmasq process touch $tmp_conf_file \ && dnsmasq \ --conf-file=$tmp_conf_file \ -k -d -D -b -R -n -N -h -q \ -p $acme_challenge_port \ --txt-record="_acme-challenge.$domain,$txt_value" \ 1>&- 2>&- & acme_dnsmasq_pid=$! sleep 3 if [ "`ps aux | grep dnsmasq | grep $acme_dnsmasq_pid`" != "" ]; then echo acme dnsmasq PID: $acme_dnsmasq_pid echo "" else echo "Error: could not start a dnsmasq process for the acme challenge." exit 1 fi # launch main dnsmasq process touch $tmp_conf_file \ && dnsmasq \ --conf-file=$tmp_conf_file \ -k -d -D -b -R -n -N -h -q \ -p $alternative_dns_port \ --address="/$domain/$my_ygg_ip" \ --address="/$domain/$bridge46_ipv4" \ --server="/_acme-challenge.$domain/127.0.0.1#$acme_challenge_port" \ 1>&- 2>&- & main_dnsmasq_pid=$! sleep 3 if [ "`ps aux | grep dnsmasq | grep $main_dnsmasq_pid`" != "" ]; then echo main dnsmasq PID: $main_dnsmasq_pid echo "" fi echo "Waiting for $wait_before_renew seconds." sleep $wait_before_renew # issue certificate $acme_cmd --renew --server letsencrypt \ -d "$domain" \ --dns $long_flag acme_renew_state=$? # kill acme challenge dnsmasq process kill $acme_dnsmasq_pid rm $tmp_conf_file echo "" if [ $acme_renew_state == "0" ]; then echo "Job finished." echo "Remember to create a cron job to run this script once a week." exit 0 else echo "Someething when wrong when trying to get/renew the certificate." exit $acme_renew_state fi