NIST BGPsec SRx对于BGP-UPDATE报文的修改

Author basilguo@163.com

Date Aug. 22, 2023

Description NIST BGPsec SRx对于BGP-UPDATE报文的修改

TOC

BGP协议很复杂,它的实现自然也不会简单到哪里去。但是关注过多的细节并不会让我们立刻成为协议专家,只能是限制了我们总览全局的视角。但是时间总归是有限的,需要能够快速找到可以下手的地方。如果想要从头分析,可以去看看CSDN上这个FRR的专栏,这位博主做了详尽的分析。FRR和Quagga是一脉相承的,至于区别就去GitHub的changelog看吧。

我这里是需要学习下BGPsec的设计与实现,NIST的人就是做BGPsec的标准的,所以他们做的实现应该会提交的IETF中。

我分析的是现在的master分支上的,对应的应该是NIST BGP SRx v6.2.0版本的代码。下载NIST-BGP-SRx代码,其实线上查看也挺方便的。我不想下载,所以就在线上查看了。

在quaaga-srx/bgpd中,bgp_packet.c中包含了BGP-UPDATE报文的处理。虽然不全是,但也大差不差。这个文件一方面包含了peer之间处理报文的代码,另一方面又包含了本机之间的函数,所以看得时候晕头晕脑的。顺次分析各个函数吧,有些函数特别简单,顺带提一嘴就是了,需要特别说明的再进行额外解释。

c 复制代码
/*
// 这个函数就是填充头部的,我们这里给出来Message Header Format
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
+                                                               +
|                                                               |
+                                                               +
|                           Marker                              |
+                                                               +
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Length               |      Type     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
static int bgp_packet_set_marker (struct stream *s, u_char type)

// 在所有内容都填充完毕之后,需要将message header中的Length字段做一次填充。
static int bgp_packet_set_size (struct stream *s)

// 将fifo队列中第一个包free
static void bgp_packet_delete (struct peer *peer)

// 检查连接是否建立
static void bgp_connect_check (struct peer *peer)

接下来是一些NIST BGP SRx自定义的函数,对于这些函数,就是和BGPsec紧密相关了,但对于BGPsec我还不是很清楚,所以它做的这些修改,还不是那么清楚明白。

c 复制代码
// 这个是Extended Community,应该就是和Community团体属性相关的内容。
// BGPsec还需要修改这个?真不知道。或者就是NIST自己搞的吧,反正BGPsec也是他们在提标准。
// https://datatracker.ietf.org/doc/rfc8374/,其中提到:
//      Extended Community携带iBGP中origin validation state是在RFC8097中规定的
// 所以这些函数应该和origin validation state相关,应该是RPKI ROV的结果。
struct ecommunity* srxEcommunityChange(struct bgp *bgp, struct attr *attr, struct bgp_info *binfo)
int srxEcommunityRestore(struct attr *attr, struct ecommunity* ecom_orig)

接下来就是一个比较重要的函数了,但是和FRRouting中又不一样,只分析这里的。需要知道调用链条:bgp_write()调用了bgp_write_packet(),然后调用了bgp_update_packet()

c 复制代码
// 构建BGP-UPDATE报文
static struct stream *bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
// 发送下一个bgp packet
static struct stream *bgp_write_packet (struct peer *peer)
// 发送报文给peer
int bgp_write (struct thread *thread)

bgp_write()中,它先读取了peer中是否有报文要发送bgp_write_packet(),要发送就调用write()发出去,然后根据报文类型进行了分类,进行了一些count等操作,然后就接着读取下一个。反正报文类型也就是BGP_MSG_OPEN | BGP_MSG_UPDATE | BGP_MSG_NOTIFY | BGP_MSG_KEEPALIVE BGP_MSG_ROUTE_REFRESH_NEW | BGP_MSG_ROUTE_REFRESH_OLD | BGP_MSG_CAPABILITY |。至于为啥这么多,实际上IANA目前已经分配的只有5个,猜测NEW、OLD应该是Quaaga自己的区分,伴随Quagga发展以及RFC标准制定,目前应该只需要有NEW,令人难绷的是,新版本的FRRouting中还是这样区分,老代码不好修改吧。BGP_MSG_CAPABILITY,值为6,IANA并没有分配这个Message Type,不知道是从哪里来的。BGPsec的在BGP_MSG_UPDATE中进行了修改。不过只是给fd加上了TCP_CORK

bgp_write_packet()中,首先从peer的obuf的fifo队列中获取头节点s,这个s就是实际的报文。如果s有内容,那么就直接返回,只能先发送出去,现在不能用,只能用空的。接下来就是两个循环,判断afi和safi类型,其实就是IPv4和IPv6的各种类型,例如Unicast、Anycast、Multicast、Broadcast。先是bgp_withdraw_packet(),再是bgp_update_packet()。获取update的fifo队列head节点adv = FIFO_HEAD (&peer->sync[afi][safi]->update);,如果可用且通过检查后,就可以填充BGP-UPDATE报文内容了。如果填充了,那么就能发送了,否则就需要调用bgp_update_packet_eor()

bgp_update_packet()中,首先NIST先加了两个变量,一个u_char bFrag =0;,一个bool useASpath = false;,前者应该是控制分片(不知是否正确),后者应该是是否使用AS_PATH路径属性,默认BGPsec_PATH和AS_PATH是对立关系,有你没我。获取一个节点,adv = FIFO_HEAD (&peer->sync[afi][safi]->update);,接下来就比较复杂,很多字段如果不知道意思,可以结合这个链接来看。我还是只看有USE_SRX的。它既然要使用Extended Community,那么就需要好好填充这个Path Attr,这里就牵涉到bgp_packet_attribute()函数,这个函数在bgp_attr.c中,主要作用就是填充BGP-UPDATE-PATH-ATTRIBUTE。

同理,也需要知道接收BGP-UPDATE报文函数的调用链条:bgp_read()调用bgp_update_receive()。对应于,也有解析BGP-UPDATE-PATH-ATTRIBUTE的函数bgp_attr_parse()。在bgp_attr_parse()中,它的真正的解析BGPsecPath的函数位于bgp_attr_bgpsec(&attr_args);

c 复制代码
// 解析BGP-UPDATE报文
static int bgp_update_receive (struct peer *peer, bgp_size_t size)
// 读取peer的报文
int bgp_read (struct thread *thread)

所以,我们主要关注的两个函数应该是bgp_update_packet()以及bgp_update_receive()。而在这两个函数中应该重点分别关注bgp_packet_attribute()以及bgp_attr_parse(),和PATH-ATTRIBUTE相关的函数都在bgp_attr.c中。

后续是一些出现在bgp_packet.c中的函数,大概记录一下。

c 复制代码
// 这2个函数并没有真正的使用。
void bgp_default_update_send (struct peer *peer, struct attr *attr,
			 afi_t afi, safi_t safi, struct peer *from)
void bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)

// 部分写入的时候可以立即发送
static int bgp_write_proceed (struct peer *peer)

// 用于发送NOTIFICATION报文
static int bgp_write_notify (struct peer *peer)

// 发送KEEPALIVE报文,keepalive没有payload
void bgp_keepalive_send (struct peer *peer)
// 收到KEEPALIVE报文,
static void bgp_keepalive_receive (struct peer *peer, bgp_size_t size)

// 发送open报文
// 我们上一期分析了的BGP-OPEN报文,其中有个`bgp_open_capability()`函数,
// 就是在这里调用的。
// 这个函数会把BGP的其他如header填充后发送出去。实际上是加入到了peer的fifo消息队列中。
// 最终调用的函数应该是`bgp_write()`,使用`write()`系统调用写入了peer的socket中
void bgp_open_send (struct peer *peer)
// 收到open报文
static int bgp_open_receive (struct peer *peer, bgp_size_t size)

// notify和bgp错误类型息息相关,所以单独说这些函数没有意义
void bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,
			   u_char *data, size_t datalen)
void bgp_notify_send (struct peer *peer, u_char code, u_char sub_code)
static void bgp_notify_receive (struct peer *peer, bgp_size_t size)

// 发送BGP-ROUTE-REFRESH报文
void bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,
			u_char orf_type, u_char when_to_refresh, int remove)
static void bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)

// 发送BGP-CAPABILITY报文
void bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,
		     int capability_code, int action)
static int bgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length)
int bgp_capability_receive (struct peer *peer, bgp_size_t size)

// RFC 1771 6.8节中提到的连接冲突检测
static int bgp_collision_detect (struct peer *new, struct in_addr remote_id)
相关推荐
岸边的风12 小时前
无需公网IP的文件交互:FileCodeBox容器化部署技术解析
网络·网络协议·tcp/ip
2501_9153743513 小时前
UDP vs TCP:核心差异与应用场景全解析
网络协议·tcp/ip·udp
Edingbrugh.南空13 小时前
操作系统级TCP性能优化:高并发场景下的内核参数调优实践
网络协议·tcp/ip·性能优化
yqcoder14 小时前
1. http 有哪些版本,你是用的哪个版本,怎么查看
网络·网络协议·http
2501_9159184118 小时前
接口漏洞怎么抓?Fiddler 中文版 + Postman + Wireshark 实战指南
websocket·网络协议·tcp/ip·http·网络安全·https·udp
en-route20 小时前
HTTP cookie
网络·网络协议·http
yqcoder20 小时前
2. 你可以说一下 http 版本的发展过程吗
网络·网络协议·http
诗句藏于尽头1 天前
完成ssl不安全警告
网络协议·安全·ssl
会飞的鱼先生1 天前
Node.js-http模块
网络协议·http·node.js
-qOVOp-1 天前
408第三季part2 - 计算机网络 - ip分布首部格式与分片
网络协议·tcp/ip·计算机网络