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

  • 相关阅读:
    【转载】有效防止百度移动搜索转码
    jquery 弥补ie6不支持input:hover状态
    解决 IE6 position:fixed 固定定位问题
    png-24在ie6中的几种透明方法
    Chrome调试小技巧
    html select美化模拟jquery插件select2.js
    响应式设计的十个基本技巧
    colspan和rowspan
    【转】为什么整个互联网行业都缺前端工程师?
    设计模式之桥接模式
  • 原文地址:https://www.cnblogs.com/danxi/p/6351384.html
Copyright © 2020-2023  润新知