pluto实现分析(10)

2023-11-18

 
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源: http://yfydz.cublog.cn

10. 主机对(host_pair)

主机对(host_pair)是连接结构的组成部分, 也都是在program/pluto/connections.c中定义, 只用来定义连接双方的地址对信息, 但又是相对独立的, 不是一一对应的, 也就是每个连接有一个主机对, 但一个主机对可能对应多个连接, 系统里的主机对单独形成了一个链表。

10.1 数据结构
struct host_pair {
// 本地和对端的地址和端口信息
    struct {
 ip_address addr;
 u_int16_t  host_port;         /* IKE port */
 bool       host_port_specific; /* if above is interesting */
    } me, him;
    bool initial_connection_sent;
// 相关的连接结构
    struct connection *connections; /* connections with this pair */
// 等待加密通道建立的等待结构
    struct pending *pending; /* awaiting Keying Channel */
// 主机对链表的下一项
    struct host_pair *next;
};

10.2 查找主机对

根据本地和对端的地址端口信息查找主机对
static struct host_pair *
find_host_pair(const ip_address *myaddr
        , u_int16_t myport
        , const ip_address *hisaddr
        , u_int16_t hisport)
{
    struct host_pair *p, *prev;
    char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF];
    /* default hisaddr to an appropriate any */
    if (hisaddr == NULL)
 hisaddr = aftoinfo(addrtypeof(myaddr))->any;
    /*
     * look for a host-pair that has the right set of ports/address.
     *
     */
   
    /*
     * for the purposes of comparison, port 500 and 4500 are identical,
     * but other ports are not.
     * So if any port==4500, then set it to 500.
     */
// 500和4500端口是等价的
    if(myport == 4500) myport=500;
    if(hisport== 4500) hisport=500;

// 遍历主机对链表, prev参数准备用于节点的断开
    for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)
    {
 DBG(DBG_CONTROLMORE
     , DBG_log("find_host_pair: comparing to %s:%d %s:%d\n"
        , (addrtot(&p->me.addr, 0, b1, sizeof(b1)), b1)
        , p->me.host_port
        , (addrtot(&p->him.addr, 0, b2, sizeof(b2)), b2)
        , p->him.host_port));
// 比较地址端口是否匹配    
 if (sameaddr(&p->me.addr, myaddr)
     && (!p->me.host_port_specific || p->me.host_port == myport)
     && sameaddr(&p->him.addr, hisaddr)
     && (!p->him.host_port_specific || p->him.host_port == hisport)
     )
 {
// 匹配
     if (prev != NULL)
     {
// 将该节点从当前位置断开, 插到链表头, 而如果prev为空,则说明该节点本来就是链表头
// 不需要调整了
  prev->next = p->next; /* remove p from list */
  p->next = host_pairs; /* and stick it on front */
  host_pairs = p;
     }
     break;
 }
    }
    return p;
}

10.3 从连接生成主机对

static void
connect_to_host_pair(struct connection *c)
{
// 连接是否已经确定方向,即本地和对端谁是left, 谁是right
    if (oriented(*c))
    {
// 根据连接安全策略连接的本地和对端地址端口查找主机对结构
 struct host_pair *hp = find_host_pair(&c->spd.this.host_addr
           , c->spd.this.host_port
           , &c->spd.that.host_addr
           , c->spd.that.host_port);
 char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF];
 DBG(DBG_CONTROLMORE
     , DBG_log("connect_to_host_pair: %s:%d %s:%d -> hp:%s\n"
        , (addrtot(&c->spd.this.host_addr, 0, b1,sizeof(b1)), b1)
        , c->spd.this.host_port
        , (addrtot(&c->spd.that.host_addr, 0, b2,sizeof(b2)), b2)
        , c->spd.that.host_port
        , (hp && hp->connections) ? hp->connections->name : "none"));
// 没找到, 新建主机对结构    
 if (hp == NULL)
 {
     /* no suitable host_pair -- build one */
// 分配结构
     hp = alloc_thing(struct host_pair, "host_pair");
// 本地地址
     hp->me.addr = c->spd.this.host_addr;
// 对端地址
     hp->him.addr = c->spd.that.host_addr;
#ifdef NAT_TRAVERSAL
// 本地端口
     hp->me.host_port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;
// 对端端口
     hp->him.host_port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;
#else
     hp->me.host_port = c->spd.this.host_port;
      hp->him.host_port = c->spd.that.host_port;
#endif
     hp->initial_connection_sent = FALSE;
     hp->connections = NULL;
     hp->pending = NULL;
// 添加到系统的主机对链表头
     hp->next = host_pairs;
     host_pairs = hp;
 }
// 连接和主机对结构互指
 c->host_pair = hp;
// 将该连接作为主机对的连接链表的链表头
 c->hp_next = hp->connections;
 hp->connections = c;
    }
    else
    {
 /* since this connection isn't oriented, we place it
  * in the unoriented_connections list instead.
  */
// 主机对为空
 c->host_pair = NULL;
// 连接挂接到未定向连接链表的链表头
 c->hp_next = unoriented_connections;
 unoriented_connections = c;
    }
}

10.4 连接方向调整

根据连接所定义的双方地址和自己的ipsec*网卡地址确定连接的方向

/* adjust orientations of connections to reflect newly added interfaces */
void
check_orientations(void)
{
    /* try to orient all the unoriented connections */
    {
// 未定向的连接链表头
 struct connection *c = unoriented_connections;
// 经过该函数处理后将没有未定向的连接
 unoriented_connections = NULL;
// 遍历链表
 while (c != NULL)
 {
     struct connection *nxt = c->hp_next;
// 连接定向操作
     (void)orient(c);
// 连接转主机对处理
     connect_to_host_pair(c);
     c = nxt;
 }
    }
    /* Check that no oriented connection has become double-oriented.
     * In other words, the far side must not match one of our new interfaces.
     */
    {
 struct iface_port *i;
// 遍历ipsec*网卡链表
 for (i = interfaces; i != NULL; i = i->next)
 {
// 表示是新加的网卡
     if (i->change == IFN_ADD)
     {
  struct host_pair *hp;
// 遍历主机对链表
  for (hp = host_pairs; hp != NULL; hp = hp->next)
  {
// 对端地址和网卡地址相同? 表示是定向错了, 需要重新调整
      if (sameaddr(&hp->him.addr, &i->ip_addr)
   && (kern_interface!=NO_KERNEL || hp->him.host_port == pluto_port))
      {
   /* bad news: the whole chain of connections
    * hanging off this host pair has both sides
    * matching an interface.
    * We'll get rid of them, using orient and
    * connect_to_host_pair.  But we'll be lazy
    * and not ditch the host_pair itself (the
    * cost of leaving it is slight and cannot
    * be induced by a foe).
    */
// 该主机对相关的连接链表, 这些连接方向都错了
   struct connection *c = hp->connections;
// 清空该主机对相关链表
   hp->connections = NULL;
   while (c != NULL)
   {
       struct connection *nxt = c->hp_next;
// 重新调整原来各个连接的方向, 重新建立主机对
// 设置连接的网卡为空, 表示尾定向
       c->interface = NULL;
       (void)orient(c);
       connect_to_host_pair(c);
       c = nxt;
   }
      }
  }
     }
 }
    }
}

// 连接定向
bool
orient(struct connection *c)
{
    struct spd_route *sr;
// 如果连接没定向, 即连接的网卡为空
    if (!oriented(*c))
    {
 struct iface_port *p;
// 遍历连接的安全策略路由链表
 for (sr = &c->spd; sr; sr = sr->next)
 {
     /* Note: this loop does not stop when it finds a match:
      * it continues checking to catch any ambiguity.
      */
// 遍历系统网卡链表
     for (p = interfaces; p != NULL; p = p->next)
     {
#ifdef NAT_TRAVERSAL
// NAT穿越时,端口不固定, 跳过
  if (p->ike_float) continue;
#endif
// 又加一个死循环,为什么要死循环呢?虽然正常应该是最多循环两次就成,出现异常呢?
  for (;;)
  {
      /* check if this interface matches this end */
// 检查安全策略路由的本地地址和网卡地址是否匹配
      if (sameaddr(&sr->this.host_addr, &p->ip_addr)
   && (kern_interface != NO_KERNEL
       || sr->this.host_port == pluto_port))
      {
   if (oriented(*c))
   {
// 如果该连接已经定向, 即连接的ipsec*网卡非空
// 说明有地址重复的ipsec*网卡
       if (c->interface->ip_dev == p->ip_dev)
    loglog(RC_LOG_SERIOUS
           , "both sides of \"%s\" are our interface %s!"
           , c->name, p->ip_dev->id_rname);
       else
    loglog(RC_LOG_SERIOUS, "two interfaces match \"%s\" (%s, %s)"
           , c->name, c->interface->ip_dev->id_rname, p->ip_dev->id_rname);
// 取消连接的定向, 返回失败
       c->interface = NULL; /* withdraw orientation */
       return FALSE;
   }
// 连接的网卡指定为该地址匹配的网卡
   c->interface = p;
      }
      /* done with this interface if it doesn't match that end */
// 如果该网卡地址不匹配对端地址, 说明查找成功
      if (!(sameaddr(&sr->that.host_addr, &p->ip_addr)
     && (kern_interface!=NO_KERNEL
         || sr->that.host_port == pluto_port)))
   break;
      /* swap ends and try again.
       * It is a little tricky to see that this loop will stop.
       * Only continue if the far side matches.
       * If both sides match, there is an error-out.
       */
// 否则对调安全策略路由的本地和对端的地址信息
      {
   struct end t = sr->this;
   sr->this = sr->that;
   sr->that = t;
      }
  }
     }
 }
    }
    return oriented(*c);
}

...... 待续 ......
 

转载于:https://blog.51cto.com/enchen/157911

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pluto实现分析(10) 的相关文章

  • 算法:双指针

    双指针 双指针是一种思想或一种技巧并不是特别具体的算法 具体就是用两个变量动态存储两个结点 来方便我们进行一些操作 通常用在线性的数据结构中 特别是链表类的题目 经常需要用到两个或多个指针配合来记忆链表上的节点 完成某些操作 常见的双指针方
  • 50个c/c++源代码网站

    C C 是最主要的编程语言 这里列出了50名优秀网站和网页清单 这些网站提供c c 源代码 这份清单提供了源代码的链接以及它们的小说明 我已尽力包括最佳的C C 源代码的网站 这不是一个完整的清单 您有建议可以联系我 我将欢迎您的建 议 以
  • Mysql 数据库

    数据库基础 1 什么是数据库 用来存储数据 数据库可在硬盘及内存中存储数据 数据库与文件存储数据的区别 数据库本质也是通过文件来存储数据 数据库的概念就是系统的管理存储数据的文件 数据库介绍 本质就是存储数据的C S架构的socket套接字
  • 《Linux From Scratch》第三部分:构建LFS系统 第六章:安装基本的系统软件- 6.29. Coreutils-8.23...

    Coreutils 软件包包含用于显示和设置基本系统特性的工具 大概编译时间 2 5 SBU 需要磁盘空间 193 MB 6 29 1 安装 Coreutils POSIX 要求 Coreutils 中的程序即使在多字节语言环境也能正确识别
  • 将二叉树转为有序的双向链表

    一 题目要求 输入一棵二叉排序树 现在要将该二叉排序树转换成一个有序的双向链表 而且在转换的过程中 不能创建任何新的结点 只能调整树中的结点指针的指向来实现 include
  • BP神经网络与Python实现

    人工神经网络是一种经典的机器学习模型 随着深度学习的发展神经网络模型日益完善 联想大家熟悉的回归问题 神经网络模型实际上是根据训练样本创造出一个多维输入多维输出的函数 并使用该函数进行预测 网络的训练过程即为调节该函数参数提高预测精度的过程
  • LeetCode83: 删除排序链表中的重复元素

    给定一个已排序的链表的头 head 删除所有重复的元素 使每个元素只出现一次 返回 已排序的链表 示例 1 输入 head 1 1 2 输出 1 2 示例 2 输入 head 1 1 2 3 3 输出 1 2 3 提示 链表中节点数目在范围
  • DDP入门

    DDP 即动态动态规划 可以用于解决一类带修改的DP问题 我们从一个比较简单的东西入手 最大子段和 带修改的最大子段和其实是常规问题了 经典的解决方法是用线段树维护从左 右开始的最大子段和和区间最大子段和 然后进行合并 现在我们换一种方法来
  • DNG格式解析

    Author Maddock Date 2015 04 22 转载请注明出处 http www cnblogs com adong7639 p 4446828 html DNG格式基本概念 DNG格式是在TIFF的基础上扩展出来的 要了解D
  • 数据结构与算法学习总结(六)——字符串的模式匹配算法

    基本概念 字符串是一种特殊的线性表 即元素都是 字符 的线性表 字符是组成字符串的基本单位 字符的取值依赖于字符集 例如二进制的字符集为0 1 则取值只能为 0 1 再比如英语语言 则包括26个字母外加标点符号 例如 abcde 就是一个字
  • 循环单链表(C语言版)

    前言 小可爱们 本次一起来看看循环单链表吧 嘻嘻 一 循环单链表的定义 循环单链表是单链表的另一种形式 其结构特点链表中最后一个结点的指针域不再是结束标记 而是指向整个链表的第一个结点 从而使链表形成一个环 和单链表相同 循环链表也有带头结
  • 『Python基础-15』递归函数 Recursion Function

    什么是递归函数 一种计算过程 如果其中每一步都要用到前一步或前几步的结果 称为递归的 用递归过程定义的函数 称为递归函数 例如连加 连乘及阶乘等 凡是递归的函数 都是可计算的 即能行的 递归就是一个函数在它的函数体内调用它自身 编程语言中的
  • 浮生六记

    浮生六记 目录 浮生六记卷一 闺房记乐 002 浮生六记卷二 闲情记趣 015 浮生六记卷三 坎坷记愁 022 浮生六记卷四 浪游记快 034 浮生六记 2 浮生六记卷一 闺房记乐 余生乾隆癸未冬十一月二十有二日 正值太平盛世 且在 衣冠之
  • 算法问题实战策略

    算法问题实战策略 基本信息作者 韩 具宗万 译者 崔盛一出版社 人民邮电出版社ISBN 9787115384621上架时间 2015 2 4出版日期 2015 年3月开本 16开页码 738版次 1 1 内容简介 算法问题实战策略 本书收录
  • 区块链中的哈希算法

    区块链中的密码学 密码学在区块链中的应用主要有两个 哈希算法与非对称加密算法 这次主要对哈希算法进行详细的说明 哈希算法 哈希算法的特点有 1 输入可以为任意大小的字符串 2 产生固定大小的输出 3 可以在合理的时间内算出输出值 若要满足密
  • 查找数组中第二大的数

    快速找出一个数组中的最大数 第二大数 思路 如果当 前元素大于最大数 max 则让第二大数等于原来的最大数 max 再把当前元素的值赋给 max 如果当前的元素大于等于第二大数secondMax的值而小于最大数max的值 则要把当前元素的值
  • 插入排序超详解释,一看就懂

    目录 一 插入排序的相关概念 1 基本思想 2 基本操作 有序插入 二 插入排序的种类 三 直接插入排序 1 直接插入排序的过程 顺序查找法查找插入位置 2 使用 哨兵 直接插入排序 四 直接插入排序算法描述 五 折半插入排序 1 查找插入
  • 基数排序代码实现

    详情请看排序总结 传送门 https blog csdn net m0 52711790 article details 121914543 基数排序的知识点我就不贴出来 相信都能搜到对应概念解释 下面就直接上代码 代码解释其实也很清晰了
  • 【数据结构入门精讲 | 第二篇】一文讲清算法复杂度

    上篇文章中我们引入了算法 数据结构 数据类型等概念 而要想衡量一个算法与数据结构是否为优质的 就需要一个衡量标准 这个衡量标准也是在我们实现一个好的算法时要遵循的原则 目录 基本概念 渐进性态 渐进性态数学表征 算法复杂度的运算 顺序搜索算
  • 最大流-Dinic算法,原理详解,四大优化,详细代码

    文章目录 零 前言 一 概念回顾 可略过 1 1流网络 1 2流 1 3最大流 1 4残留网络 1 5增广路

随机推荐

  • 随机数函数(一):均匀分布的随机数函数

    随机数是随机产生的数 可以分为两种 真随机数和伪随机数 计算机所使用的都是伪随机数 并不能像投硬币或者投骰子那样产生真正随机的 事前不能确定结果的数值 事实上 计算机在模拟产生随机数前就会按照某种算法产生一个特定的序列 也就意味着每个随机数
  • 主流WEB漏洞扫描器种类及其指纹特征分析

    福利 网络安全重磅福利 入门 进阶全套282G学习资源包免费分享 0x01 Web 漏洞扫描 器 国内 绿盟 WVSS https www nsfocus com cn html 2019 206 0911 8 html 安恒 明鉴 htt
  • ESP32 的esp_http_client详解

    说明 我使用的是esp idf V3 1 3 官方给我们封装好了 HTTP 使用起来还是很方便 一 wifi连接 在main函数里面主要是做了wifi连接的初始化和HTTP任务的创建 如下是main的全部内容 void app main e
  • In-Memory:内存数据库

    在逝去的2016后半年 由于项目需要支持数据的快速更新和多用户的高并发负载 我试水SQL Server 2016的In Memory OLTP 创建内存数据库实现项目的负载需求 现在项目接近尾声 系统运行稳定 写一篇博客 记录一下使用内存数
  • 探究前后端数据交互方式

    前端和后端在 Web 开发中扮演着不同的角色 两者需要进行数据的传递和交互 本篇文章将主要讨论前后端数据交互方式的不同类型和应用场景 一 什么是前后端数据交互 在 Web 开发中 前端负责用户界面的设计和交互 后端负责数据的处理和存储 因此
  • JAVA中的集合知识点

    JAVA中的集合主要又Collection和Map两个接口组成 其中Collection包括Set List Queue三个实现类 而Map接口包含TreeMap HashMap HashTable等实现类 下面是主要介绍 1 Collec
  • 训练 open-mmlab/mmclassification

    代码下载 github https github com open mmlab mmclassification 确定模型 resnet18 点击configs gt resnet18 8 b32 in1k py 说明 模型文件 base
  • 空间里种菜、偷菜,重现只属于80后的回忆

    何为 无人农场 中国工程院院士罗锡文用五句话高度概括 耕种管收生产环节全覆盖 机库田间转移作业全自动 自动避障异况停车保安全 作物生产过程实施全监控 智能决策精准作业全无人 随着新一代信息技术飞速融入传统产业 农业数字化 网络化 智能化逐步
  • cesium js 路径_Cesium开发入门篇

    01 开发环境准备 利用Cesium API进行二次开发属于Web前端开发范畴 目前比较火的Web三剑客包括React Vue AngularJS 每个js库的详细介绍可转至官网查看 在此不做详细介绍 本次开发环境是基于Vue搭建的 需要安
  • 搭建VUE脚手架 + 引入element-ui

    转载路径 https segmentfault com a 1190000011023102 从新建vue项目到引入组件Element 一 新建项目 1 查看 node是不是已经安装好命令 node v 没有安装的先安装环境 https n
  • 云服务器被ddos五个解决方案

    如果你的网站或网络设备遭到了DDOS攻击 你可以采取以下步骤来解决这个问题 1 首先 应尽快联系你的厂家ISP 告诉他们你正在遭受DDOS攻击 他们可能会帮助你拦截攻击流量 并提供其他帮助 2 尝试使用拥有较大带宽的服务器或CDN 内容分发
  • Android Studio 常用快捷键整理(转载+体验)

    一 调换格式 Ctrl D 复制行 其实是复制粘贴到下一行 有用 alt shift 移动到上一行 行内容向上移动 剪切粘贴到上一行 还行 alt shift 移动到下一行 剪切粘贴到下一行 Ctrl R 查找后替换 逐个查找 自动跳跃 手
  • 域名备案指南

    在运营网站的过程中 有一件不可忽略的事情 那就是网站上线之前需要完成 ICP 备案 根据工信部规定 所有在境内运行的服务 有境内公网 IP 地址 能够通过公网访问 都必须进行 ICP 备案 1 哪些单位需要办理互联网网站备案 已在工信部备案
  • CentOS8安装redis5

    CentOS8安装redis5 CentOS8的安装镜像已经包含redis5的软件包 可以直接通过yum安装 安装并启动redis5 yum install y redis systemctl start redis service sys
  • Oracle VM VirtualBox安装及使用常见问题

    1 安装系统显示FATAL NO bootable medium found System halted 镜像问题 需要下载纯净的镜像 推荐MSDN所提供的镜像 从网上或者系统之家下载的将无法启动 https msdn itellyou c
  • uniapp小程序单页面改变手机电量,头部通知的颜色效果demo(整理)

    onShow 改变电池的颜色 wx setNavigationBarColor frontColor ffffff 只支持两种颜色 backgroundColor ffffff animation duration 1
  • 刷题day_9 : 删除链表的倒数第 N 个结点

    题意描述 给你一个链表 删除链表的倒数第 n 个结点 并且返回链表的头结点 利用虚拟头结点 和双指针法 如果要删除倒数第n个节点 让fast移动n步 然后让fast和slow同时移动 直到fast指向链表末尾 删掉slow所指向的节点就可以
  • MoCaPose:在宽松服装中实现动作捕捉

    动作姿态是人类个体活动和互动的基本信息来源 采集人们的动作信息能实现了解 分析日常生活等功能 尽管在宽松服装上可以使用IMU实现动作捕捉 但由于需要将大量IMU并将其节点牢固 精确地固定在特定的身体位置 因此并不适合许多现实生活中的应用 这
  • python cgi如何获得html post 的信息,如何在Python CGI脚本中读取所有HTTP标头?

    可以使用python在apache CGI脚本中获取自定义请求标头的值 解决方法与此类似 Apache的mod cgi将为收到的每个HTTP请求标头设置环境变量 以这种方式设置的变量都将带有HTTP 前缀 因此例如x client vers
  • pluto实现分析(10)

    本文档的Copyleft归yfydz所有 使用GPL发布 可以自由拷贝 转载 转载时请保持文档的完整性 严禁用于任何商业用途 msn yfydz no1 hotmail com 来源 http yfydz cublog cn 10 主机对