# $Id: netbios.py 271 2006-01-11 16:03:33Z dugsong $
"""Network Basic Input/Output System."""
import struct
import dpkt, dns
def encode_name(name):
"""Return the NetBIOS first-level encoded name."""
l = []
for c in struct.pack('16s', name):
c = ord(c)
l.append(chr((c >> 4) + 0x41))
l.append(chr((c & 0xf) + 0x41))
return ''.join(l)
def decode_name(nbname):
"""Return the NetBIOS first-level decoded nbname."""
if len(nbname) != 32:
return nbname
l = []
for i in range(0, 32, 2):
l.append(chr(((ord(nbname[i]) - 0x41) << 4) |
((ord(nbname[i+1]) - 0x41) & 0xf)))
return ''.join(l).split('\x00', 1)[0]
# RR types
NS_A = 0x01 # IP address
NS_NS = 0x02 # Name Server
NS_NULL = 0x0A # NULL
NS_NB = 0x20 # NetBIOS general Name Service
NS_NBSTAT = 0x21 # NetBIOS NODE STATUS
# RR classes
NS_IN = 1
# NBSTAT name flags
NS_NAME_G = 0x8000 # group name (as opposed to unique)
NS_NAME_DRG = 0x1000 # deregister
NS_NAME_CNF = 0x0800 # conflict
NS_NAME_ACT = 0x0400 # active
NS_NAME_PRM = 0x0200 # permanent
# NBSTAT service names
nbstat_svcs = {
# (service, unique): list of ordered (name prefix, service name) tuples
(0x00, 0):[ ('', 'Domain Name') ],
(0x00, 1):[ ('IS~', 'IIS'), ('', 'Workstation Service') ],
(0x01, 0):[ ('__MSBROWSE__', 'Master Browser') ],
(0x01, 1):[ ('', 'Messenger Service') ],
(0x03, 1):[ ('', 'Messenger Service') ],
(0x06, 1):[ ('', 'RAS Server Service') ],
(0x1B, 1):[ ('', 'Domain Master Browser') ],
(0x1C, 0):[ ('INet~Services', 'IIS'), ('', 'Domain Controllers') ],
(0x1D, 1):[ ('', 'Master Browser') ],
(0x1E, 0):[ ('', 'Browser Service Elections') ],
(0x1F, 1):[ ('', 'NetDDE Service') ],
(0x20, 1):[ ('Forte_$ND800ZA', 'DCA IrmaLan Gateway Server Service'),
('', 'File Server Service') ],
(0x21, 1):[ ('', 'RAS Client Service') ],
(0x22, 1):[ ('', 'Microsoft Exchange Interchange(MSMail Connector)') ],
(0x23, 1):[ ('', 'Microsoft Exchange Store') ],
(0x24, 1):[ ('', 'Microsoft Exchange Directory') ],
(0x2B, 1):[ ('', 'Lotus Notes Server Service') ],
(0x2F, 0):[ ('IRISMULTICAST', 'Lotus Notes') ],
(0x30, 1):[ ('', 'Modem Sharing Server Service') ],
(0x31, 1):[ ('', 'Modem Sharing Client Service') ],
(0x33, 0):[ ('IRISNAMESERVER', 'Lotus Notes') ],
(0x43, 1):[ ('', 'SMS Clients Remote Control') ],
(0x44, 1):[ ('', 'SMS Administrators Remote Control Tool') ],
(0x45, 1):[ ('', 'SMS Clients Remote Chat') ],
(0x46, 1):[ ('', 'SMS Clients Remote Transfer') ],
(0x4C, 1):[ ('', 'DEC Pathworks TCPIP service on Windows NT') ],
(0x52, 1):[ ('', 'DEC Pathworks TCPIP service on Windows NT') ],
(0x87, 1):[ ('', 'Microsoft Exchange MTA') ],
(0x6A, 1):[ ('', 'Microsoft Exchange IMC') ],
(0xBE, 1):[ ('', 'Network Monitor Agent') ],
(0xBF, 1):[ ('', 'Network Monitor Application') ]
}
def node_to_service_name((name, service, flags)):
try:
unique = int(flags & NS_NAME_G == 0)
for namepfx, svcname in nbstat_svcs[(service, unique)]:
if name.startswith(namepfx):
return svcname
except KeyError:
pass
return ''
class NS(dns.DNS):
"""NetBIOS Name Service."""
class Q(dns.DNS.Q):
pass
class RR(dns.DNS.RR):
"""NetBIOS resource record."""
def unpack_rdata(self, buf, off):
if self.type == NS_A:
self.ip = self.rdata
elif self.type == NS_NBSTAT:
num = ord(self.rdata[0])
off = 1
l = []
for i in range(num):
name = self.rdata[off:off+15].split(None, 1)[0].split('\x00', 1)[0]
service = ord(self.rdata[off+15])
off += 16
flags = struct.unpack('>H', self.rdata[off:off+2])[0]
off += 2
l.append((name, service, flags))
self.nodenames = l
# XXX - skip stats
def pack_name(self, buf, name):
return dns.DNS.pack_name(self, buf, encode_name(name))
def unpack_name(self, buf, off):
name, off = dns.DNS.unpack_name(self, buf, off)
return decode_name(name), off
class Session(dpkt.Packet):
"""NetBIOS Session Service."""
__hdr__ = (
('type', 'B', 0),
('flags', 'B', 0),
('len', 'H', 0)
)
SSN_MESSAGE = 0
SSN_REQUEST = 1
SSN_POSITIVE = 2
SSN_NEGATIVE = 3
SSN_RETARGET = 4
SSN_KEEPALIVE = 5
class Datagram(dpkt.Packet):
"""NetBIOS Datagram Service."""
__hdr__ = (
('type', 'B', 0),
('flags', 'B', 0),
('id', 'H', 0),
('src', 'I', 0),
('sport', 'H', 0),
('len', 'H', 0),
('off', 'H', 0)
)
DGRAM_UNIQUE = 0x10
DGRAM_GROUP = 0x11
DGRAM_BROADCAST = 0x12
DGRAM_ERROR = 0x13
DGRAM_QUERY = 0x14
DGRAM_POSITIVE = 0x15
DGRAM_NEGATIVE = 0x16
syntax highlighted by Code2HTML, v. 0.9.1