#!/usr/bin/env python
#
#
# OSPF Multicast Sniffer
#
# Add's a listener to multicast group 224.0.0.5 (AllSPFRouters),
# waits for an OSPF hello packet and extract the most important info.
# Won't work on Win32...
#
# Limited support for LS_UPDATE, LS_REQUEST, LS_ACKNOWLEDGE and
# DB_DESCRIPTION specific structure.
#
# ***CODE PROVIDED AS-IS WITHOUT ANY KIND OF WARRANTY***
#
# Sample Output:
# *** Packet received from 192.168.1.231 ***
# Protocol OSPF IGP (89)
# Message Type: Hello Packet (1)
# OSPF Version: 2
# Area ID: 0.0.0.0
# Source OSPF Router: 192.168.168.231
# Authentication Type: Message-digest
# Network Mask: 255.255.255.0
# Router Priority: 1
# Hello Interval: 10 seconds
# Dead Interval: 40 seconds
# Designated Router: 192.168.1.230
# Backup Designated Router: 192.168.1.231
#
from socket import *
from sys import exit
from struct import pack
from binascii import b2a_hex, b2a_qp
from string import atoi
MCAST_GROUP = '224.0.0.5'
PROTO = 89
BUFSIZE = 10240
OSPF_TYPE_IGP = '59'
HELLO_PACKET = '01'
DB_DESCRIPTION = '02'
LS_REQUEST = '03'
LS_UPDATE = '04'
LS_ACKNOWLEDGE = '05'
class mcast(object):
def __init__(self):
self.bufsize = BUFSIZE
def create(self, MCAST_GROUP, PROTO):
self.mcast_group = MCAST_GROUP
self.proto = PROTO
s = socket(AF_INET, SOCK_RAW, self.proto)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
mcast = pack('4sl', inet_aton(self.mcast_group), INADDR_ANY)
s.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, mcast)
return s
def recv(self,s):
self.s = s
return self.s.recvfrom(self.bufsize)
def td(r):
for i in r:
return atoi(b2a_hex(i), 16)
if __name__ == '__main__':
print """
\nAdding multicast group %s with protocol %d\nWaiting for first packet to arrive...\n
""" % (MCAST_GROUP, PROTO)
mcast = mcast()
mgroup = mcast.create(MCAST_GROUP, PROTO)
pos = 0
while True:
try:
data, addr = mcast.recv(mgroup)
if data:
break
except KeyboardInterrupt:
exit()
print "*** Packet received from %s ***" % (addr[0])
if b2a_hex(data[pos+9]) == OSPF_TYPE_IGP:
print "Protocol OSPF IGP (%d)" % atoi(b2a_hex(data[pos+9]),16)
else:
print "Error, not an OSPF packet"
exit(0)
pos += 20
# Message Type
if b2a_hex(data[pos+1]) == HELLO_PACKET:
type = 1
print "Message Type: Hello Packet (%d)" % atoi(b2a_hex(data[pos+1]),16)
elif b2a_hex(data[pos+1]) == DB_DESCRIPTION:
type = 2
print "Message Type: DB Description (%d)" % atoi(b2a_hex(data[pos+1]),16)
elif b2a_hex(data[pos+1]) == LS_REQUEST:
type = 3
print "Message Type: LS Request (%d)" % atoi(b2a_hex(data[pos+1]),16)
elif b2a_hex(data[pos+1]) == LS_UPDATE:
type = 4
print "Message Type: LS Update (%d)" % atoi(b2a_hex(data[pos+1]),16)
elif b2a_hex(data[pos+1]) == LS_ACKNOWLEDGE:
type = 5
print "Message Type: LS Acknowledge (%d)" % atoi(b2a_hex(data[pos+1]),16)
if b2a_hex(data[pos]) == '01' or '02' or '03':
print "OSPF Version: %d" % atoi(b2a_hex(data[pos]),16)
else: print "OSPF Version: Unknown"
print "Area ID: %s" % (inet_ntoa(data[pos+8:pos+12]))
print "Source OSPF Router: %s" % (inet_ntoa(data[pos+4:pos+8]))
# Authentication Type
if b2a_hex(data[pos+14]) == '00' and b2a_hex(data[pos+15]) == '00':
print "Authentication Type: None"
elif b2a_hex(data[pos+14]) == '00' and b2a_hex(data[pos+15]) == '01':
print "Authentication Type: Plain text"
print "Authentication Data: %s" % b2a_qp(data[pos+16:pos+24])
elif b2a_hex(data[pos+14]) == '00' and b2a_hex(data[pos+15]) == '02':
print "Authentication Type: Message-digest"
if type == 1:
# Hello Packet
print "Network Mask: %s" % (inet_ntoa(data[pos+24:pos+28]))
print "Router Priority: %d" % (td(data[pos+31]))
print "Hello Interval: %d seconds" % (td(data[pos+28]) + td(data[pos+29]))
print "Dead Interval: %d seconds" % (td(data[pos+32]) + td(data[pos+33]) + td(data[pos+34]) +td(data[pos+35]))
print "Designated Router: %s" % (inet_ntoa(data[pos+36:pos+40]))
print "Backup Designated Router: %s\n" % (inet_ntoa(data[pos+40:pos+44]))
elif type != 1:
exit(0)