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

02f,18aug03,agi added #include 02e,02jun03,agi removed #include "rwproto.h" 02d,02jun03,agi changed #include "rwos.h" to include "ospf_rwos.h" 02c,29may03,agi removed unused includes, added new includes 02c,08may03,asr Changes to make OSPF virtual stack compatible 02b,09may03,agi added #include , removed #include 02a,17feb02,ram SPR 81808 Added OSPF memory partition support 21,13october01,kc Dynamic configuration changes. 20,21september01,kc Removed unused raw socket specific declarations. 19,26september00,reshma Added WindRiver CopyRight 18,25september00,reshma RFC-1587 implementation for OSPF NSSA Option, also tested against ANVL. 17,20july00,reshma Unix compatibility related changes. 16,06july00,reshma Removed unnecessary header files and defines. 15,23february00,reshma Changes for ospf mib 14,23december99,reshma Compatibility with VxWorks-IP and VxWorks RTM-interface 13,13august99,jack compilation fixes no IP case 12,05august99,nishit Replaced including IP header files by the new ospf_ip_structures.h 11,17may99,jack Added new include file ospf_patricia_32_bits_key_prototypes.h 10,28december98,jack Compiled and added some comments 09,25november98,rajive Deleted socket include file 08,11november98,jack Config changes, linted and big endian changes 07,30october98,jack Incorporate changes for compilation on Vxworks 06,12february98,release engineer code style changes, feature enhancements, complete CISCO and BAY compaltibility. OSPF v4.2.0 05,10july97,cindy Pre-release v1.52b 04,10february97,cindy Release Version 1.52 03,22october97,cindy Release Version 1.50 02,05june96,cindy Including visnpstr.h as a kludge for the first beta release. 01,05june96,cindy First Beta Release
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值