2
0
mirror of https://github.com/xcat2/confluent.git synced 2025-03-03 17:51:00 +00:00

Provide internal URL shortening service

Permit users to have very long profile names, and provide
a URL shortening service to bridge the gap for fixed-width
field limitations in DHCP/PXE.
This commit is contained in:
Jarrod Johnson 2025-01-22 15:44:49 -05:00
parent 2f33aa5d83
commit e3d70f351d
2 changed files with 46 additions and 13 deletions

View File

@ -22,6 +22,7 @@
# option 97 = UUID (wireformat)
import base64
import confluent.config.configmanager as cfm
import confluent.collective.manager as collective
import confluent.noderange as noderange
@ -35,6 +36,7 @@ import eventlet
import eventlet.green.socket as socket
import eventlet.green.select as select
import netifaces
import os
import struct
import time
import traceback
@ -165,6 +167,18 @@ pxearchs = {
}
shorturls = {}
def register_shorturl(url):
urlid = base64.urlsafe_b64encode(os.urandom(3))
while urlid in shorturls:
urlid = base64.urlsafe_b64encode(os.urandom(3))
urlid = urlid.decode()
shorturls[urlid] = url
returl = '/'.join(url.split('/')[:3])
returl += '/confluent-api/boot/su/' + urlid + '/' + os.path.basename(url)
return returl
uuidmap = {}
macmap = {}
attribwatcher = None
@ -369,12 +383,15 @@ def proxydhcp(handler, nodeguess):
elif disco['arch'] == 'uefi-aarch64':
bootfile = b'confluent/aarch64/ipxe.efi'
if len(bootfile) > 127:
log.log(
{'info': 'Boot offer cannot be made to {0} as the '
'profile name "{1}" is {2} characters longer than is supported '
'for this boot method.'.format(
node, profile, len(bootfile) - 127)})
continue
if bootfile.startswith(b'http'):
bootfile = register_shorturl(bootfile.decode('utf8')).encode('utf8')
else:
log.log(
{'info': 'Boot offer cannot be made to {0} as the '
'profile name "{1}" is {2} characters longer than is supported '
'for this boot method.'.format(
node, profile, len(bootfile) - 127)})
continue
rpv[:240] = rqv[:240].tobytes()
rpv[0:1] = b'\x02'
rpv[108:108 + len(bootfile)] = bootfile
@ -797,12 +814,15 @@ def reply_dhcp4(node, info, packet, cfg, reqview, httpboot, cfd, profile, sock=N
if not isinstance(bootfile, bytes):
bootfile = bootfile.encode('utf8')
if len(bootfile) > 127:
log.log(
{'info': 'Boot offer cannot be made to {0} as the '
'profile name "{1}" is {2} characters longer than is supported '
'for this boot method.'.format(
node, profile, len(bootfile) - 127)})
return
if bootfile.startswith(b'http'):
bootfile = register_shorturl(bootfile.decode('utf8')).encode('utf8')
else:
log.log(
{'info': 'Boot offer cannot be made to {0} as the '
'profile name "{1}" is {2} characters longer than is supported '
'for this boot method.'.format(
node, profile, len(bootfile) - 127)})
return
repview[108:108 + len(bootfile)] = bootfile
elif info.get('architecture', None) == 'uefi-aarch64' and packet.get(77, None) == b'iPXE':
if not profile:

View File

@ -30,6 +30,7 @@ import confluent.config.attributes as attribs
import confluent.config.configmanager as configmanager
import confluent.consoleserver as consoleserver
import confluent.discovery.core as disco
import confluent.discovery.protocols.pxe as pxe
import confluent.forwarder as forwarder
import confluent.exceptions as exc
import confluent.log as log
@ -640,6 +641,8 @@ def resourcehandler(env, start_response):
yield '500 - ' + str(e)
return
def resourcehandler_backend(env, start_response):
"""Function to handle new wsgi requests
"""
@ -648,7 +651,7 @@ def resourcehandler_backend(env, start_response):
('Pragma', 'no-cache'),
('X-Content-Type-Options', 'nosniff'),
('Content-Security-Policy', "default-src 'self'"),
('X-XSS-Protection', '1; mode=block'), ('X-Frame-Options', 'deny'),
('X-XySS-Protection', '1; mode=block'), ('X-Frame-Options', 'deny'),
('Strict-Transport-Security', 'max-age=86400'),
('X-Permitted-Cross-Domain-Policies', 'none')]
reqbody = None
@ -671,6 +674,16 @@ def resourcehandler_backend(env, start_response):
request = env['PATH_INFO'].split('/')
if not request[0]:
request = request[1:]
if request[1] == 'su': # shorturl
targurl = pxe.shorturls.get(request[2], None)
if not targurl:
start_response('404 Not Found', headers)
yield ''
return
headers.append(('Location', targurl))
start_response('302 Found', headers)
yield ''
return
if len(request) != 4:
start_response('400 Bad Request', headers)
yield ''