OSPF协议解析及代码实现

OSPF 是一种 TCP/IP 路由协议,在RIP协议中最大路径长度是15,在很多场景下不能满足大型网络的需求,这就有了开放最短路径优先(OSPF),设计用于在大型互联网网络中交换路由信息。据说最多可支持几百台路由器。

OSPF有三个版本,IPV6使用OSPFv3,IPv4使用的是OSPFv2,在OSPFv2经过多次修改,可以参考RFC2328。

OSPF路由器的类型

OSPF路由器可以分为以下4种类型:

  • 区域内路由器(Internal Router)

该类路由器的所有接口都属于同一个OSPF区域。

  • 区域边界路由器(Area Border Router,ABR)

该类路由器可以同时属于两个以上的区域,但其中一个必须是主干区域,ABR用来连接主干区域和分支区域,它与主干区域之间既可以是物理连接,也可以是逻辑上的连接。

  • 主干路由器(Backbone Router)

主干路由器我们也可以称为骨干路由器,至少有一个接口属于主干区域,所有的ABR和位于主干区域的内部路由器都是主干路由器。

  • 自治系统边界路由器(Autonomous System Border Router,ASBR)

与其他自治系统交换路由信息的路由器称为ASBR。

在这里插入图片描述

在这里插入图片描述

OSPF路由分级

OSPF将路由分为4种级别,按照优先级从高到底的顺序依次为:

区域内路由
区域间路由
第一类外部路由
第二类外部路由

区域内和区域间路由描述的是自治系统内部的网络结构,外部路由则用于选择自治系统以外目的地址的路由。

路由聚合

路由聚合是指边界路由器(ABR或ASBR)将具有相同前缀的路由信息聚合,只发布一条路由到其他区域。自治系统划分成不同的区域后,区域间可以通过路由聚合来减少路由信息,减少路由表规模,提高路由表的处理速度。

下图中,区域内有4个区域。

在这里插入图片描述

链路状态通告(LSA)

OSPF是一个链路状态协议。链路状态通告(Link State Advertisement,LSA)又叫链路状态数据包(Link State Advertisement Packet,LSP)是链接状态协议使用的一个数据包,它包含有关邻居和路径成本的信息。

OSPF网络类型

对于不同链路层的协议,OSPF网络采用不同的数据包发送方式。

  • 广播

当链路层协议是以太网时,OSPF默认的网络类型是广播。

  • 非广播多路访问

当链路层协议是帧中继或者ATM时,可以减少对其他设备的干扰。

  • 点到点

当链路层协议是PPP时,OSPF默认的网络类型是P2P。

  • 点到多点

由其他OSPF网络类型强制更改的一种类型。

OSPF数据包类型

将OSPF协议传输的协议数据单元称为OSPF数据包。

OSPF共有以下5种类型的协议数据包。主要包括:

  • 问候(Hello)数据包

周期性发送 ,用来发现和维持OSPF邻居关系以及指定路由器或备份指定路由器的选举。这也是最常用的数据包。

  • 数据库描述(Database Description,DD)数据包

描述了本地LSDB中每条LSA的摘要信息,用于两台路由器进行数据库同步。

  • 链路状态请求(Link State Repuest,LSR)数据包

向对方请求所需的LSA,内容包括所需要的LSA的摘要。

链路状态更新(Link State Update,LSU)数据包

向对方发送其所需要的LSA。

  • 链路状态确认(Link State Acknowledggment,LSAck)数据包

用来对收到的LSA进行确认。

OSPF数据包结构

OSPF数据包直接封装为IP数据报,其协议号为89。

在这里插入图片描述

OSPF数据包包括首部和数据两个部分。
在这里插入图片描述

OSPF首部数据包

在这5种数据包类型中,OSPF拥有相同的数据包首部
在这里插入图片描述主要字段说明如下

版本(Version):OSPF的版本号,对于OSPFv2来说,其值为2。
类型( Message Type):OSPF数据包的类型。数值从1到5,分别对应Hello数据包、DD数据包、LSR数据包、LSU数据包和LSAck数据包。
数据包长度(Packet length):包括首部在内的OSPF数据包的总长度,以字节为单位。
源 OSPF 路由器 (Source OSPF Router):源OSPF的IP地址
区域ID(Area ID):发送该数据包的路由器所在的区域ID
检验和(Checksum):对整个OSPF数据包的校验和。
认证类型(Auth Type):可分为不认证、简单口令认证和MD5认证,其值为0、1、2。
认证数据(Auth Data):厂商认证数据

问候(Hello)数据包格式

在这里插入图片描述
主要的字段如下:
网络掩码(Network Mask):发送问候数据包的接口所在网络的掩码。
问候间隔(Hello Interval):发送问候数据包的时间间隔。
选项(Options):路由器所支持的能力。
路由器优先级(Router Priority):用来选择指定路由器。如果设置为0,则该路由器接口不能成为指定路由器或备份指定路由器。
指定路由器(Designated Router):设置指定路由器的接口的IP地址。
备份指定路由(Backup Designated Router):设置备份指定路由器的接口IP地址。

OSPF选项字段

OSPF选项字段出现在问候数据包、数据库描述包和所有的LSA中,用于使OSPF路由器支持可选择的功能,并向其他OSPF路由器通告其能力,不同能力的路由器可以混合在一个OSPF路由域中。

OSPF选项字段长8位,其中定义了以下标志位,格式如下

在这里插入图片描述DN标志用来避免在MPLS 中出现环路。
O标志用来说明路由器是否有能力发送和接收opaque LSA即类型9,类型10和类型11。
DC标志表示处理按需链路。
MC标志表示转发IP多播包。
E标志表示洪泛AS外部LSA。
MT标志表示始发路由器支持多拓扑OSPF(MT-OSPF)。

OSPF代码实现

static void dissect_ospf(u_char *data_info, int offset,int ip_total_len)
{uint8_t  version;uint8_t  packet_type;uint16_t ospflen;//vec_t cksum_vec[4];int cksum_vec_len;uint32_t phdr[2];uint16_t cksum, computed_cksum;unsigned int length, reported_length;uint16_t auth_type;int crypto_len = 0;unsigned int ospf_header_length;uint8_t instance_id;uint32_t areaid;uint8_t  address_family = OSPF_AF_6;in_addr ip;version = data_info[offset];printf("version: %d\n",version);switch (version) {case OSPF_VERSION_2:ospf_header_length = OSPF_VERSION_2_HEADER_LENGTH;break;case OSPF_VERSION_3:ospf_header_length = OSPF_VERSION_3_HEADER_LENGTH;break;default:ospf_header_length = 14;break;}offset += 1;packet_type = data_info[offset];printf("packet_type: %d\n",packet_type);	offset += 1;ospflen = ntohs(*(uint16_t*)(data_info + offset));printf("ospflen: %d\n",ospflen);offset += 2;if (ospf_msg_type_to_filter(packet_type) != -1) {}memcpy(&ip.s_addr,data_info + offset,sizeof(ip.s_addr));printf("source router: %s\n",inet_ntoa(ip));offset += 4;areaid = ntohl(*(uint32_t*)(data_info + offset));if(areaid == 0){printf("(Backbone)\n");}memcpy(&ip.s_addr,data_info + offset,sizeof(ip.s_addr));printf("area id: %s\n",inet_ntoa(ip));offset += 4;cksum = ntohs(*(uint16_t*)(data_info + offset));if(cksum == 0){printf("(None)\n");}offset += 2;/*如果是未知的 OSPF 版本,请在此时退出*/if(version != OSPF_VERSION_2 && version != OSPF_VERSION_3) {return ;}switch (version) {case OSPF_VERSION_2:/* 认证仅对 OSPFv2 有效 */auth_type = ntohs(*(uint16_t*)(data_info + offset));switch (auth_type) {case OSPF_AUTH_NONE:printf("ospf header auth data none \n");break;case OSPF_AUTH_SIMPLE:printf("ospf header auth data simple \n");break;case OSPF_AUTH_CRYPT:printf("ospf auth crypt \n");crypto_len = data_info[19];printf("crypto_len: %d\n",crypto_len);break;default:printf("ospf header auth data unknown \n");break;}break;case OSPF_VERSION_3:/* 实例 ID 和“保留”仅适用于 OSPFv3  */printf("ospf header instance id \n");instance_id = data_info[14];/* 默认设置 address_family 为 OSPF_AF_6 */address_family = OSPF_AF_6;if(instance_id > 65 && instance_id < 128) {address_family = OSPF_AF_4;}break;default:break;}	offset += 2;/*auth_type*/offset += 8;/*auth_data*/switch (packet_type){case OSPF_HELLO:printf("OSPF_HELLO\n");dissect_ospf_hello(data_info, ospf_header_length,version,(uint16_t)(ospflen - ospf_header_length));break;case OSPF_DB_DESC:break;case OSPF_LS_REQ:break;case OSPF_LS_UPD:break;case OSPF_LS_ACK:break;default:break;}/* 处理 LLS 数据块  */if (ospf_has_lls_block(data_info, ospf_header_length, packet_type, version)){dissect_ospf_lls_data_block(data_info,ospflen + crypto_len, version);}/*处理 AT(Authentication Trailer)数据块 */
}

编译运行

在这里插入图片描述

总结

OSPF的最大优点是效率高,要求很小的开销,适应范围广,可以说是目前应用最广、性能最好的路由器协议。

欢迎关注微信公众号【程序猿编码】,需要OSPF源码和报文的添加本人微信号(17865354792)

参考:RFC2328


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部