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

  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值