quagga源码学习--BGP协议对等体连接tcp md5签名认证选项

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接收处理时就完成了签名验证。

原文地址:https://www.cnblogs.com/danxi/p/6351384.html