python實(shí)現(xiàn)解析oui.txt并抽取MAC前綴及組織名稱

做無線抓包時就曾經(jīng)設(shè)想過顯示MAC地址所屬組織的名稱,一直在研究如何根據(jù)MAC查詢對應(yīng)的名稱。今天無意看到網(wǎng)上有相關(guān)文章,里面有介紹,使用C語言實(shí)現(xiàn)。本文使用python來實(shí)現(xiàn)。

oui.txt文件可以在官網(wǎng)地址http://standards-oui.ieee.org/oui/oui.txt下載,該文件包含了MAC地址前綴(前MAC地址前三字節(jié),下文直接使用“MAC地址”)、組織名稱(即公司名稱)、公司地址、國家等信息。截至目前,一共有2萬多個記錄。本文要做的,只是提取出MAC地址和對應(yīng)的組織名稱,再重新整理,以方便程序查詢。

先看一下文件內(nèi)容:

00-CD-FE? (hex) Apple, Inc.

00CDFE? ? (base 16) Apple, Inc.

1 Infinite Loop

Cupertino? CA? 95014

US

第一部分為“xx-xx-xx”形式的MAC地址和名稱;第二部分類似,但省略掉“-”;第三部分是公司地址信息(含國家,行數(shù)較多)。文中選擇第二部分,因為可以直接將如“00CDFE”字符串轉(zhuǎn)換成十六進(jìn)制使用。

提取MAC地址的設(shè)計思路很簡單,如下:

1、逐行讀取oui.txt,利用正則表達(dá)式查找上文所說的“第二部分”內(nèi)容。并放到list中。

2、將list內(nèi)容排序,方便使用二分查找算法,提高速度。

3、將MAC地址轉(zhuǎn)換成十六進(jìn)制存儲(非字符串,這樣省一點(diǎn)空間),組織信息還是用字符串存儲。

4、寫到文件中。其中頭部信息表示著記錄的數(shù)目。數(shù)據(jù)部分即為MAC地址和組織信息。組織信息前一字節(jié)表示該信息長度。

涉及到的python知識點(diǎn):

1、正則表達(dá)式:re.findall(r"^[A-F0-9].[A-F0-9].[A-F0-9].+$", l)

2、字符串轉(zhuǎn)換成數(shù)值:int(mac, 16)

3、字符串轉(zhuǎn)成二進(jìn)制寫入文件:

f1 = open(BIN_FILE, "wb")

format='%ds' % len(org)

byte=struct.pack('i',mac_int) + struct.pack(format,str.encode(org))

f1.write(byte)

4、UTF8編碼:

reload(sys)

sys.setdefaultencoding('utf8')

完整代碼如下:

#!/usr/bin/python

# encoding: utf-8

# 解析oui.txt文件 Powred by Late Lee

# 注:文件編碼格式為utf-8,oui.txt也必須保證是uft-8

# 如果使用python3.4版本,則不需要調(diào)用 sys.setdefaultencoding('utf8')

# 生成bin文件格式:頭部共8字節(jié):前4字節(jié)表示一共有多少條記錄,后面4字節(jié)表示最大組織名稱長度為多少。數(shù)據(jù)部:MAC地址及組織名稱。

# 耗時2秒完成

import os

import re

import struct

import sys

OUI_FILE = "oui.txt"

TXT_FILE = "oui_txt.txt"

BIN_FILE = "oui.bin"

##################################

def write_file():

line=0

list =[]

try:

f = open(OUI_FILE, 'r')

while True:

l = f.readline()

if l == '': # end

break

line += 1

l = l.strip('\n') # not need \n

#print("#%d %s" % (line, l))

ret = re.findall(r"^[A-F0-9].[A-F0-9].[A-F0-9].+$", l) # eg 9C8E99

if len(ret) != 0:

mac = l[:6]

mac_int = int(mac, 16) # string to int number

org = l[22:]

org.strip()

test = mac+" "+org

list.append(test) # add to list

list.sort()

f.close()

except:

raise

line = 0

try:

f1 = open(BIN_FILE, "wb")

f2 = open(TXT_FILE, "w")

f1.write("0000")

for i in range(0, len(list)):

#print("%d %s" % (i, list[i]))

line += 1

mac = list[i][:6]

mac_int = int(mac, 16) # string to int number

org = list[i][7:]

format='%ds' % len(org) # how many bytes in org

org_byte = struct.pack(format,str.encode(org))

org_len = len(org)

byte=struct.pack('i',mac_int) + struct.pack('b',org_len) + struct.pack(format,str.encode(org)) # to byte

#print("333#%d 0x%x %d-->%s %s" % (i, mac_int, mac_int, org, org_byte))

f1.write(byte) # binary

test = mac + " " + org + "\n"

f2.write(test) # text

print("total number: %d max name len: %d" % (line, org_len))

f1.seek(0, 0)

byte=struct.pack('i',line)

f1.write(byte)

f1.close()

f2.close()

except:

raise

if __name__ == '__main__':

reload(sys)

sys.setdefaultencoding('utf8')

write_file()

至此,就完成了MAC信息的提取。最終的二進(jìn)制文件存儲22982條記錄,空間只有600KB左右。文本形式的如下:

000000 XEROX CORPORATION

000001 XEROX CORPORATION

000002 XEROX CORPORATION

000003 XEROX CORPORATION

。。。

FCFC48 Apple, Inc.

FCFE77 Hitachi Reftechno, Inc.

FCFEC2 Invensys Controls UK Limited

FCFFAA IEEE Registration Authority

文本僅描述一種方法。存儲可以使用定長和變長方式。如下:

1、使用定長存儲組織信息,這樣無需處理長度不一的組織名稱,方便編碼。但以犧牲空間為代價,比如使用100字節(jié)存儲名稱,則生成的文件大小由600KB上漲到2MB多。

2、如果要節(jié)省空間,可以在每條記錄中存儲組織名稱長度信息,然后在代碼中根據(jù)此長度動態(tài)分配組織名稱長度。編碼相對復(fù)雜一點(diǎn)點(diǎn)。筆者喜歡這個方法。

參考資料:

1、OUI文件:http://standards-oui.ieee.org/oui/oui.txt

2、http://www.cnblogs.com/Anker/archive/2013/12/22/3486344.html

李遲 2017.1.14 周六 凌晨

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容