Skip to content

Commit

Permalink
Merge pull request #18 from pbertera/development
Browse files Browse the repository at this point in the history
Merge from development branch
  • Loading branch information
pbertera committed Jun 23, 2015
2 parents c84187e + e1bf513 commit 07d976b
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 19 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ On windows (in a cmd.exe prompt):
DHCP lease fileserver IP (option 66)
--dhcp-filename=DHCP_FILENAME
DHCP lease filename (option 67)

--dhcp-leasesfile=DHCP_LEASESFILE
DHCP leases file store
# Screenshots

**Main tab:**
Expand Down
5 changes: 4 additions & 1 deletion SPLiT.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
help='DHCP lease fileserver IP (option 66)')
opt.add_option('--dhcp-filename', dest='dhcp_filename', default='', action='store',
help='DHCP lease filename (option 67)')
opt.add_option('--dhcp-leasesfile', dest='dhcp_leasesfile', default='dhcp_leases.dat', action='store',
help='DHCP leases file store')

options, args = opt.parse_args(sys.argv[1:])

Expand Down Expand Up @@ -177,7 +179,8 @@
dnsserver = options.dhcp_dns,
broadcast = options.dhcp_bcast,
fileserver = options.dhcp_fileserver,
filename = options.dhcp_filename)
filename = options.dhcp_filename,
leases_file = options.dhcp_leasesfile)
dhcp_server_thread = threading.Thread(name='dhcp', target=dhcp_server.listen)
dhcp_server_thread.daemon = True
dhcp_server_thread.start()
Expand Down
3 changes: 2 additions & 1 deletion gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ def start_dhcp_server(self):
dnsserver = self.options.dhcp_dns,
broadcast = self.options.dhcp_bcast,
fileserver = self.options.dhcp_fileserver,
filename = self.options.dhcp_filename)
filename = self.options.dhcp_filename,
leases_file = self.options.dhcp_leasesfile)
self.dhcp_server_thread = threading.Thread(name='dhcp', target=self.dhcp_server.listen)
self.dhcp_server_thread.daemon = True
self.dhcp_server_thread.start()
Expand Down
30 changes: 25 additions & 5 deletions pnp.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@
rx_subscribe = re.compile("^SUBSCRIBE")
rx_uri_with_params = re.compile("sip:([^@]*)@([^;>$]*)")
rx_uri = re.compile("sip:([^@]*)@([^>$]*)")
rx_addr = re.compile("sip:([^ ;>$]*)")
rx_code = re.compile("^SIP/2.0 ([^ ]*)")
rx_request_uri = re.compile("^([^ ]*) sip:([^ ]*?)(;.*)* SIP/2.0")
rx_event = re.compile("^Event:")
rx_via = re.compile("^Via:")
rx_cvia = re.compile("^v:")
rx_contact = re.compile("^Contact:")
rx_ccontact = re.compile("^m:")

def hexdump( chars, sep, width ):
"""Dump chars in hex and ascii format
Expand All @@ -56,6 +59,7 @@ def __init__(self, mac=None, ip=None, mod=None, fw=None, subs=None):
self.model = mod
self.fw_version = fw
self.subscribe = subs
self.uri = "sip:%s:%s" % (self.ip_addr, self.sip_port)

def __repr__(self):
"""Gets a string representation of the phone"""
Expand All @@ -77,7 +81,7 @@ def __init__(self, server_address, RequestHandlerClass, sip_logger, main_logger,
self.options = options

self.main_logger.info("NOTICE: PnP Server starting on %s:%d and %s:%d." % (server_address[0], server_address[1], self.options.ip_address, self.options.sip_port))

# bind on the right interface where the options.ip_address is
iface = socket.inet_aton(options.ip_address)
group = socket.inet_aton(server_address[0])
Expand Down Expand Up @@ -127,9 +131,22 @@ def parse(self):
l_model_info =line.split(';')
new_phone.model = l_model_info[3].split('=')[1][1:-1]
new_phone.fw_version = l_model_info[4].split('=')[1][1:-1]
if rx_contact.search(line) or rx_ccontact.search(line):
md = rx_uri.search(line)
if md:
new_phone.uri = "sip:%s@%s" % (md.group(1), md.group(2))
self.server.main_logger.debug("PnP: found URI in Contact: %s" % new_phone.uri)
else:
md = rx_addr.search(line)
if md:
new_phone.uri = "sip:" + md.group(1)
self.server.main_logger.debug("PnP: found Address in Contact: %s" % new_phone.uri)
else:
self.server.main_logger.warning("PnP: found Nothing in Contact, using the URI: %s" % new_phone.uri)
return new_phone
except Exception, e:
self.main_logger("PnP: malformed request, cannot parse")
self.server.main_logger.error("PnP: malformed request, cannot parse")
print e
return None

def get_sip_info(self):
Expand Down Expand Up @@ -171,7 +188,7 @@ def processPnP(self):
else:
pnp_uri = self.server.options.pnp_uri.format(model = phone.model, mac = '{mac}')

notify = "NOTIFY sip:%s:%s SIP/2.0\r\n" % (phone.ip_addr, phone.sip_port)
notify = "NOTIFY %s SIP/2.0\r\n" % (phone.uri)
notify += via_header + "\r\n"
notify += "Max-Forwards: 20\r\n"
notify += "Contact: <sip:%s:1036;transport=TCP;handler=dum>\r\n" % self.server.options.ip_address
Expand Down Expand Up @@ -216,10 +233,13 @@ def handle(self):

if __name__ == '__main__':
import utils
import sys

class Options:
ip = "127.0.0.1"
pnp_uri = "http://test.com"
def __init__(self):
self.ip_address = sys.argv[1]
self.pnp_uri = sys.argv[2]
self.sip_port = 5060

options = Options()

Expand Down
78 changes: 68 additions & 10 deletions pypxe/dhcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,32 @@ def __init__(self, **serverSettings):
raise Exception('DHCP pool start undefined')
if self.offerto == '':
raise Exception('DHCP pool end undefined')
if self.router == '':
raise Exception('DHCP router undefined')
if self.dnsserver == '':
raise Exception('DHCP DNS server undefined')
if self.broadcast == '':
raise Exception('DHCP broadcast undefined')

try:
socket.inet_aton(self.offerfrom)
except:
raise Exception("Invalid DHCP pool start")
try:
socket.inet_aton(self.offerto)
except:
raise Exception("Invalid DHCP pool end")
try:
socket.inet_aton(self.broadcast)
except:
raise Exception("Invalid DHCP broadcast")
if self.dnsserver != '':
try:
socket.inet_aton(self.dnsserver)
except:
raise Exception("Invalid DHCP DNS server")
if self.router != '':
try:
socket.inet_aton(self.router)
except:
raise Exception("Invalid DHCP Gateway")

self.mode_debug = serverSettings.get('mode_debug', False) #debug mode
self.magic = struct.pack('!I', 0x63825363) #magic cookie
self.logger = serverSettings.get('logger', None)
Expand All @@ -66,6 +85,11 @@ def __init__(self, **serverSettings):
if self.mode_debug:
self.logger.setLevel(logging.DEBUG)

if self.router == '':
self.logger.warning('DHCP router undefined: DHCP opt.3 will not be sent')
if self.dnsserver == '':
self.logger.warning('DHCP DNS server undefined: DHCP opt.6 will not be sent')

self.logger.info("NOTICE: DHCP server starting on %s:%d" % (self.ip, self.port))
self.logger.debug('DHCP server is using the following:')
self.logger.debug(' DHCP Server IP: {}'.format(self.ip))
Expand All @@ -86,15 +110,22 @@ def __init__(self, **serverSettings):

if os.path.isfile(self.leases_file):
try:
self.logger.info("Reading leases file: %s" % self.leases_file)
self.leases = pickle.load(open(self.leases_file, 'r'))
try:
for k,v in self.leases.iteritems():
self.logger.info("Imported leases:")
self.logger.info("\t%s - %s" % (self.printMAC(k), v))
except Exception, e:
self.logger.error("Cannot read leses file: %s" % e)
except Exception, e:
self.logger.error("Cannot load the leases file: %s" % self.leases_file)
self.leases = defaultdict(default_lease)
else:
#key is mac
#self.leases = defaultdict(lambda: {'ip': '', 'expire': 0})
self.leases = defaultdict(default_lease)

def nextIP(self):
'''
This method returns the next unleased IP from range;
Expand Down Expand Up @@ -167,14 +198,30 @@ def craftHeader(self, message):
#op, htype, hlen, hops, xid
response = struct.pack('!BBBB4s', 2, 1, 6, 0, xid)
response += struct.pack('!HHI', 0, 0, 0) #secs, flags, ciaddr
offer = None
if self.leases[clientmac]['ip']: #OFFER
offer = self.leases[clientmac]['ip']
try:
socket.inet_aton(offer)
except Exception:
self.logger.error('DHCP: Trying to offer an ivalid IP from lease file: %s' % offer)
return (clientmac, None)

self.logger.info('DHCP Assignment from leases file - MAC: {MAC} -> IP: {IP}'.format(MAC = self.printMAC(clientmac), IP = self.leases[clientmac]['ip']))
else: #ACK
offer = self.nextIP()
try:
offer = self.nextIP()
socket.inet_aton(offer)
except Exception:
self.logger.error('DHCP: Trying to offer an ivalid new IP: %s' % offer)
return (clientmac, None)

self.leases[clientmac]['ip'] = offer
self.leases[clientmac]['expire'] = time() + 86400
self.logger.info("Writing to the leases file: %s" % self.leases_file)
pickle.dump(self.leases, open(self.leases_file, "wb"))
self.logger.debug('New DHCP Assignment - MAC: {MAC} -> IP: {IP}'.format(MAC = self.printMAC(clientmac), IP = self.leases[clientmac]['ip']))
self.logger.info('New DHCP Assignment - MAC: {MAC} -> IP: {IP}'.format(MAC = self.printMAC(clientmac), IP = self.leases[clientmac]['ip']))

response += socket.inet_aton(offer) #yiaddr
response += socket.inet_aton(self.ip) #siaddr
response += socket.inet_aton('0.0.0.0') #giaddr
Expand All @@ -196,23 +243,31 @@ def craftOptions(self, opt53, clientmac):
response = self.tlvEncode(53, chr(opt53)) #message type, offer
response += self.tlvEncode(54, socket.inet_aton(self.ip)) #DHCP Server
response += self.tlvEncode(1, socket.inet_aton(self.subnetmask)) #SubnetMask
response += self.tlvEncode(3, socket.inet_aton(self.router)) #Router
response += self.tlvEncode(6, socket.inet_aton(self.dnsserver)) #DNS
if self.router != '':
response += self.tlvEncode(3, socket.inet_aton(self.router)) #Router
if self.dnsserver != '':
response += self.tlvEncode(6, socket.inet_aton(self.dnsserver)) #DNS
response += self.tlvEncode(51, struct.pack('!I', 86400)) #lease time

if self.fileserver != '':
#TFTP Server OR HTTP Server; if iPXE, need both
response += self.tlvEncode(66, self.fileserver)
self.logger.info("Encoded option 66: %s" % self.fileserver)

#filename null terminated
if self.filename != '':
response += self.tlvEncode(67, self.filename + chr(0))
self.logger.info("Encoded option 67: %s" % self.filename)

response += '\xff'
return response

def dhcpOffer(self, message):
'''This method responds to DHCP discovery with offer'''
clientmac, headerResponse = self.craftHeader(message)
if headerResponse == None:
self.logger.warning("DHCP response not valid, ignoring the request")
return
optionsResponse = self.craftOptions(2, clientmac) #DHCPOFFER
response = headerResponse + optionsResponse
self.logger.debug('DHCPOFFER - Sending the following')
Expand All @@ -227,6 +282,9 @@ def dhcpOffer(self, message):
def dhcpAck(self, message):
'''This method responds to DHCP request with acknowledge'''
clientmac, headerResponse = self.craftHeader(message)
if headerResponse == None:
self.logger.warning("DHCP response not valid, ignoring the request")
return
optionsResponse = self.craftOptions(5, clientmac) #DHCPACK
response = headerResponse + optionsResponse
self.logger.debug('DHCPACK - Sending the following')
Expand Down Expand Up @@ -255,7 +313,7 @@ def listen(self):
break
try:
message, address = self.sock.recvfrom(1024)
except error, e:
except Exception, e:
continue
try:
clientmac = struct.unpack('!28x6s', message[:34])
Expand Down
12 changes: 11 additions & 1 deletion pypxe/tftp.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,17 @@ def handle(self):
self.block = block + 1
self.retries = self.default_retries
self.send_block()

elif opcode == 2:
# write request
self.logger.info('Write request: unsupported.')
self.sock = ParentSocket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.ip, 0))
# used by select() to find ready clients
self.sock.parent = self
# send error
self.sendError(4, 'Write support not implemented')
self.dead = True

class TFTPD:
'''
Expand Down

0 comments on commit 07d976b

Please sign in to comment.