【网络入侵检测】基于源码分析Suricata的IP分片重组

【作者主页】只道当时是寻常

【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。

目录

目录

1.概要

2. 配置信息

2.1 名词介绍

2.2 defrag 配置

3. 代码实现

3.1 配置解析

3.1.1 defrag配置

3.1.2 主机系统策略

3.2 分片重组模块

3.2.1分片追踪器(DefragTracker )

3.2.2 获取分片追踪器(DefragGetTracker)

3.2.3 分片插入(DefragInsertFrag)

3.2.3.1 分片冲突策略

3.2.3.1.1 DEFRAG_POLICY_BSD

3.2.3.1.2 DEFRAG_POLICY_BSD_RIGHT

3.2.3.1.3 DEFRAG_POLICY_LINUX

3.2.3.1.4 DEFRAG_POLICY_WINDOWS

3.2.3.1.5 DEFRAG_POLICY_SOLARIS

3.2.3.2 获取主机系统策略


1.概要

👋 本文针对网络入侵检测中 Suricata 的 IP 分片重组模块展开源码分析。IP 分片重组是网络数据传输关键,对 NIDS 执行 DPI 至关重要。Suricata 作为开源高性能网络威胁检测引擎,通过分析其 IP 分片重组模块源码,解析该模块处理 IP 分片数据、监视重组数据包,并将重组数据传递给后续模块的过程,以确保检测准确完整。文中主要包含Suricata中分片配置、分片重组以及解决重组冲突信息。

2. 配置信息

2.1 名词介绍

IP 分片

IP 分片是因不同网络链路 MTU 不同,当 IP 数据包大小超链路 MTU 时,将其拆成多个小数据包的机制。

IP 分片流

单个 IP 报文经分片处理后,由其形成的多个分片所构成的传输流,被称为 IP 分片流,其中各分片报文的 IP 包头 ID 标识保持一致。

分片重组引擎

Suricata 中专门用于对 IP 分片报文实施内部重组的功能模块。

2.2 defrag 配置

在 Suricata 的配置文件中,defrag 关键字包含的配置信息用于配置分片重组引擎。其默认配置信息如下:

defrag:memcap: 32mb# memcap-policy: ignorehash-size: 65536trackers: 65535 # number of defragmented flows to followmax-frags: 65535 # number of fragments to keep (higher than trackers)prealloc: yestimeout: 60# Enable defrag per host settings
#  host-config:
#
#    - dmz:
#        timeout: 30
#        address: [192.168.1.0/24, 127.0.0.0/8, 1.1.1.0/24, 2.2.2.0/24, "1.1.1.1", "2.2.2.2", "::1"]
#
#    - lan:
#        timeout: 45
#        address:
#          - 192.168.0.0/24
#          - 192.168.10.0/24
#          - 172.16.14.0/24
  • memcap:设置分片重组引擎可申请的最大使用内存,这限制了碎片整理过程中内存的使用量。

  • memcap-policy:[drop-packet/pass-packet/reject/ignore(默认)],适用于IPS模式,例如在分片重组时空间申请失败等因素导致无法重组该分片时,对该分片采取的策略。

  • hash-size:设置哈希表中能存储的元素的上限。

  • trackers:设置预先申请的分片追踪器(DefragTracker )的数量,一般和 prealloc 配合使用,prealloc yes,则申请执行数量的DefragTracker 存储在defragtracker_spare_q结构中,否则不申请。

  • max-frags:设置最大分片数量。

  • prealloc:见 "trackers" 字段解释。

  • timeout:设置分片重组超时时间,默认 60s。

  • host-config: 针对特定主机单独设置分片重组策略。

    • timeout:设置分片重组超时时间,默认 60s。

    • address:设置主机IP地址。

3. 代码实现

3.1 配置解析

3.1.1 defrag配置

DefragInit 函数是Suricata 解析配置文件中 Defrag 配置信息的入口函数,DefragPolicyLoadFromConfig 函数用于解析 defrag.host-config 相关的配置信息,DefragInitConfig 函数用于解析其它配置信息。

3.1.2 主机系统策略

在Suricata中 SCHInfoLoadFromConfig 函数主要用于加载配置文件中 host-os-policy 相关的配置信息。

host-os-policy 的配置格式如下所示,分号前面为操作系统类型,后面列表中包含主机的IP地址,不同的IP地址可使用逗号分割。Suricata依据用户配置的IP地址区分主机系统类型。

# Host specific policies for defragmentation and TCP stream
# reassembly. The host OS lookup is done using a radix tree, just
# like a routing table so the most specific entry matches.
host-os-policy:windows: [0.0.0.0/0]bsd: []bsd_right: []old_linux: []linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"]old_solaris: []solaris: ["::1"]hpux10: []hpux11: []irix: []macos: []vista: []windows2k3: []

下面sc_hinfo_os_policy_map 结构用于将配置信息中主机类型转换成宏变量。

/** Enum map for the various OS flavours */
SCEnumCharMap sc_hinfo_os_policy_map[ ] = {{ "none",        OS_POLICY_NONE },{ "bsd",         OS_POLICY_BSD },{ "bsd-right",   OS_POLICY_BSD_RIGHT },{ "old-linux",   OS_POLICY_OLD_LINUX },{ "linux",       OS_POLICY_LINUX },{ "old-solaris", OS_POLICY_OLD_SOLARIS },{ "solaris",     OS_POLICY_SOLARIS },{ "hpux10",      OS_POLICY_HPUX10 },{ "hpux11",      OS_POLICY_HPUX11 },{ "irix",        OS_POLICY_IRIX },{ "macos",       OS_POLICY_MACOS },{ "windows",     OS_POLICY_WINDOWS },{ "vista",       OS_POLICY_VISTA },{ "windows2k3",  OS_POLICY_WINDOWS2K3 },{ NULL,          -1 },
};

3.2 分片重组模块

Defrag 函数作为分片重组引擎的入口函数,在网络数据包解码过程中发挥着关键作用。当解码进入网络层时,会根据数据包的 IP 版本调用 DecodeIPV4 DecodeIPV6 函数进行处理(有关具体的解码流程以及这两个函数的详细介绍,可查阅 【网络入侵检测】基于源码分析Suricata的解码模块)。在调用这两个解码函数期间,Defrag 函数可能会被触发。IPv4 报文触发的条件是:IP 包头中的偏移字段值大于零,或者更多分片标志位(MF)被设置为 1。只有满足这些条件,才会调用 Defrag 函数对分片数据包进行重组操作。IPv6不是本文重点,本文不再关注。

下面是 Suricata 源码中对于IPv4包头是否分片判断:

int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,const uint8_t *pkt, uint16_t len)
{... .../* If a fragment, pass off for re-assembly. */if (unlikely(IPV4_GET_IPOFFSET(p) > 0 || IPV4_GET_MF(p) == 1)) {Packet *rp = Defrag(tv, dtv, p);if (rp != NULL) {PacketEnqueueNoLock(&tv->decode_pq, rp);}p->flags |= PKT_IS_FRAGMENT;return TM_ECODE_OK;}... ...
}

下面是分片重组模块四个主要函数:

  • Defrag:分片重组入口函数。

  • DefragGetTracker:获取分片追踪器(DefragTracker )。

  • DefragInsertFrag:执行分片重组操作。

  • DefragTrackerRelease:执行 DefragTracker 结构引用计数减一操作,并不是释放该对象。

下面是分片重组模块整体设计:

3.2.1分片追踪器(DefragTracker )

在 Suricata 中 DefragTracker 这个结构体尤为重要,该结构体用于跟踪和管理 IP 分片重组的过程。它的主要作用是记录与特定 IP 分片流相关的信息,以便在接收到所有分片后能够正确地重组原始数据包。下面是该结构体的结构:

/*** A defragmentation tracker.  Used to track fragments that make up a* single packet.*/
typedef struct DefragTracker_ {SCMutex lock; /**< Mutex for locking list operations on* this tracker. */uint16_t vlan_id[VLAN_MAX_LAYERS]; /**< VLAN ID tracker applies to. */uint32_t id; /**< IP ID for this tracker.  32 bits for IPv6, 16* for IPv4. */uint8_t proto; /**< IP protocol for this tracker. */uint8_t policy; /**< Reassembly policy this tracker will use. */uint8_t af; /**< Address family for this tracker, AF_INET or* AF_INET6. */uint8_t seen_last; /**< Has this tracker seen the last fragment? */uint8_t remove; /**< remove */Address src_addr; /**< Source address for this tracker. */Address dst_addr; /**< Destination address for this tracker. */int datalink;           /**< datalink for reassembled packet, set by first fragment */SCTime_t timeout;       /**< When this tracker will timeout. */uint32_t host_timeout;  /**< Host timeout, statically assigned from the yaml *//** use cnt, reference counter */SC_ATOMIC_DECLARE(unsigned int, use_cnt);struct IP_FRAGMENTS fragment_tree;/** hash pointers, protected by hash row mutex/spin */struct DefragTracker_ *hnext;struct DefragTracker_ *hprev;/** list pointers, protected by tracker-queue mutex/spin */struct DefragTracker_ *lnext;struct DefragTracker_ *lprev;
} DefragTracker;

下面我们挑选几个主要的变量进行解释:

  • vlan_id:记录 VLAN ID,用于标识分片所属的 VLAN 网络。

  • id:IP 分片的标识符(IP ID),用于区分不同的分片流。

  • proto: IP 协议类型(如 TCP、UDP 等),用于确定分片所属的协议。

  • policy:分片重组策略,不同的主机系统在遇到重组冲突时遵循的重组策略是不同的。

  • af:地址族,标识是 IPv4 (AF_INET) 还是 IPv6 (AF_INET6)。

  • seen_last:标记是否已经接收到最后一个分片。

  • remove:标记该跟踪器是否需要被移除。

  • src_addr:记录分片流的源地址。

  • dst_addr:记录分片流的目的地址。

  • datalink:数据链路层类型,由第一个分片设置。

  • timeout:超时时间,用于确定何时丢弃未完成的分片流。

  • fragment_tree: 用于存储分片的红黑树,按分片偏移量排序。

  • hnext hprev: 哈希表指针,用于在哈希表中链接多个跟踪器。

  • lnext lprev: 链表指针,用于在跟踪器队列中链接多个跟踪器。

👋 综上所述,我们能够明确,每个不同的 IP 分片流都与唯一的 DefragTracker 结构相对应。DefragTracker 结构借助红黑树,按照偏移顺序对当前 IP 分片流中的各个数据包进行存储。后续的分片存储、数据包重组等操作,均依赖这一结构体展开。

3.2.2 获取分片追踪器(DefragGetTracker)

在 Defrag 函数对分片包完成统计操作后,会调用 DefragGetTracker 函数,以查找当前分片报文是否存在对应的 DefragTracker 结构。若存在,则返回该 DefragTracker 结构;若不存在,则创建一个新的 DefragTracker 结构,用于存储该分片包所在分片流的相关信息。具体流程如下图所示:

3.2.3 分片插入(DefragInsertFrag)

调用 DefragGetTracker 后已经获取当前分片关联的 DefragTracker 对象,接着根据当前分片的偏移值,将分片插入到分片队列中。下面是分片插入操作流程图:

3.2.3.1 分片冲突策略

分片在重组的过程中可能出现新的分片与旧的分片出现冲突或者覆盖的现象,如下图所示(参考自TCP IP协议 卷2 第十章):

通过观察上图可以看到分片5与分片1和分片2发生重叠,分片7和分片3发生重叠,分片6与分片4发生重叠。其中分片1、2、3、4先到达目标主机,分片5、6、7后到达主机。

👋 为什么分片在传输过程中出现重叠现象?

在正常的网络通信中,IP分片的“Fragment Offset”字段应确保各分片数据在重组时无重叠。然而,攻击者可以故意设置多个分片的偏移量和长度,使它们在重组时发生重叠。

例如,攻击者可能发送两个分片:

  • 分片A:偏移量为0,长度为100字节

  • 分片B:偏移量为50,长度为100字节

在这种情况下,分片B的前50字节将覆盖分片A的后50字节,导致数据重叠。

👋 发生分片重叠时应该怎么处理?

不同操作系统和网络设备在处理重叠分片时的行为可能不同:

  • 某些系统可能保留第一个到达的分片数据,忽略后续重叠部分。

  • 另一些系统可能使用后到达的分片数据覆盖先前的内容。

  • 还有的系统可能在检测到重叠时直接丢弃整个数据包。

Suricata 支持多种分片重组策略来适配多种不同的操作系统,而在配置文件中 host-os-policy 配置可指定目标主机系统类型。

3.2.3.1.1 DEFRAG_POLICY_BSD

该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留旧分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。

该部分逻辑代码实现如下所示:

/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_BSD:if (frag_offset < prev->offset + prev->data_len) {if (prev->offset <= frag_offset) {  /* We prefer the data from the previous* fragment, so trim off the data in the new* fragment that exists in the previous* fragment. */uint16_t prev_end = prev->offset + prev->data_len;if (prev_end > frag_end) { /* Just skip. *//* TODO: Set overlap flag. */goto done;}ltrim = prev_end - frag_offset;if ((next != NULL) && (frag_end > next->offset)) {next->ltrim = frag_end - next->offset;}goto insert;}/* If the end of this fragment overlaps the start* of the previous fragment, then trim up the* start of previous fragment so this fragment is* used.** See:* DefragBsdSubsequentOverlapsStartOfOriginal.*/if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {uint16_t prev_ltrim = frag_end - prev->offset;if (prev_ltrim > prev->ltrim) {prev->ltrim = prev_ltrim;}}if ((next != NULL) && (frag_end > next->offset)) {next->ltrim = frag_end - next->offset;}goto insert;}break;... ...
}
3.2.3.1.2 DEFRAG_POLICY_BSD_RIGHT

该策略遵循右侧覆盖策略,即右边的分片覆盖前面的分片数据。

3.2.3.1.3 DEFRAG_POLICY_LINUX

该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留新分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪旧分片数据。

该部分逻辑代码实现如下所示:

/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_LINUX:/* Check if new fragment overlaps the end of previous* fragment, if it does, trim the new fragment.** Old: AAAAAAAA AAAAAAAA AAAAAAAA* New:          BBBBBBBB BBBBBBBB BBBBBBBB* Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB*/if (prev->offset + prev->ltrim < frag_offset + ltrim &&prev->offset + prev->data_len > frag_offset + ltrim) {ltrim += prev->offset + prev->data_len - frag_offset;}/* Check if new fragment overlaps the beginning of* previous fragment, if it does, tim the previous* fragment.** Old:          AAAAAAAA AAAAAAAA* New: BBBBBBBB BBBBBBBB BBBBBBBB* Res: BBBBBBBB BBBBBBBB BBBBBBBB*/if (frag_offset + ltrim < prev->offset + prev->ltrim &&frag_end > prev->offset + prev->ltrim) {prev->ltrim += frag_end - (prev->offset + prev->ltrim);goto insert;}/* If the new fragment completely overlaps the* previous fragment, mark the previous to be* skipped. Re-assembly would succeed without doing* this, but this will prevent the bytes from being* copied just to be overwritten. */if (frag_offset + ltrim <= prev->offset + prev->ltrim &&frag_end >= prev->offset + prev->data_len) {prev->skip = 1;goto insert;}break;... ...
}
3.2.3.1.4 DEFRAG_POLICY_WINDOWS

该策略遵循"先到先得"原则,即尽量保全先到来的数据包分片。除非新分片包含且不完全重合于旧分片的情况下,保留新分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。

该部分逻辑代码实现如下所示:

/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_WINDOWS:/* If new fragment fits inside a previous fragment, drop it. */if (frag_offset + ltrim >= prev->offset + ltrim &&frag_end <= prev->offset + prev->data_len) {goto done;}/* If new fragment starts before and ends after* previous fragment, drop the previous fragment. */ if (frag_offset + ltrim < prev->offset + ltrim &&frag_end > prev->offset + prev->data_len) {prev->skip = 1;goto insert;}/* Check if new fragment overlaps the end of previous* fragment, if it does, trim the new fragment.** Old: AAAAAAAA AAAAAAAA AAAAAAAA* New:          BBBBBBBB BBBBBBBB BBBBBBBB* Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB*/if (frag_offset + ltrim > prev->offset + prev->ltrim &&frag_offset + ltrim < prev->offset + prev->data_len) {  ltrim += prev->offset + prev->data_len - frag_offset; goto insert;}/* If new fragment starts at same offset as an* existing fragment, but ends after it, trim the new* fragment. */if (frag_offset + ltrim == prev->offset + ltrim &&frag_end > prev->offset + prev->data_len) {ltrim += prev->offset + prev->data_len - frag_offset;goto insert;}break;... ...
}
3.2.3.1.5 DEFRAG_POLICY_SOLARIS

该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留旧分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。

该部分逻辑代码实现如下所示:

/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_SOLARIS:if (frag_offset < prev->offset + prev->data_len) {if (frag_offset >= prev->offset) {ltrim = prev->offset + prev->data_len - frag_offset;}if ((frag_offset < prev->offset) &&(frag_end >= prev->offset + prev->data_len)) {prev->skip = 1;}goto insert;}break;... ...
}
3.2.3.2 获取主机系统策略

在Suricata的配置文件中通过host-os-policy关键字已经配置好主机系统策略,而在初始化DefragTracker对象时,即调用DefragTrackerInit函数时,会通过当前分片的IP地址,结合host-os-policy配置来选择重组策略。

调用逻辑如下所示:

在 DefragGetOsPolicy 函数中,Suricata会将不同的系统策略归为7类。注意,如果未配置,默认重组策略为DEFRAG_POLICY_BSD。

系统策略

分片重组策略

DEFRAG_POLICY_BSD

OS_POLICY_BSD

OS_POLICY_HPUX10

OS_POLICY_IRIX

DEFRAG_POLICY_BSD_RIGHT

OS_POLICY_BSD_RIGHT

DEFRAG_POLICY_LINUX

OS_POLICY_OLD_LINUX

OS_POLICY_LINUX

DEFRAG_POLICY_FIRST

OS_POLICY_OLD_SOLARIS

OS_POLICY_HPUX11

OS_POLICY_MACOS

OS_POLICY_FIRST

DEFRAG_POLICY_SOLARIS

OS_POLICY_SOLARIS

DEFRAG_POLICY_WINDOWS

OS_POLICY_WINDOWS

OS_POLICY_VISTA

OS_POLICY_WINDOWS2K3

DEFRAG_POLICY_LAST

OS_POLICY_LAST

分片重组策略结构如下所示:

/** Fragment reassembly policies. */
enum defrag_policies {DEFRAG_POLICY_FIRST = 1,DEFRAG_POLICY_LAST,DEFRAG_POLICY_BSD,DEFRAG_POLICY_BSD_RIGHT,DEFRAG_POLICY_LINUX,DEFRAG_POLICY_WINDOWS,DEFRAG_POLICY_SOLARIS,DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/83080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二分查找的边界问题

前言 二分查找(Binary Search)是一种高效的查找算法&#xff0c;时间复杂度为O(log n)。它适用于已排序的数组或列表。本文将详细介绍二分查找的两种常见写法&#xff1a;闭区间写法和左闭右开区间写法。 一、二分查找基本思想 二分查找的核心思想是"分而治之"&am…

重庆医科大学附属第二医院外科楼外挡墙自动化监测

1.项目概述 重庆医科大学附属第二医院&#xff0c;重医附二院&#xff0c;是集医疗、教学、科研、预防保健为一体的国家三级甲等综合医院。前身为始建于1892年的“重庆宽仁医院”。医院现有开放床位 1380张&#xff0c;年门诊量超过百万人次&#xff0c;年收治住院病人4.5万人…

【Redis实战篇】秒杀优化

1. 秒杀优化-异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单…

【idea】调试篇 idea调试技巧合集

前言&#xff1a;之前博主写过一篇idea技巧合集的文章&#xff0c;由于技巧过于多了&#xff0c;文章很庞大&#xff0c;所以特地将调试相关的技巧单独成章, 调试和我们日常开发是息息相关的&#xff0c;用好调试可以事半功倍 文章目录 1. idea调试异步线程2. idea调试stream流…

postman 用法 LTS

postman 用法 LTS File ---- View ---- Show Postman Console

MySQL 数据库故障排查指南

MySQL 数据库故障排查指南 本指南旨在帮助您识别和解决常见的 MySQL 数据库故障。我们将从问题识别开始&#xff0c;逐步深入到具体的故障类型和排查步骤。 1. 问题识别与信息收集 在开始排查之前&#xff0c;首先需要清晰地了解问题的现象和范围。 故障现象&#xff1a; 数…

用AI写简历是否可行?

让AI批量写简历然后投简历是绝对不行的&#xff01;&#xff01;&#xff01; 为什么不行&#xff0c;按照 "招聘经理" 工作经历举例&#xff1a; ai提示词&#xff1a;请帮我写一份招聘经理的工作经历内容&#xff1a; 招聘经理 | XXX科技有限公司 | 2020年…

【从零实现JsonRpc框架#1】Json库介绍

1.JsonCpp第三方库 JSONCPP 是一个开源的 C 库&#xff0c;用于解析和生成 JSON&#xff08;JavaScript Object Notation&#xff09;数据。它提供了简单易用的接口&#xff0c;支持 JSON 的序列化和反序列化操作&#xff0c;适用于处理配置文件、网络通信数据等场景。 2.Jso…

Ubuntu——执行echo $USE什么都不显示

问题&#xff1a;“执行 echo $USER 什么都不显示”&#xff1f; 一、原因分析 环境变量 $USER 未正确设置 $USER 是系统自动定义的环境变量&#xff0c;通常用于表示当前登录的用户名。若该变量未设置或为空&#xff0c;执行 echo $USER 会无输出。可能场景&#xff1a; 用户通…

uni-app学习笔记五--vue3插值表达式的使用

vue3快速上手导航&#xff1a;简介 | Vue.js 模板语法 插值表达式 最基本的数据绑定形式是文本插值&#xff0c;它使用的是“Mustache”语法 (即双大括号)&#xff1a; <span>Message: {{ msg }}</span> 双大括号标签会被替换为相应组件实例中 msg 属性的值。同…

【PSINS工具箱】基于工具箱的单独GNSS导航、单独INS导航、两者结合组合导航,三种导航的对比程序。附完整的代码

本文给出基于PSINS工具箱的单独GNSS导航、单独INS导航、两者结合组合导航(153EKF)的程序。并提供三者的轨迹对比、误差对比。 文章目录 运行结果MATLAB代码代码的简单介绍简介2. 平均绝对误差 (MAE)主要模块运行结果 三轴轨迹图: 各轴误差曲线: 命令行窗口的结果输出: …

C. scanf 函数基础

scanf 函数 1. scanf 函数基础1.1 函数原型与头文件1.2 格式化输入的基本概念2.1 常见格式说明符整数格式说明符浮点数格式说明符字符和字符串格式说明符其他格式说明符2.2 格式说明符的高级用法宽度修饰符精度修饰符跳过输入字段宽度组合修饰符对齐修饰符实际应用示例3.2 精度…

spring cloud loadbalancer实现机房感知的负载均衡

1 概述 在同城多机房情景下&#xff0c;各个机房各自部署一套微服务集群&#xff0c;正常情况下微服务调用在本机房闭环。在如下某些灾难情景&#xff0c;可以尝试拉远调用以最大程度维持业务连续性&#xff0c;这些情景例如&#xff1a; A机房多个服务器宕机。应用由于BUG发…

vue中,created和mounted两个钩子之间调用时差值受什么影响

在 Vue 中&#xff0c;created 和 mounted 是两个生命周期钩子&#xff0c;它们之间的调用时差主要受以下几个因素影响&#xff1a; &#x1f7e2; 1. 模板复杂度与渲染耗时&#xff08;最主要因素&#xff09; mounted 的触发时间是在组件的 DOM 被挂载之后&#xff08;也就是…

Linux篇 第2章Linux基础指令

Linux篇 第2章Linux基础指令 文章目录 前言一、基础的一些命令1.pwd2.mkdir3.ls4.cd5.clear 二、ls1.ls -l2.ls -a3.ls -l -a 三、touch四、 cd1.cd /2.cd ..3.cd ~4. cd - 五、tree1. Linux系统文件的结构2.绝对路径和相对路径 六、mkdir -p七、rmdir&#xff08;没啥用&#…

Scrapyd 详解:分布式爬虫部署与管理利器

Scrapyd 是 Scrapy 官方提供的爬虫部署与管理平台&#xff0c;支持分布式爬虫部署、定时任务调度、远程管理爬虫等功能。本文将深入讲解 Scrapyd 的核心功能、安装配置、爬虫部署流程、API 接口使用&#xff0c;以及如何结合 Scrapy-Redis 实现分布式爬虫管理。通过本文&#x…

国产免费工作流引擎star 6.5k,Warm-Flow升级1.7.2(新增案例和修复缺陷)

文章目录 主要更新内容项目介绍功能思维导图设计器流程图演示地址官网Warm-Flow视频 主要更新内容 [feat] 开启流程实例&#xff0c;新增流程定义是否存在校验[feat] 新增合同签订流程案例[feat] 新增企业采购流程案例[update] mybatis-plus逻辑删除&#xff0c;删除值和未删除…

数据仓库Hive

1.数据仓库 1.1数据仓库的概念 数据仓库&#xff08;Data Warehouse&#xff09;是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合&#xff0c;用于支持管理决策。 面向主题。操作型数据库的数据组织面向事务处理任务&#xff0c;而数据仓库中的数据按照一定的…

dify 连接不上ollama An error occurred during credentials validation:

三大报错 An error occurred during credentials validation: HTTPConnectionPool(hosthost.docker.internal, port11434): Max retries exceeded with url: /api/chat (Caused by NameResolutionError("<urllib3.connection.HTTPConnection object at 0x7f26fc3c00b0&…

uniapp 生成海报二维码 (微信小程序)

先下载qrcodenpm install qrcode 调用 community_poster.vue <template><view class"poster-page"><uv-navbar title"物业推广码" placeholder autoBack></uv-navbar><view class"community-info"><text clas…