bgp使用tcp连接,每个bgp实例自身是peer的一个tcp server端,同时也是peer的tcp client端。
1、在bgp_create之后都建立自己的socket服务端开始监听179端口:
1 bgp = bgp_create(as, name); 2 bgp_router_id_set(bgp, &router_id_zebra); 3 *bgp_val = bgp; 4 5 /* Create BGP server socket, if first instance. */ 6 if (list_isempty(bm->bgp) 7 && !bgp_option_check(BGP_OPT_NO_LISTEN)) { 8 if (bgp_socket(bm->port, bm->address) < 0) return BGP_ERR_INVALID_VALUE; 9 } 10 11 listnode_add(bm->bgp, bgp);
bgp_socket里完成server socket的创建与监听。
2、在bgp_start函数里开始对peer的connect操作。在connect之前会清楚一些peer的设置,避免与上一个连接session的混淆。
1 status = bgp_connect(peer);
如果定义了HAVE_DECL_TCP_MD5SIG宏,或者更老的linux 2.4内核版本的宏 HAVE_TCP_MD5_LINUX24,即会添加TCP MD5签名验证选项。
为了跟上时代的步伐,这里我们就只看高版本的内核了。
1 int keylen = password ? strlen(password) : 0; 2 struct tcp_md5sig md5sig; 3 union sockunion *su2, *susock; 4 5 ...... 6 7 memset(&md5sig, 0, sizeof(md5sig)); 8 memcpy(&md5sig.tcpm_addr, su2, sizeof(*su2)); 9 md5sig.tcpm_keylen = keylen; 10 if (keylen) memcpy(md5sig.tcpm_key, password, keylen); 11 sockunion_free(susock); 12 13 if ((ret = setsockopt(sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0) { 14 /* ENOENT is harmless. It is returned when we clear a password for which 15 one was not previously set. */ 16 if (ENOENT == errno) ret = 0; 17 else zlog_err("sockopt_tcp_signature: setsockopt(%d): %s", 18 sock, safe_strerror(errno)); 19 } 20 return ret;
上面的代码即完成MD5SIG选项。
如果md5值不正确或者密码错误,内核会丢弃当前的报文。
4.1.3版本内核对md5sig的结构定义:
1 struct tcp_md5sig { 2 struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ 3 __u16 __tcpm_pad1; /* zero */ 4 __u16 tcpm_keylen; /* key length */ 5 __u32 __tcpm_pad2; /* zero */ 6 __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ 7 };
在int tcp_v4_rcv(struct sk_buff *skb)函数里:
1 #ifdef CONFIG_TCP_MD5SIG 2 /* 3 * We really want to reject the packet as early as possible 4 * if: 5 * o We're expecting an MD5'd packet and this is no MD5 tcp option 6 * o There is an MD5 option and we're not expecting one 7 */ 8 if (tcp_v4_inbound_md5_hash(sk, skb)) 9 goto discard_and_relse; 10 #endif
因此在服务端,直接由内核在tcp接收处理时就完成了签名验证。