zl程序教程

您现在的位置是:首页 >  其他

当前栏目

解析oui.txt文件,通过MAC前缀获取Organization

文件Mac 获取 解析 通过 txt 前缀 organization
2023-09-14 08:59:45 时间

1、前言

OUI是指Organizationally unique identifier  (组织唯一标识符),签发给各类组织的唯一标识符。MAC地址共有6个字节48位组成,前3个字节体现了OUI,其表明了NIC的制造组织。通常情况下,该标识符是唯一的。详细介绍参考:http://standards.ieee.org/develop/regauth/oui/public.html。oui.txt文件中记录世界所有网卡的制造厂商,共有18859个。文件中记录mac的前三位与公司的对应关系。本文目地是对oui.txt文件进行解析,生产一个信息的文件,在程序中可以根据制定的mac地址,快速查找其对应的公司名称。在此将MAC前三个字节简称为MAC前缀。

2、初步处理

oui.txt文件内容很有规律,根据MAC前缀由小到大记录。但是,MAC前缀并不是连续的,中间有些间断,但是顺序是由小到大。原始文件内容格式如下所示:

复制代码
 OUI Organization

 company_id Organization

 Address


UNITED STATES
复制代码

文件中网卡前缀00-00-00和000000两种形式,为了具备一致性,可以提前像00-00-00 (hex) XEROX CORPORATION的行。linux采用cat命令提取。

命令为:cat oui.txt | grep hex mac_hex_org.txt

生成的mac_hex_org.txt文件内容如下:

复制代码
 00-00-00 (hex) XEROX CORPORATION

 00-00-01 (hex) XEROX CORPORATION

 00-00-02 (hex) XEROX CORPORATION

 00-00-03 (hex) XEROX CORPORATION

 00-00-04 (hex) XEROX CORPORATION

 00-00-05 (hex) XEROX CORPORATION

 00-00-06 (hex) XEROX CORPORATION
复制代码

更进一步抽取mac和org信息,可以对mac_hex_org.txt文件进行提前,采用一个简单的shell脚本,提前mac列和org列,分别保存在MAC.log和ORG.log文件中。shell脚本mac_org.sh如下:

复制代码
1 #!/bin/sh

2 SRC_FILE=mac_hex_org.txt

3 MAC_FILE=MAC.log

4 ORG_FILE=ORG.log

5 cat ${SRC_FILE} |grep -v "^#" | while read line;

7 echo "${line:0:8}" ${MAC_FILE}

8 echo "${line:18}" ${ORG_FILE}

9 done
复制代码

执行mac_org.sh生产MAC.log和ORG.log文件。两个文件的每行对应关系就是mac前缀与公司名称的关系。文件内容如下所示:

复制代码
00-00-00

00-00-01

00-00-02

00-00-03

00-00-04

00-00-05

00-00-06
复制代码
复制代码
XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

XEROX CORPORATION

OMRON TATEISI ELECTRONICS CO.

MATRIX CORPORATION

CISCO SYSTEMS, INC.
复制代码

3、生产mac-org结构文件

为了在程序快速查找,将MAC.log和ORG.log文件中对应关系转换为一个结构体,存入mac_org.log文件中。mac前缀是唯一的,对应转换为10进制的整数,相比字符串,查找更加方便。mac_org结构定义如下:

//mac前缀和公司名称对应关系
typedef struct mac_org uint32_t key; //mac前缀作为key char org_name[ORG_NAME_LEN]; //公司名称 }mac_org;

在程序中分别读取MAC.log和ORG.log的每一行,转换为一个mac_log结构,写入mac_log.log文件。转换程序如下所示:

复制代码
 1 #include stdio.h 

 2 #include stdlib.h 

 3 #include inttypes.h 

 4 #include string.h 

 5 #include time.h 

 6 #include errno.h 

 7 #include unistd.h 

 9 #define MAC_PREFIX_LEN 10 //mac前缀长度

 10 #define ORG_NAME_LEN 96 //公司名称长度

 11 #define MAC_LOG_FILE "MAC.log" //mac前缀文件

 12 #define ORG_LOG_FILE "ORG.log" //公司名称文件

 13 #define MAC_ORG_FILE "mac2org.log" //mac前缀对应公司名称文件

 15 #define PRINT_ERROR_POS() do{ \

 16 printf("File: "__FILE__", Line:%d\n", __LINE__); \

 17 }while(0);

 19 //mac前缀和公司名称对应关系

 20 typedef struct mac_org

 21 {

 22 uint32_t key; //mac前缀作为key

 23 char org_name[ORG_NAME_LEN]; //公司名称

 24 }mac_org;

 26 void print_mac_org(const mac_org *macorg)

 27 {

 28 printf("mac key:%d,org_name:%s\n",macorg- key, macorg- org_name);

 29 }

 31 //将mac前缀转换为数字,前缀格式为:00-00-00

 32 uint32_t macprefix2uint(const char *mac_prefix)

 33 {

 34 char mac[8] = {0};

 35 sscanf(mac_prefix, "%c%c-%c%c-%c%c", mac[0], mac[1], mac[2],

 36 mac[3], mac[4], mac[5]);

 37 return strtoul(mac,0,16);

 38 }

 39 //将mac前缀文件和org文件组织成mac_org结构,并将结果存入文件

 40 int store_mac_org()

 41 {

 42 FILE *mac_fp = NULL;

 43 FILE *org_fp = NULL;

 44 FILE *fp = NULL;

 45 char mac_buf[MAC_PREFIX_LEN] = {0};

 46 char org_buf[ORG_NAME_LEN] = {0};

 47 uint32_t mac_len;

 48 uint32_t org_len;

 49 mac_org tmp;

 51 memset( tmp, 0, sizeof(mac_org));

 52 if ((mac_fp = fopen(MAC_LOG_FILE, "r")) == NULL)

 53 {

 54 fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s\n",

 55 MAC_LOG_FILE, errno, strerror(errno));

 56 PRINT_ERROR_POS();

 57 return -1;

 58 }

 59 if ((org_fp = fopen(ORG_LOG_FILE, "r")) == NULL)

 60 {

 61 fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s\n",

 62 ORG_LOG_FILE, errno, strerror(errno));

 63 PRINT_ERROR_POS();

 64 return -1;

 65 }

 66 if ((fp = fopen(MAC_ORG_FILE, "wb")) == NULL)

 67 {

 68 fprintf(stderr,"Failed open mac log file: %s,errno: %u,reason: %s\n",

 69 MAC_ORG_FILE, errno, strerror(errno));

 70 PRINT_ERROR_POS();

 71 return -1;

 72 }

 73 while(fgets(mac_buf, MAC_PREFIX_LEN, mac_fp) != NULL 

 74 fgets(org_buf, ORG_NAME_LEN, org_fp) != NULL)

 75 {

 76 //去掉换行符\n

 77 mac_len = strlen(mac_buf);

 78 org_len = strlen(org_buf);

 79 if (mac_buf[mac_len-1] == \n)

 80 {

 81 mac_buf[mac_len-1] = 0;

 82 }

 83 if (org_buf[org_len-1] == \n)

 84 {

 85 org_buf[org_len-1] = 0;

 86 }

 87 //设置记录值

 88 tmp.key = macprefix2uint(mac_buf);

 89 strcpy(tmp.org_name,org_buf);

 90 //将该记录写入文件

 91 if(fwrite((void *) tmp, sizeof(mac_org), 1, fp) == 0) 

 92 {

 93 fprintf(stderr, "Failed to write macorg to %s,errno:%u,reason:%s\n",

 94 MAC_ORG_FILE, errno, strerror(errno));

 95 PRINT_ERROR_POS();

 96 return -1;

 97 }

 98 }

 99 fclose(mac_fp);

100 fclose(org_fp);

101 fclose(fp);

102 return 0;

103 }

105 //mac前缀格式是00-00-00

106 int main()

107 {

108 //判断文件是否存在

109 if(access(MAC_ORG_FILE, F_OK) != 0)

110 {

111 if (store_mac_org() == -1)

112 {

113 fprintf(stderr, "Failed to create mac2org file.\n");

114 return -1;

115 }

116 else

117 {

118 printf("Successed to create mac2org file.\n");

119 }

120 }

121 return 0;

122 } 
复制代码

执行程序:

查看mac2org.log文件大小和内容如下:文件是二进制形式存入。

4、根据mac前缀在mac2org.log查找org

mac2org.log文件结构很明确,而且文件大小仅为1.8MB,完全可以将文件内容全部读到内存进行查找。而且mac2org.log记录是根据mac前缀有小到大的,即读到内存中的buffer中,mac_org记录是有序的,可以采用折半查找进行,以mac前缀转换的整数为key。查找程序如下所示:

复制代码
 1 /**根据mac前缀(形如00-00-00)查找organzation

 2 先将mac_org.log读取到内存,然后进行折半查找

 3 @auther: Anker @date:2013-12-18

 4 **/

 5 #include stdio.h 

 6 #include stdlib.h 

 7 #include inttypes.h 

 8 #include string.h 

 9 #include time.h 

 10 #include errno.h 

 11 #include unistd.h 

 13 #define MAC_PREFIX_LEN 10 //mac前缀长度

 14 #define ORG_NAME_LEN 96 //公司名称长度

 15 #define MAC_TYPE_COUNT 18860 //记录个数

 16 #define MAC_ORG_FILE "mac2org.log" //mac前缀对应公司名称文件

 18 #define PRINT_ERROR_POS() do{ \

 19 printf("File: "__FILE__", Line:%d\n", __LINE__); \

 20 }while(0);

 22 //mac前缀和公司名称对应关系

 23 typedef struct mac_org

 24 {

 25 uint32_t key; //mac前缀作为key

 26 char org_name[ORG_NAME_LEN]; //公司名称

 27 }mac_org;

 29 void print_mac_org(const mac_org *macorg)

 30 {

 31 printf("mac key:%d,org_name:%s\n",macorg- key, macorg- org_name);

 32 }

 34 //将mac前缀转换为数字,前缀格式为:00-00-00

 35 uint32_t macprefix2uint(const char *mac_prefix)

 36 {

 37 char mac[8] = {0};

 38 sscanf(mac_prefix, "%c%c-%c%c-%c%c", mac[0], mac[1], mac[2],

 39 mac[3], mac[4], mac[5]);

 40 return strtoul(mac,0,16);

 41 }

 43 //二分查找过程

 44 int32_t binary_search(mac_org *macorg, int32_t n, uint32_t key)

 45 {

 46 //在有序表macorg[0..n-1]中进行二分查找,成功时返回结点的位置,失败时返回-1

 47 int32_t low = 0, high = n-1, mid; //置当前查找区间上、下界的初值

 48 if(macorg[low].key == key)

 49 {

 50 return low;

 51 }

 52 if(macorg[high].key == key)

 53 {

 54 return high;

 55 }

 56 while(low = high)

 57 {

 58 //当前查找区间macorg[low..high]非空

 59 mid = low + ((high - low) / 2);

 60 //使用 (low + high) / 2 会有整数溢出的问题

 61 //(问题会出现在当low + high的结果大于表达式结果类型所能表示的最大值时,

 62 //这样,产生溢出后再/2是不会产生正确结果的,而low+((high-low)/2)不存在这个问题

 63 if(macorg[mid].key == key)

 64 {

 65 return mid; //查找成功返回

 66 }

 67 if(macorg[mid].key key)

 68 {

 69 high = mid - 1; //继续在macorg[low..mid-1]中查找

 70 }

 71 else

 72 {

 73 low = mid + 1; //继续在macorg[mid+1..high]中查找

 74 }

 75 }

 76 return -1; //当low high时表示查找区间为空,查找失败

 77 }//BinSeareh

 79 //给定一个mac前缀,获取对应的公司名称

 80 int get_org_by_mac(const char *mac_prefix, mac_org **rmg)

 81 {

 82 mac_org buffer[MAC_TYPE_COUNT];

 83 size_t read_num;

 84 uint32_t key = macprefix2uint(mac_prefix);

 85 int pos = -1;

 86 FILE *fp;

 87 if((fp = fopen(MAC_ORG_FILE, "rb")) == NULL)

 88 {

 89 fprintf(stderr, "Failed to open mac log file: %s,errno:%u,reason:%s\n",

 90 MAC_ORG_FILE, errno, strerror(errno));

 91 PRINT_ERROR_POS();

 92 goto FAILED;

 93 }

 94 fflush(stdin);

 95 read_num = fread((void *)buffer, sizeof(mac_org), MAC_TYPE_COUNT, fp);

 96 if (read_num == 0 errno != 0)

 97 {

 98 fprintf(stderr, "Failed to read mac log file: %s,errno:%u,reason:%s\n",

 99 MAC_ORG_FILE, errno, strerror(errno));

100 PRINT_ERROR_POS();

101 goto FAILED;

102 }

103 pos = binary_search(buffer, read_num, key); 

104 if (pos != -1)

105 {

106 *rmg = (mac_org *)malloc(sizeof(mac_org));

107 if (rmg == NULL)

108 {

109 fprintf(stderr, "Failed to malloc memory,errno:%u,reason:%s\n",

110 errno, strerror(errno));

111 PRINT_ERROR_POS();

112 goto FAILED;

113 }

114 memset(*rmg, 0, sizeof(mac_org));

115 memcpy(*rmg, buffer[pos], sizeof(mac_org));

116 }

117 fclose(fp);

118 return 0;

119 FAILED:

120 if(fp)

121 {

122 fclose(fp);

123 }

124 return -1;

125 }

127 //mac前缀格式是00-00-00

128 int main(int argc,char **argv)

129 {

130 time_t time1,time2;

131 time( time1);

132 mac_org *pmacorg = NULL;

133 char *mac_prefix = NULL;

134 if (argc != 2)

135 {

136 fprintf(stderr,"Paramer error,please input mac prefix.\n");

137 return -1;

138 }

139 if(access(MAC_ORG_FILE, F_OK) != 0)

140 {

141 printf("Can not found mac2org file:%s.\n", MAC_ORG_FILE);

142 return -1;

143 }

144 mac_prefix = argv[1];

145 if (get_org_by_mac(mac_prefix, pmacorg) == -1)

146 {

147 fprintf(stderr, "Failed to search mac.\n");

148 PRINT_ERROR_POS();

149 return -1;

150 }

151 if (!pmacorg)

152 {

153 printf("Can not find the mac prefix:%s\n", mac_prefix);

154 }

155 else

156 {

157 time( time2);

158 printf("Successed to find the mac info, cost time:%lds\n", time2 - time1);

159 print_mac_org(pmacorg);

160 free(pmacorg);

161 }

162 return 0;

163 } 
复制代码

测试结果如下所示:

采用折半查找,针对18860条记录,查询时间不足1秒,非常之快。

5、总结

     刚开始拿到oui.txt文件时,看了文件的格式和规律。当时没有检查,以为mac前缀是连续的,如是开始第一个想到用hash做,mac前缀作为key,value是mac-key在文件中的偏移量。因为hash是唯一的,转换为整数,不会有冲突。实现后发现生产的mac_org.log文件1.2G之大,文件中有很多空白地方,排查发现mac前缀并不是连续的,而且MAC前缀还存在重复。如下图所示:

故不可以采用hash实现。最后还是采用将文件内容记载到内存处理。mac_log结构的占用100字节,18860条共计约1.8MB,如今内存都已GB计算,完全可以全部加载到内存进行二分查找。


mac如何在Finder中显示隐藏的文件或文件夹 每次执行命令也挺麻烦的,可以一段代码生成一个.app文件,每次操作的时候打开操作就好了。 1.打开 AppleScript 编辑器 这个自带 App(前往- 实用工具-》打开applescript) 2. 新建一个文档,将下面的代码粘贴进去,编译,然后导出 .app 应用程序,方便切换显示/隐藏两个状态。
研发提效工具2 - Mac快速新建文件方案 # 背景 Mac电脑不支持右键新建文件。 一般大家使用较多的几种解决方案是 1. 借助诸如`超级右键`这种第三方App; 2. 通过终端的`touch`命令创建; 3. 使用App自带的新建,如`Sublime`的新建文件菜单; 本文介绍一种基于Alfred来快速新建文件的解决方案。
Kubernetes 技术图谱 Kubernetes 技术图谱由 Linux Foundation 开源软件大学、马哥教育、阿里云云原生团队、阿里云开发者学堂专家联合出品,通过技术入门、Kubernetes 应知应会、Kubernetes 实践能力训练三个维度的设计,帮助云原生人才建包括理论、实践、体验的基础技能体系,提供 CKA、CKAD、ACA、ACP 等相关认证资格提供积累专业技能的基础环境。
大数据工程师进阶 技术图谱 从开源大数据技术(选学),到云上大数据快速应用(更便捷、更强大)