Skip to content

Commit

Permalink
1.0 release
Browse files Browse the repository at this point in the history
1.0 release
  • Loading branch information
yapishu authored Nov 25, 2022
2 parents 934efa2 + 131b7ea commit 043fc9e
Show file tree
Hide file tree
Showing 9 changed files with 264 additions and 55 deletions.
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
wg-push
caddy-push
api-push
*-push
key.pem
64 changes: 64 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
pipeline {
agent any
environment {
reg_pw = credentials('Dockerhub PW')
environ = sh (
script: '''
echo $BRANCH_NAME|sed 's@origin/@@g'
''',
returnStdout: true
).trim()
}
stages {
stage('Build') {
environment {
environ = sh (
script: '''
echo $BRANCH_NAME|sed 's@origin/@@g'
''',
returnStdout: true
).trim()
tag = sh (
script: '''
if [ "${environ}" = "dev" ]; then
echo "staging"
elif [ "${environ}" = "master" ]; then
echo "latest"
else
echo "nobuild"
fi
''',
returnStdout: true
).trim()
}
steps {
script {
if( "${tag}" == "nobuild" ) {
currentBuild.getRawBuild().getExecutor().interrupt(Result.ABORTED)
print("Ignoring branch ${tag}")
sleep(1)
}
}
git url: 'https://github.com/Native-Planet/anchor-source.git',
credentialsId: 'Github token',
branch: "${environ}"
sh "docker login -u nativeplanet -p $reg_pw docker.io"
dir("${env.WORKSPACE}/"){
sh (
script: '''
docker buildx build --push --tag nativeplanet/anchor-api:${tag} --platform linux/amd64 --no-cache ./api/
docker buildx build --push --tag nativeplanet/anchor-wg:${tag} --platform linux/amd64 --no-cache ./wg/
docker buildx build --push --tag nativeplanet/anchor-caddy:${tag} --platform linux/amd64 --no-cache ./caddy/
''',
returnStdout: true
)
}
}
}
}
post {
always {
cleanWs deleteDirs: true, notFailBuild: true
}
}
}
17 changes: 17 additions & 0 deletions api/Nuitka.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM alpine:3.17 AS builder
RUN mkdir /app
WORKDIR /app
# Install dependencies:
RUN apk update && apk add --update musl-dev gcc patchelf python3-dev py3-pip chrpath wget make ccache
RUN pip install nuitka zstandard wheel
COPY requirements.txt /app/requirements.txt
RUN pip install -r /app/requirements.txt

# Build
COPY ./ /app
RUN python3 -m nuitka --onefile app.py

# Clean layer
FROM alpine:3.17
COPY --from=builder /app/app.bin /app/anchor
CMD ["./app/anchor"]
20 changes: 20 additions & 0 deletions api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def retrieve_info():
'pubkey':pubkey,
'status':status,
'subdomains':subdomains,
'ongoing':1,
'lease': np_db.lease}
return jsonify(response),reqstatus

Expand Down Expand Up @@ -164,6 +165,25 @@ def add_anchor():
response = np_db.invalid_fail(subdomain,pubkey,svc_type,validation)
return jsonify(response)

# Route to delete a registered service
@app.route('/v1/delete', methods=['POST'])
def del_svc():

headers = request.headers
content = request.get_json()
fwd_ip = headers.get("X-Forwarded-For")
subdomain = content.get('subdomain').lower()
pubkey = content.get('pubkey')
svc_type = content.get('svc_type').lower()
timestamp = datetime.now()

logging.info(f"\n\n===\n{timestamp}\n{subdomain} {fwd_ip} DELETE\n---\n{content}\n---")

response = np_db.delete_service(subdomain,pubkey,svc_type)
req_code = response['code']
response.pop('code',None)
return jsonify(response),req_code


if __name__ == "__main__":
http_server = WSGIServer(('0.0.0.0', 8090), app)
Expand Down
4 changes: 1 addition & 3 deletions api/caddy_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,7 @@ def check_upstream(sub,upstream):
# If it's pointing at the right upstream
return True
else:
result = False
else:
result = False
return False
except Exception as e:
logging.exception(f'check_upstream: {sub} {upstream} {e}')
return result
Expand Down
70 changes: 67 additions & 3 deletions api/np_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ def check_dns(url):
my_ip = get('https://api.ipify.org').content.decode('utf8')
subdomain_ip = socket.gethostbyname(url)
if subdomain_ip != my_ip:
print(f'''[DNS]\n
Error: please double-check your DNS records!\n
Your host: {my_ip}\n
{url} IP: {subdomain_ip}''')
return False
else:
return True
Expand Down Expand Up @@ -234,7 +238,7 @@ def rectify_svc_list(pubkey):
forwarded = ['urbit-ames']
caddy_conf = caddy_api.get_conf()['apps']['http']['servers']['srv0']['routes']
svc_list, caddy_list = ['anchor'], []
services, minios = {}, {}
services, minios, ameses = {}, {}, {}
peerlist = wg_api.peer_list()
del_peers = []
svcs = get_client_svcs(pubkey)
Expand Down Expand Up @@ -293,7 +297,6 @@ def rectify_svc_list(pubkey):
upstr = services[subd]
if caddy_api.check_upstream(subd,upstr) == False:
caddy_api.add_reverse_proxy(subd, host=f'{root_domain}',upstream=upstr)
sleep(3)

# Delete pubkeys that aren't registered
for peer in peerlist:
Expand All @@ -307,7 +310,6 @@ def rectify_svc_list(pubkey):
upstr = minios[subd]
if caddy_api.check_upstream(subd,upstr) == False:
caddy_api.add_minio(subd, host=f'{root_domain}',upstream=upstr)
sleep(3)

# Rectify port forwarding configurations
# Add a 'tcp' key for TCP services
Expand Down Expand Up @@ -449,6 +451,68 @@ def port_assign(svc):
upd_value('services','status','creating','uid',svc)


# Delete a service for a client
def delete_service(subdomain,pubkey,svc_type):
lease = get_value('anchors','lease','pubkey',pubkey)
response = {'action':'delete',
'debug':None,
'error':0,
'pubkey':pubkey,
'svc_type':svc_type,
'lease':lease,
'subdomain':subdomain,
'code':200}
sub_exists = get_value('services','uid','subdomain',subdomain)
pub_exists = get_value('services','pubkey','subdomain',subdomain)
if sub_exists != False:
if pubkey == pub_exists:
assoc_rows = []
sub_svc = get_value('services','svc_type','uid',sub_exists)
if (sub_svc == 'urbit-web') or (sub_svc == 'urbit-ames'):
service = 'urbit'
assoc_rows.append(sub_exists)
if sub_svc == 'urbit-web':
ames_row = get_value('services','uid','subdomain',f'ames.{subdomain}')
assoc_rows.append(ames_row)
else:
landscape_sub = subdomain.replace('ames.','')
landscape_row = get_value('services','uid','subdomain',landscape_row)
assoc_rows.append(landscape_row)
elif (sub_svc == 'minio') or (sub_svc == 'minio-console') or (sub_svc == 'minio-bucket'):
service = 'minio'
assoc_rows.append(sub_exists)
if sub_svc == 'minio':
console_row = get_value('services','uid','subdomain',f'console.{subdomain}')
bucket_row = get_value('services','uid','subdomain',f'bucket.{subdomain}')
assoc_rows.append(console_row)
append_rows.append(bucket_row)
elif sub_svc == 'minio-console':
minio_sub = subdomain.replace('console.','')
minio_row = get_value('services','uid','subdomain',minio_sub)
bucket_row = get_value('services','uid','subdomain',f'bucket.{minio_sub}')
append_rows.append(minio_row)
append_rows.append(bucket_row)
elif sub_svc == 'minio-bucket':
minio_sub = subdomain.replace('bucket.','')
console_row = get_value('services','uid','subdomain',f'console.{minio_sub}')
minio_row = get_value('services','uid','subdomain',minio_sub)
append_rows.append(console_row)
append_rows.append(minio_row)
if assoc_rows != []:
for svc in assoc_rows:
delete_svc('uid',svc)
threading.Thread(target=rectify_svc_list, name='poll', args=(pubkey,)).start()
else:
response['error'] = 1
response['code'] = 400
response['debug'] = 'Invalid pubkey'
else:
response['error'] = 1
response['code'] = 400
response['debug'] = 'Service is not registered'
return response


# Determine random unused port for service
def port_gen(svc_type):
port_records = get_values('services','port','svc_type',svc_type)
Expand Down
115 changes: 86 additions & 29 deletions api/wg_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,27 @@ def wg_pubkey():
srv_pubkey = wg_pubkey()

# Reset interface
# Restart with preup list, insert predown rules, restart again, remove predown
def restart_wg():
logging.info('[WG]: Restarting interface...')
hook_auth = os.getenv('HOOK_AUTH')
url = f"http://172.20.0.2:9000/hooks/restart-wg?token={hook_auth}"
resp = requests.get(url)
try:
resp = requests.get(url)
msg = resp.content.decode('utf-8')
except Exception as e:
logging.error(f'[WG]: Failed to parse response from webhook {e}')
return False
if resp.status_code == 200:
logging.info('[WG]: WG interface restarted')
remove_predowns()
fwd_predown_rules()
os.system(f'cp {wgconf} {wgconf}.bak')
return True
else:
logging.warn(f'[WG]: Could not restart WG: {resp.status_code}')
title = f'{hosturl} Could not restart IF'
logging.error(f'[WG]: Could not restart WG: {msg}')
sg_api.send_email(title,msg)
return False

# Does this pubkey exist?
Expand Down Expand Up @@ -203,23 +215,6 @@ def rule_gen(rule,ad):
fwd = rule_gen('fwd','A')
contents.insert(index, pre)
contents.insert(index, fwd)
if (pre != False) and (fwd != False):
with open("/etc/wireguard/wg0.conf", "w") as f:
contents = "".join(contents)
f.write(contents)
else:
logging.warning(f'[WG]: Invalid routing rule')
return False
with open("/etc/wireguard/wg0.conf", "r") as f:
contents = f.readlines()
for num, line in enumerate(contents, 1):
# Find the line numbers to insert PreDown rules
if 'PostDown' in line:
index = num - 1
pre = rule_gen('pre','D')
fwd = rule_gen('fwd','D')
contents.insert(index, pre)
contents.insert(index, fwd)
if (pre != False) and (fwd != False):
with open("/etc/wireguard/wg0.conf", "w") as f:
contents = "".join(contents)
Expand All @@ -233,16 +228,30 @@ def rule_gen(rule,ad):
# Remove a forwarding rule from WG conf
def remove_fwd(port):
port = str(port)
logging.info(f'[WG]: Removing port forwarding for {port}')
lookup = f'dport {port}'
with open("/etc/wireguard/wg0.conf","r+") as f:
new_f = f.readlines()
f.seek(0)
for line in new_f:
if lookup not in line:
lookup = f'--dport {port}'
# Remove the PreUp rule
linematch,preups,predowns = [],[],[]
with open(wgconf, "r") as f:
lines = f.readlines()
for line in lines:
if lookup in line:
linematch.append(lines.index(line))
preups = linematch[0:2]
predowns = linematch[2:4]
with open(wgconf, 'w') as f:
for number, line in enumerate(lines):
if number not in preups:
f.write(line)
# Restart after the PreUp rule is removed
# in order to be able to remove PreDown
restart_wg()
# Remove the PreDown rule (no restart)
with open(wgconf, "r") as f:
lines = f.readlines()
with open(wgconf, 'w') as f:
for number, line in enumerate(lines):
if number not in predowns:
f.write(line)
f.truncate()
# You still need to restart the interface

# Return a dict of all existing port forwards
# {tcp:{port:peer,port:peer},udp:{port:peer}}
Expand Down Expand Up @@ -308,4 +317,52 @@ def port_list(port_input):
except Exception as e:
print(e)
logging.warn(f'[WG]: Port fwd rectification: {e}')
return False
return False

# Create PreDown rules after interface restart
# We can't restart it if it has an invalid rule
def fwd_predown_rules():
pres = []
with open(wgconf, "r") as f:
contents = f.readlines()
for num, line in enumerate(contents, 1):
if ("--dport" in line) and ("PreUp" in line):
substr = "PreUp = iptables -A"
replace = "PreDown = iptables -D"
# Create matching PreDown rules
post_rule = line.replace(substr,replace)
# Ignore this in stdout in case it's an unapplied rule
if '&' not in post_rule:
post_rule = post_rule.replace('\n',' &\n')
pres.append(post_rule)
with open(wgconf, "r") as f:
contents = f.readlines()
for num, line in enumerate(contents, 1):
# Find the line numbers to insert PreDown rules
if 'PostDown' in line:
index = num - 1
for rule in pres:
# Append deletion rules if they don't exist
if rule not in contents:
contents.insert(index,rule)
contents = "".join(contents)
with open(wgconf, "w+") as f:
f.write(str(contents))
logging.info(f'fwd_predown_rules(): {contents}')
pred = len(pres)
logging.info(f'[WG]: Inserted {pred} PreDown rules')

# Remove all predown rules (for restart_wg)
def remove_predowns():
with open(wgconf, "r") as f:
lines = f.readlines()
count,keep = 0,[]
for num,line in enumerate(lines):
if 'PreDown' not in line:
keep.append(num)
count += 1
with open(wgconf, 'w') as f:
for num,line in enumerate(lines):
if num in keep:
f.write(line)
return True
Loading

0 comments on commit 043fc9e

Please sign in to comment.