zoukankan      html  css  js  c++  java
  • 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接收处理时就完成了签名验证。

  • 相关阅读:
    java如何将char类型的数字转换成int型的数字,而不是Ascii
    java 二分查找的注意事项
    IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结
    java中Math的常用方法整理
    判断字符串是否可由重复子字符串组成
    P3558 [POI2013]BAJ-Bytecomputer
    BZOJ 3329. Xorequ
    Codeforces 1221F. Choose a Square
    Codeforces 1221E. Game With String
    Codeforces 1221D. Make The Fence Great Again
  • 原文地址:https://www.cnblogs.com/danxi/p/6351384.html
Copyright © 2011-2022 走看看