Last active
August 8, 2022 14:31
-
-
Save jpouellet/57a321becd66d9138c74 to your computer and use it in GitHub Desktop.
Tiny PXE boot server for specific mac address w/ no side effects. (No DHCPNAKs to other hosts.)
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
#!/usr/bin/env python | |
import argparse | |
import struct | |
import logging | |
logging.getLogger('scapy').setLevel(logging.WARNING) | |
from scapy.all import * | |
def packMAC(s): | |
return ''.join([struct.pack('!B', int(x, 16)) for x in s.split(':')]) | |
def pxeboot(iface, mac, ip, tftp_server=None, file=None, netmask=None, gateway=None): | |
server_ip = get_if_addr(iface) | |
server_mac = get_if_hwaddr(iface) | |
client_ip = ip | |
client_mac = mac | |
if tftp_server is None: | |
tftp_server = server_ip | |
if file is None: | |
file = 'pxeboot' | |
def handle_pkt(pkt): | |
# Are we a DHCP packet? | |
try: | |
pkt[DHCP] | |
except: | |
return | |
# Ignore unless from the MAC we care about. | |
if pkt[Ether].src != client_mac: | |
print pkt[Ether].src+': wrong MAC: Ignoring request.' | |
return | |
if pkt[DHCP].options[0][1] == 1: # DHCP Discover | |
print pkt[Ether].src+': got DHCP Discover.' | |
reply_type = 'offer' | |
elif pkt[DHCP].options[0][1] == 3: # DHCP Request | |
print pkt[Ether].src+': got DHCP Request.' | |
reply_type = 'ack' | |
else: | |
print pkt[Ether].src+': unknown DHCP option: Ignoring request.' | |
return # Ignore all others | |
p = Ether(src=server_mac, dst=pkt[Ether].src) | |
p /= IP(src=server_ip, dst=client_ip) | |
p /= UDP(sport=67, dport=68) | |
p /= BOOTP( | |
op=2, | |
yiaddr=client_ip, | |
siaddr=tftp_server, | |
chaddr=packMAC(pkt[Ether].src), | |
file=file, | |
xid=pkt[BOOTP].xid) | |
if gateway is not None: | |
p[BOOTP].giaddr=gateway | |
p /= DHCP(options=[('message-type', reply_type)]) | |
if netmask is not None: | |
p /= DHCP(options=[('subnet_mask', netmask)]) | |
p /= DHCP(options=[('server_id', server_ip), 'end']) | |
sendp(p, verbose=False) | |
print reply_type+' sent' | |
sniff(filter='arp or (udp and (port 67 or 68))', prn=handle_pkt, store=0) | |
parser = argparse.ArgumentParser(description='Whitelisting PXE boot server.') | |
parser.add_argument('interface') | |
parser.add_argument('mac') | |
parser.add_argument('ip') | |
parser.add_argument('-t', '--tftp-server', default=None) | |
parser.add_argument('-f', '--file', default=None) | |
parser.add_argument('-n', '--netmask', default=None) | |
parser.add_argument('-g', '--gateway', default=None) | |
args = parser.parse_args() | |
conf.checkIPaddr = False | |
conf.iface = args.interface | |
# Sniff DHCP requests | |
pxeboot(iface=args.interface, mac=args.mac, ip=args.ip, tftp_server=args.tftp_server, file=args.file, netmask=args.netmask, gateway=args.gateway) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment