1
1
mirror of https://github.com/eblot/pybootd.git synced 2024-09-11 22:17:44 +03:00

More cleanup and removing old useless stuff

This commit is contained in:
Emmanuel Blot 2019-09-03 19:12:16 +02:00
parent d1231d55c0
commit 02c32b412c
6 changed files with 89 additions and 123 deletions

View File

@ -18,33 +18,8 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os import os
import sys
__version__ = '1.7.0'
def _get_package_name(default='', version='1.6.0'):
try:
from pkg_resources import WorkingSet
except ImportError:
ws = []
else:
ws = WorkingSet()
_path, _ = os.path.split(os.path.dirname(
sys.modules['pybootd'].__file__))
_path = os.path.normpath(_path)
if 'nt' not in os.name:
for dist in ws:
if os.path.samefile(os.path.normpath(dist.location), _path):
return dist.project_name, dist.version
else: # tweak for windows
_path = os.path.abspath(_path).lower()
for dist in ws:
if 'pybootd' in dist.location:
if _path == os.path.abspath(dist.location).lower():
return dist.project_name, dist.version
return default, version
PRODUCT_NAME, __version__ = _get_package_name('pybootd')
def pybootd_path(path): def pybootd_path(path):
@ -61,9 +36,9 @@ def pybootd_path(path):
except ImportError: except ImportError:
raise IOError('pkg_resources module not available') raise IOError('pkg_resources module not available')
try: try:
newpath = resource_filename(Requirement.parse(PRODUCT_NAME), path) newpath = resource_filename(Requirement.parse('pybootd'), path)
if not newpath: if not newpath:
localpath = get_distribution(PRODUCT_NAME).location localpath = get_distribution('pybootd').location
newpath = os.path.join(localpath, path) newpath = os.path.join(localpath, path)
except DistributionNotFound: except DistributionNotFound:
newpath = path newpath = path

View File

@ -24,7 +24,7 @@
from os.path import isfile from os.path import isfile
from threading import Thread from threading import Thread
from sys import exit as sysexit, modules, stderr from sys import exit as sysexit, modules, stderr
from . import pybootd_path, PRODUCT_NAME, __version__ as VERSION from . import pybootd_path, __version__
from .pxed import BootpServer from .pxed import BootpServer
from .tftpd import TftpServer from .tftpd import TftpServer
from .util import logger_factory, EasyConfigParser from .util import logger_factory, EasyConfigParser
@ -94,7 +94,7 @@ def main():
logfile=cfgparser.get('logger', 'file'), logfile=cfgparser.get('logger', 'file'),
level=cfgparser.get('logger', 'level', level=cfgparser.get('logger', 'level',
'info')) 'info'))
logger.info('-'.join((PRODUCT_NAME, VERSION))) logger.info('-'.join(('pybootd', __version__)))
daemon = None daemon = None
if not args.tftp: if not args.tftp:

View File

@ -5,7 +5,8 @@ level = info
[bootp] [bootp]
address = 0.0.0.0 address = 0.0.0.0
; pool_start should be in a valid subnet ; pool_start should be in a valid subnet
pool_start = 192.168.25.100 ; pool_start = 192.168.25.100
pool_start = 10.113.116.245
pool_count = 5 pool_count = 5
domain = localdomain domain = localdomain
server_name = debug server_name = debug

View File

@ -17,15 +17,15 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import re
import select
import socket
import string
import struct
import sys
import time
from binascii import hexlify from binascii import hexlify
from . import PRODUCT_NAME from re import compile as recompile
from select import select
from socket import (inet_aton, inet_ntoa, socket,
AF_INET, SOCK_DGRAM, IPPROTO_UDP, SOL_SOCKET,
SO_BROADCAST, SO_REUSEADDR)
from struct import calcsize as scalc, pack as spack, unpack as sunpack
from time import sleep
from traceback import format_exc
from .util import hexline, to_bool, iptoint, inttoip, get_iface_config from .util import hexline, to_bool, iptoint, inttoip, get_iface_config
BOOTP_PORT_REQUEST = 67 BOOTP_PORT_REQUEST = 67
@ -35,9 +35,9 @@ BOOTREQUEST = 1
BOOTREPLY = 2 BOOTREPLY = 2
BOOTPFORMAT = '!4bIHH4s4s4s4s16s64s128s64s' BOOTPFORMAT = '!4bIHH4s4s4s4s16s64s128s64s'
BOOTPFORMATSIZE = struct.calcsize(BOOTPFORMAT) BOOTPFORMATSIZE = scalc(BOOTPFORMAT)
DHCPFORMAT = '!4bIHH4s4s4s4s16s64s128s4s' DHCPFORMAT = '!4bIHH4s4s4s4s16s64s128s4s'
DHCPFORMATSIZE = struct.calcsize(DHCPFORMAT) DHCPFORMATSIZE = scalc(DHCPFORMAT)
(BOOTP_OP, BOOTP_HTYPE, BOOTP_HLEN, BOOTP_HOPS, BOOTP_XID, BOOTP_SECS, (BOOTP_OP, BOOTP_HTYPE, BOOTP_HLEN, BOOTP_HOPS, BOOTP_XID, BOOTP_SECS,
BOOTP_FLAGS, BOOTP_CIADDR, BOOTP_YIADDR, BOOTP_SIADDR, BOOTP_GIADDR, BOOTP_FLAGS, BOOTP_CIADDR, BOOTP_YIADDR, BOOTP_SIADDR, BOOTP_GIADDR,
@ -177,9 +177,7 @@ class BootpServer:
self.ippool = {} # key MAC address string, value assigned IP string self.ippool = {} # key MAC address string, value assigned IP string
self.filepool = {} # key IP string, value pathname self.filepool = {} # key IP string, value pathname
self.states = {} # key MAC address string, value client state self.states = {} # key MAC address string, value client state
name_ = PRODUCT_NAME.split('-') self.bootp_section = 'bootp'
name_[0] = 'bootp'
self.bootp_section = '_'.join(name_)
self.pool_start = self.config.get(self.bootp_section, 'pool_start') self.pool_start = self.config.get(self.bootp_section, 'pool_start')
if not self.pool_start: if not self.pool_start:
raise BootpError('Missing pool_start definition') raise BootpError('Missing pool_start definition')
@ -236,7 +234,7 @@ class BootpServer:
msg = ','.join([notice, uuid_str, mac_str, ip]) msg = ','.join([notice, uuid_str, mac_str, ip])
else: else:
msg = ','.join([notice, mac_str, ip]) msg = ','.join([notice, mac_str, ip])
notify_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) notify_sock = socket(AF_INET, SOCK_DGRAM)
for n in self.notify: for n in self.notify:
self.log.info('Notifying %s with %s' % (n, msg)) self.log.info('Notifying %s with %s' % (n, msg))
notify_sock.sendto(msg, n) notify_sock.sendto(msg, n)
@ -249,10 +247,9 @@ class BootpServer:
host = self.config.get(self.bootp_section, 'address', '0.0.0.0') host = self.config.get(self.bootp_section, 'address', '0.0.0.0')
port = self.config.get(self.bootp_section, 'port', port = self.config.get(self.bootp_section, 'port',
str(BOOTP_PORT_REQUEST)) str(BOOTP_PORT_REQUEST))
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
socket.IPPROTO_UDP) sock.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.append(sock) self.sock.append(sock)
self.log.info('Listening to %s:%s' % (host, port)) self.log.info('Listening to %s:%s' % (host, port))
sock.bind((host, int(port))) sock.bind((host, int(port)))
@ -260,14 +257,13 @@ class BootpServer:
def forever(self): def forever(self):
while True: while True:
try: try:
r, w, e = select.select(self.sock, [], self.sock) r, w, e = select(self.sock, [], self.sock)
for sock in r: for sock in r:
data, addr = sock.recvfrom(556) data, addr = sock.recvfrom(556)
self.handle(sock, addr, data) self.handle(sock, addr, data)
except Exception as exc: except Exception as exc:
import traceback self.log.critical('%s\n%s' % (exc, format_exc()))
self.log.critical('%s\n%s' % (exc, traceback.format_exc())) sleep(1)
time.sleep(1)
def parse_options(self, tail): def parse_options(self, tail):
self.log.debug('Parsing DHCP options') self.log.debug('Parsing DHCP options')
@ -280,7 +276,7 @@ class BootpServer:
if tag == 0xff: if tag == 0xff:
return dhcp_tags return dhcp_tags
length = ord(tail[1]) length = ord(tail[1])
(value, ) = struct.unpack('!%ss' % length, tail[2:2+length]) (value, ) = sunpack('!%ss' % length, tail[2:2+length])
tail = tail[2+length:] tail = tail[2+length:]
try: try:
option = DHCP_OPTIONS[tag] option = DHCP_OPTIONS[tag]
@ -296,25 +292,25 @@ class BootpServer:
try: try:
buf = '' buf = ''
uuid = options[97] uuid = options[97]
buf += struct.pack('!BB%ds' % len(uuid), buf += spack('!BB%ds' % len(uuid),
97, len(uuid), uuid) 97, len(uuid), uuid)
clientclass = options[60] clientclass = options[60]
clientclass = clientclass[:clientclass.find(':')] clientclass = clientclass[:clientclass.find(':')]
buf += struct.pack('!BB%ds' % len(clientclass), buf += spack('!BB%ds' % len(clientclass),
60, len(clientclass), clientclass) 60, len(clientclass), clientclass)
vendor = '' vendor = ''
vendor += struct.pack('!BBB', PXE_DISCOVERY_CONTROL, 1, 0x0A) vendor += spack('!BBB', PXE_DISCOVERY_CONTROL, 1, 0x0A)
vendor += struct.pack('!BBHB4s', PXE_BOOT_SERVERS, 2+1+4, vendor += spack('!BBHB4s', PXE_BOOT_SERVERS, 2+1+4,
0, 1, server) 0, 1, server)
srvstr = 'Python' srvstr = 'Python'
vendor += struct.pack('!BBHB%ds' % len(srvstr), PXE_BOOT_MENU, vendor += spack('!BBHB%ds' % len(srvstr), PXE_BOOT_MENU,
2+1+len(srvstr), 0, len(srvstr), srvstr) 2+1+len(srvstr), 0, len(srvstr), srvstr)
prompt = 'Stupid PXE' prompt = 'Stupid PXE'
vendor += struct.pack('!BBB%ds' % len(prompt), PXE_MENU_PROMPT, vendor += spack('!BBB%ds' % len(prompt), PXE_MENU_PROMPT,
1+len(prompt), len(prompt), prompt) 1+len(prompt), len(prompt), prompt)
buf += struct.pack('!BB%ds' % len(vendor), 43, buf += spack('!BB%ds' % len(vendor), 43,
len(vendor), vendor) len(vendor), vendor)
buf += struct.pack('!BBB', 255, 0, 0) buf += spack('!BBB', 255, 0, 0)
return buf return buf
except KeyError as exc: except KeyError as exc:
self.log.error('Missing options, cancelling: %s' % exc) self.log.error('Missing options, cancelling: %s' % exc)
@ -324,7 +320,7 @@ class BootpServer:
buf = '' buf = ''
if not clientname: if not clientname:
return buf return buf
buf += struct.pack('!BB%ds' % len(clientname), buf += spack('!BB%ds' % len(clientname),
12, len(clientname), clientname) 12, len(clientname), clientname)
return buf return buf
@ -333,7 +329,7 @@ class BootpServer:
if len(data) < DHCPFORMATSIZE: if len(data) < DHCPFORMATSIZE:
self.log.error('Cannot be a DHCP or BOOTP request - too small!') self.log.error('Cannot be a DHCP or BOOTP request - too small!')
tail = data[DHCPFORMATSIZE:] tail = data[DHCPFORMATSIZE:]
buf = list(struct.unpack(DHCPFORMAT, data[:DHCPFORMATSIZE])) buf = list(sunpack(DHCPFORMAT, data[:DHCPFORMATSIZE]))
if buf[BOOTP_OP] != BOOTREQUEST: if buf[BOOTP_OP] != BOOTREQUEST:
self.log.warn('Not a BOOTREQUEST') self.log.warn('Not a BOOTREQUEST')
return return
@ -477,7 +473,7 @@ class BootpServer:
# construct reply # construct reply
buf[BOOTP_HOPS] = 0 buf[BOOTP_HOPS] = 0
buf[BOOTP_OP] = BOOTREPLY buf[BOOTP_OP] = BOOTREPLY
self.log.info('Client IP: %s' % socket.inet_ntoa(buf[7])) self.log.info('Client IP: %s' % inet_ntoa(buf[7]))
if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00': if buf[BOOTP_CIADDR] == '\x00\x00\x00\x00':
self.log.debug('Client needs its address') self.log.debug('Client needs its address')
ipaddr = iptoint(self.pool_start) ipaddr = iptoint(self.pool_start)
@ -501,20 +497,20 @@ class BootpServer:
self.bootp_section, 'netmask', self.netconfig['mask'])) self.bootp_section, 'netmask', self.netconfig['mask']))
reply_broadcast = iptoint(ip) & mask reply_broadcast = iptoint(ip) & mask
reply_broadcast |= (~mask) & ((1 << 32)-1) reply_broadcast |= (~mask) & ((1 << 32)-1)
buf[BOOTP_YIADDR] = socket.inet_aton(ip) buf[BOOTP_YIADDR] = inet_aton(ip)
buf[BOOTP_SECS] = 0 buf[BOOTP_SECS] = 0
buf[BOOTP_FLAGS] = BOOTP_FLAGS_BROADCAST buf[BOOTP_FLAGS] = BOOTP_FLAGS_BROADCAST
relay = buf[BOOTP_GIADDR] relay = buf[BOOTP_GIADDR]
if relay != b'\x00\x00\x00\x00': if relay != b'\x00\x00\x00\x00':
addr = (socket.inet_ntoa(relay), addr[1]) addr = (inet_ntoa(relay), addr[1])
else: else:
addr = (inttoip(reply_broadcast), addr[1]) addr = (inttoip(reply_broadcast), addr[1])
self.log.info('Reply to: %s:%s' % addr) self.log.info('Reply to: %s:%s' % addr)
else: else:
buf[BOOTP_YIADDR] = buf[BOOTP_CIADDR] buf[BOOTP_YIADDR] = buf[BOOTP_CIADDR]
ip = socket.inet_ntoa(buf[BOOTP_YIADDR]) ip = inet_ntoa(buf[BOOTP_YIADDR])
buf[BOOTP_SIADDR] = socket.inet_aton(server_addr) buf[BOOTP_SIADDR] = inet_aton(server_addr)
# sname # sname
buf[BOOTP_SNAME] = \ buf[BOOTP_SNAME] = \
'.'.join([self.config.get(self.bootp_section, '.'.join([self.config.get(self.bootp_section,
@ -567,38 +563,38 @@ class BootpServer:
else: else:
self.log.debug('No filename defined for IP %s' % ip) self.log.debug('No filename defined for IP %s' % ip)
pkt = struct.pack(DHCPFORMAT, *buf) pkt = spack(DHCPFORMAT, *buf)
pkt += struct.pack('!BBB', DHCP_MSG, 1, dhcp_reply) pkt += spack('!BBB', DHCP_MSG, 1, dhcp_reply)
server = socket.inet_aton(server_addr) server = inet_aton(server_addr)
pkt += struct.pack('!BB4s', DHCP_SERVER, 4, server) pkt += spack('!BB4s', DHCP_SERVER, 4, server)
mask = socket.inet_aton(self.config.get( mask = inet_aton(self.config.get(
self.bootp_section, 'netmask', self.netconfig['mask'])) self.bootp_section, 'netmask', self.netconfig['mask']))
pkt += struct.pack('!BB4s', DHCP_IP_MASK, 4, mask) pkt += spack('!BB4s', DHCP_IP_MASK, 4, mask)
gateway_addr = self.config.get(self.bootp_section, 'gateway', '') gateway_addr = self.config.get(self.bootp_section, 'gateway', '')
if gateway_addr: if gateway_addr:
gateway = socket.inet_aton(gateway_addr) gateway = inet_aton(gateway_addr)
else: else:
gateway = server gateway = server
pkt += struct.pack('!BB4s', DHCP_IP_GATEWAY, 4, gateway) pkt += spack('!BB4s', DHCP_IP_GATEWAY, 4, gateway)
dns = self.config.get(self.bootp_section, dns = self.config.get(self.bootp_section,
'dns', None) 'dns', None)
if dns: if dns:
if dns.lower() == 'auto': if dns.lower() == 'auto':
dns_list = self.get_dns_servers() or [socket.inet_ntoa(server)] dns_list = self.get_dns_servers() or [inet_ntoa(server)]
else: else:
dns_list = dns.split(';') dns_list = dns.split(';')
for dns_str in dns_list: for dns_str in dns_list:
dns_ip = socket.inet_aton(dns_str) dns_ip = inet_aton(dns_str)
pkt += struct.pack('!BB4s', DHCP_IP_DNS, 4, dns_ip) pkt += spack('!BB4s', DHCP_IP_DNS, 4, dns_ip)
pkt += struct.pack('!BBI', DHCP_LEASE_TIME, 4, pkt += spack('!BBI', DHCP_LEASE_TIME, 4,
int(self.config.get(self.bootp_section, int(self.config.get(self.bootp_section,
'lease_time', 'lease_time',
str(24*3600)))) str(24*3600))))
pkt += struct.pack('!BB', DHCP_END, 0) pkt += spack('!BB', DHCP_END, 0)
# do not attempt to produce a PXE-augmented response for # do not attempt to produce a PXE-augmented response for
# regular DHCP requests # regular DHCP requests
@ -623,7 +619,7 @@ class BootpServer:
self.states[mac_str] = newstate self.states[mac_str] = newstate
def get_dns_servers(self): def get_dns_servers(self):
nscre = re.compile(r'nameserver\s+(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s') nscre = recompile(r'nameserver\s+(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s')
result = [] result = []
try: try:
with open('/etc/resolv.conf', 'r') as resolv: with open('/etc/resolv.conf', 'r') as resolv:

View File

@ -18,22 +18,21 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import os import os
import re
import select
import socket
import string
import struct
import sys
import time
from configparser import NoSectionError from configparser import NoSectionError
from io import StringIO from io import StringIO
from re import compile as recompile, sub as resub
from select import select
from socket import socket, AF_INET, SOCK_DGRAM
from struct import pack as spack, unpack as sunpack
from sys import argv, exc_info
from threading import Thread from threading import Thread
from time import time as now
from traceback import print_exc
from urllib.parse import urlparse from urllib.parse import urlparse
from urllib.request import urlopen from urllib.request import urlopen
from . import pybootd_path from . import pybootd_path
from .util import hexline from .util import hexline
__all__ = ['TftpServer']
TFTP_PORT = 69 TFTP_PORT = 69
@ -86,7 +85,7 @@ class TftpConnection(object):
timeout = self.timeout timeout = self.timeout
retry = self.server.retry retry = self.server.retry
while retry: while retry:
r, w, e = select.select([fno], [], [fno], timeout) r, w, e = select([fno], [], [fno], timeout)
if not r: if not r:
# We timed out -- retransmit # We timed out -- retransmit
retry = retry - 1 retry = retry - 1
@ -121,13 +120,13 @@ class TftpConnection(object):
path = self.server.bootpd.get_filename(client_ip) path = self.server.bootpd.get_filename(client_ip)
return path return path
def parse(self, data, unpack=struct.unpack): def parse(self, data, unpack=sunpack):
self.log.debug('parse') self.log.debug('parse')
buf = buffer(data) buf = buffer(data)
pkt = {} pkt = {}
opcode = pkt['opcode'] = unpack('!h', buf[:2])[0] opcode = pkt['opcode'] = unpack('!h', buf[:2])[0]
if (opcode == self.RRQ) or (opcode == self.WRQ): if (opcode == self.RRQ) or (opcode == self.WRQ):
resource, mode, options = string.split(data[2:], '\000', 2) resource, mode, options = data[2:].split('\000', 2)
resource = self.server.fcre.sub(self._filter_file, resource) resource = self.server.fcre.sub(self._filter_file, resource)
if self.server.root and self.is_url(self.server.root): if self.server.root and self.is_url(self.server.root):
resource = '%s/%s' % (self.server.root, resource) resource = '%s/%s' % (self.server.root, resource)
@ -138,7 +137,7 @@ class TftpConnection(object):
if not self.server.genfilecre.match(resource): if not self.server.genfilecre.match(resource):
if resource.startswith('^%s' % os.sep): if resource.startswith('^%s' % os.sep):
resource = os.path.join( resource = os.path.join(
os.path.dirname(sys.argv[0]), os.path.dirname(argv[0]),
resource.lstrip('^%s' % os.sep)) resource.lstrip('^%s' % os.sep))
elif self.server.root: elif self.server.root:
if self.server.root.startswith(os.sep): if self.server.root.startswith(os.sep):
@ -147,7 +146,7 @@ class TftpConnection(object):
resource) resource)
else: else:
# Relative root directory, from the daemon path # Relative root directory, from the daemon path
daemonpath = os.path.dirname(sys.argv[0]) daemonpath = os.path.dirname(argv[0])
if not daemonpath.startswith(os.sep): if not daemonpath.startswith(os.sep):
daemonpath = os.path.normpath( daemonpath = os.path.normpath(
os.path.join(os.getcwd(), daemonpath)) os.path.join(os.getcwd(), daemonpath))
@ -220,8 +219,7 @@ class TftpConnection(object):
except TftpError as exc: except TftpError as exc:
self.send_error(exc[0], exc[1]) self.send_error(exc[0], exc[1])
except: except:
import traceback self.log.error(format_exc())
self.log.error(traceback.format_exc())
self.log.debug('Ending connection %s:%s' % addr) self.log.debug('Ending connection %s:%s' % addr)
def recv_ack(self, pkt): def recv_ack(self, pkt):
@ -245,19 +243,19 @@ class TftpConnection(object):
self.handle_err(pkt) self.handle_err(pkt)
self.retransmit() self.retransmit()
def send_data(self, data, pack=struct.pack): def send_data(self, data, pack=spack):
self.log.debug('send_data') self.log.debug('send_data')
if not self.time: if not self.time:
self.time = time.time() self.time = now()
blocksize = self.blocksize blocksize = self.blocksize
block = self.blockNumber = self.blockNumber + 1 block = self.blockNumber = self.blockNumber + 1
lendata = len(data) lendata = len(data)
format = '!hh%ds' % lendata fmt = '!hh%ds' % lendata
pkt = pack(format, self.DATA, block, data) pkt = pack(fmt, self.DATA, block, data)
self.send(pkt) self.send(pkt)
self.active = (len(data) == blocksize) self.active = (len(data) == blocksize)
if not self.active and self.time: if not self.active and self.time:
total = time.time()-self.time total = now()-self.time
self.time = 0 self.time = 0
try: try:
name = self.file.name name = self.file.name
@ -271,26 +269,24 @@ class TftpConnection(object):
# StringIO does not have a 'name' attribute # StringIO does not have a 'name' attribute
pass pass
except Exception: except Exception:
import traceback print_exc()
traceback.print_exc()
pass
def send_ack(self, pack=struct.pack): def send_ack(self, pack=spack):
self.log.debug('send_ack') self.log.debug('send_ack')
block = self.blockNumber block = self.blockNumber
self.blockNumber = self.blockNumber + 1 self.blockNumber = self.blockNumber + 1
format = '!hh' fmt = '!hh'
pkt = pack(format, self.ACK, block) pkt = pack(fmt, self.ACK, block)
self.send(pkt) self.send(pkt)
def send_error(self, errnum, errtext, pack=struct.pack): def send_error(self, errnum, errtext, pack=spack):
self.log.debug('send_error') self.log.debug('send_error')
errtext = errtext + '\000' errtext = errtext + '\000'
format = '!hh%ds' % len(errtext) fmt = '!hh%ds' % len(errtext)
outdata = pack(format, self.ERR, errnum, errtext) outdata = pack(fmt, self.ERR, errnum, errtext)
self.sock.sendto(outdata, self.client_addr) self.sock.sendto(outdata, self.client_addr)
def send_oack(self, options, pack=struct.pack): def send_oack(self, options, pack=spack):
self.log.debug('send_oack') self.log.debug('send_oack')
pkt = pack('!h', self.OACK) pkt = pack('!h', self.OACK)
for k, v in options: for k, v in options:
@ -341,7 +337,7 @@ class TftpConnection(object):
except Exception: except Exception:
self.send_error(1, 'Cannot open resource') self.send_error(1, 'Cannot open resource')
self.log.warn('Cannot open file for reading %s: %s' % self.log.warn('Cannot open file for reading %s: %s' %
sys.exc_info()[:2]) exc_info()[:2])
return return
if 'tsize' not in pkt: if 'tsize' not in pkt:
self.send_data(self.file.read(self.blocksize)) self.send_data(self.file.read(self.blocksize))
@ -359,7 +355,7 @@ class TftpConnection(object):
except: except:
self.send_error(1, 'Cannot open file') self.send_error(1, 'Cannot open file')
self.log.error('Cannot open file for writing %s: %s' % self.log.error('Cannot open file for writing %s: %s' %
sys.exc_info()[:2]) exc_info()[:2])
return return
self.send_ack() self.send_ack()
@ -398,7 +394,7 @@ class TftpServer:
self.retry = int(self.config.get('tftp', 'blocksize', '5')) self.retry = int(self.config.get('tftp', 'blocksize', '5'))
self.root = self.config.get('tftp', 'root', os.getcwd()) self.root = self.config.get('tftp', 'root', os.getcwd())
self.fcre, self.filepatterns = self.get_file_filters() self.fcre, self.filepatterns = self.get_file_filters()
self.genfilecre = re.compile(r'\[(?P<name>[\w\.\-]+)\]') self.genfilecre = recompile(r'\[(?P<name>[\w\.\-]+)\]')
def bind(self): def bind(self):
netconfig = self.bootpd and self.bootpd.get_netconfig() netconfig = self.bootpd and self.bootpd.get_netconfig()
@ -407,7 +403,7 @@ class TftpServer:
if not host: if not host:
raise TftpError('TFTP address no defined') raise TftpError('TFTP address no defined')
port = int(self.config.get('tftp', 'port', str(TFTP_PORT))) port = int(self.config.get('tftp', 'port', str(TFTP_PORT)))
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket(AF_INET, SOCK_DGRAM)
self.sock.append(sock) self.sock.append(sock)
sock.bind((host, port)) sock.bind((host, port))
@ -417,7 +413,7 @@ class TftpServer:
if not self.bootpd.is_alive(): if not self.bootpd.is_alive():
self.log.info('Bootp daemon is dead, exiting') self.log.info('Bootp daemon is dead, exiting')
break break
r, w, e = select.select(self.sock, [], self.sock) r, w, e = select(self.sock, [], self.sock)
for sock in r: for sock in r:
data, addr = sock.recvfrom(516) data, addr = sock.recvfrom(516)
tc = TftpConnection(self) tc = TftpConnection(self)
@ -433,7 +429,7 @@ class TftpServer:
if not filename: if not filename:
continue continue
filepattern = self.filepatterns[group] filepattern = self.filepatterns[group]
return re.sub(r'\{(\w+)\}', connexion._dynreplace, filepattern) return resub(r'\{(\w+)\}', connexion._dynreplace, filepattern)
raise TftpError('Internal error, file matching pattern issue') raise TftpError('Internal error, file matching pattern issue')
def get_file_filters(self): def get_file_filters(self):
@ -451,4 +447,4 @@ class TftpServer:
xre = r'^(?:\./)?(?:%s)$' % r'|'.join(patterns) xre = r'^(?:\./)?(?:%s)$' % r'|'.join(patterns)
except NoSectionError: except NoSectionError:
xre = r'^$' xre = r'^$'
return (re.compile(xre), replacements) return (recompile(xre), replacements)

View File

@ -17,7 +17,6 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from array import array
from configparser import SafeConfigParser, InterpolationSyntaxError from configparser import SafeConfigParser, InterpolationSyntaxError
from logging import (DEBUG, INFO, ERROR, CRITICAL, WARNING, from logging import (DEBUG, INFO, ERROR, CRITICAL, WARNING,
Formatter, FileHandler, StreamHandler, getLogger) Formatter, FileHandler, StreamHandler, getLogger)
@ -29,7 +28,6 @@ from subprocess import run
from struct import pack as spack, unpack as sunpack from struct import pack as spack, unpack as sunpack
from sys import stderr from sys import stderr
try: try:
import netifaces import netifaces
except ImportError: except ImportError:
@ -112,7 +110,7 @@ def hexline(data, sep=' '):
of the buffer data of the buffer data
""" """
try: try:
if isinstance(data, (bytes, array)): if isinstance(data, bytes):
src = bytearray(data) src = bytearray(data)
elif isinstance(data, bytearray): elif isinstance(data, bytearray):
src = data src = data