Skip to content

Instantly share code, notes, and snippets.

@jpouellet
Last active August 8, 2022 14:31
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jpouellet/57a321becd66d9138c74 to your computer and use it in GitHub Desktop.
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.)
#!/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