一个奇葩的问题

news2024/11/24 22:26:57

defab04d1c984f5ae05518006e3a7453.jpeg

大家好,这里是极客重生,最近遇到一个奇葩的网络问题,分享给大家,看完一定会觉得很奇葩。

问题现象

客户反馈有一个server端S, 两个client端C1, C2, S的iptables规则对C1, C2都是放通的,但是C2无法连接上S,客户很着急,催我们尽快解决。

这里解释一下,iptables规则是防火墙规则,是linux系统实现防火墙一个应用层配置工具,底层依赖是Linux内核网络子系统的netfiler框架。这里简单介绍一下问题的背景知识(后面网络硬核系列文章会详细介绍)。


欢迎加入极客星球学习圈子,全网专业且高质量的学习圈子:

  • 修炼基本功:分享多年基础技术深度理解(比如深入理解系列),基础概念深度解析等等;

  • 扩展技术和商业视野:真正的分享海内外技术发展,大厂技术内幕,业界解决方案;

  • 校招/高薪/跳槽涨薪/大厂:关于一切找工作问题分享,面试问题,简历修改,面试经验,面试问题答疑,各类大厂制定后端学习路线和指导;

  • 职场普升/技术专家:分享各种不同公司宝贵的职场普升经验,核心员工,职场潜规则, 团队合作,做事经验,普升经验,技术深耕经验,少走弯路;

  • 专属交流群:高手交流,开阔眼界,分享心得,每天成长,厚积薄发,任何技术问题,任何疑难杂症,都可以咨询,讨论,交流!

  • 深入理解系列

已完成:

  • 深入理解计算机系统

  • 深入理解操作系统(调度,内存,网络,IO)

  • 深入理解并发技术全景指南

  • 深入理解编程语言

  • 深入理解算法与数据结构

  • 深入理解网络协议

  • 深入理解网络编程

  • 深入理解性能优化

敬请期待:

  • 深入理解分布式技术

  • 深入理解数据库

  • 深入理解代码设计

  • 深入理解架构设计

详细了解:极客星球  ,现在加入超级优惠,早点加入一起学习成长,早点突破成长瓶颈:

d292b45c4455387568b979a6fae68c34.png

背景知识

30e0d4912337763a09d769a22cf11eac.png

netfilter是Linux内核内部的一个框架,该框架允许内核模块在Linux网络堆栈的不同位置注册回调函数。然后对于遍历Linux网络堆栈内各个挂钩的每个数据包,将调用已注册的回调函数。

netfilter / iptables能做什么?

  • 建立基于无状态和有状态数据包过滤的Internet防火墙

  • 部署高可用性的无状态和有状态防火墙集群

  • 如果您没有足够的公共IP地址,请使用NAT和伪装来共享Internet访问

  • 使用NAT来实现透明代理

  • 协助tc和iproute2系统用于构建复杂的QoS和策略路由器

  • 进行进一步的数据包处理(处理),例如更改IP标头的TOS / DSCP / ECN位

在内核协议栈位置大概是这样:

4c6bdb0d2d12b8a69aa1a3c3e1a586c9.png

netfilter 注册HOOK函数位置:

2be2158a65d14cb42dc814699eb73653.png

5个HOOK点:

PREROUTING:数据包进入路由表之前

INPUT:通过路由表后目的地为本机

FORWARD:通过路由表后,目的地不为本机

OUTPUT:由本机产生,向外发送

POSTROUTIONG:发送到网卡接口之前。

每个HOOK点都会执行一些函数,大致分为下面几个表:

NAT表: 用于实现nat功能,端口映射,地址映射等

mangle表: 用来修改报文,例如更改IP标头的TOS / DSCP / ECN位

filter表:用来过滤报文

raw表:用来提前标记报文不走一些流程(比如不需要建会话)

如果不熟悉不要紧,只需知道在协议栈收发关键入口(进入,转发,发出)注册一些 hook函数,然后报文会经过hook里面函数处理,而这些hook的动作(函数)是需要一个iptables的工具下发配置生成的。

iptables是您下发规则的用户态工具。IP表中的每个规则都由多个分类器(iptables匹配项)和一个连接的动作(iptables目标)组成。命令格式可参考下图,详细可以参考man手册:

93c5b23c900fe89f18b693dd68c8d4cc.png

这里记住两个动作就行了,ACCEPT表示通过,DROP表示丢掉;

内核里面看到的规则大概是这个样子:

98c4f0489f31312bc44ec856c8b5c6a9.png

主要特点

  • 无状态数据包过滤(IPv4和IPv6)

  • 有状态的数据包过滤(IPv4和IPv6)

  • 各种网络地址和端口转换,例如NAT / NAPT(IPv4和IPv6)

  • 灵活可扩展的基础架构

  • 第三方扩展的API

所以大多数公司会基于netfilter框架实现软件防火墙(安全组)和软件虚拟交换机(vswitch,类似ovs)。

好,背景简单介绍完了,如果不是很理解,后面会详细介绍的,来看一下这个客户实际问题。

分析过程

1.先了解网络拓扑

ff6d56f960c79b556829c978a5ceaaf4.png

客户网络拓扑是相当的简单,就是同网段下client机器访问服务器,一台可以访问,一台不可以。

2. 查看配置是否丢失

由于是同网段,相当于局域网通信,C1都可以访问S,那在S上路由肯定是ok的。对于服务端 10.0.0.3 而言,两台客户端机器到本机的iptable规则都是一样的。但10.0.2.8到10.0.0.3 的20202端口的syn包被丢了,而10.0.2.7 到 10.0.0.3 的 20202 端口的访问是正常的。

b3830ebf4c7b675ba21a5327b1124555.png

配置都在,需要进一步分析。

3. 抓包分析

client端发起telnet命令连接server, server按client ip抓包, 发现只有TCP SYN请求过来,并无回包,确实是本机OS内丢包导致无法正常连接:

6961e90dfb1ababae303b1c07e845854.png

通过netstat可以查看服务器TCP统计: 连接数不高,没有TCP队列丢包统计,结合10.0.2.7 client可以访问,进一步确认,放通安全组后,10.0.2.8 到 10.0.0.3 的 icmp 包也没有回,这个时候和TCP协议处理没有必然关系了。

4. 追踪内核丢包调用栈

报文如果被内核丢弃后,正常情况都会调用kfree_skb函数,内核通过kfree_skb释放skb,kfree_skb函数中已经埋下了trace点,并且通过__builtin_return_address(0)记录下了调用kfree_skb的函数地址并传给location参数,可以通过systemtap脚本,追踪kfree_skb这个trace point, 找到匹配ip的丢包并输出对应的堆栈:

/**
 *      kfree_skb - free an sk_buff
 *      @skb: buffer to free
 *
 *      Drop a reference to the buffer and free it if the usage count has
 *      hit zero.
 */
void kfree_skb(struct sk_buff *skb)
{
        if (unlikely(!skb))
                return;
        if (likely(atomic_read(&skb->users) == 1))
                smp_rmb();
        else if (likely(!atomic_dec_and_test(&skb->users)))
                return;
        trace_kfree_skb(skb, __builtin_return_address(0));
        __kfree_skb(skb);
}
EXPORT_SYMBOL(kfree_skb);


/*
 * Tracepoint for free an sk_buff:
 */
TRACE_EVENT(kfree_skb,

        TP_PROTO(struct sk_buff *skb, void *location),

        TP_ARGS(skb, location),

        TP_STRUCT__entry(
                __field(        void *,         skbaddr         )
                __field(        void *,         location        )
                __field(        unsigned short, protocol        )
        ),

        TP_fast_assign(
                __entry->skbaddr = skb;
                __entry->location = location;
                __entry->protocol = ntohs(skb->protocol);
        ),

        TP_printk("skbaddr=%p protocol=%u location=%p",
                __entry->skbaddr, __entry->protocol, __entry->location)
);

systemtap脚本:

# cat mydropwatch.stp
#!/usr/bin/stap --all-modules
%{
#include <linux/kernel.h>
#include <linux/net.h>
#include <linux/textsearch.h>
#include <net/checksum.h>
#include <linux/dma-mapping.h>
#include <linux/netdev_features.h>
#include <linux/skbuff.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/udp.h>
#include <uapi/linux/tcp.h>
%}
############################################################
# dropwatch2.stp
# An example script to mimic the behavior of the dropwatch utility
# Reports every 5 seconds with timestamp
# Usage: stap -g --all-modules mydropwatch.stp //-g for guru mode
############################################################
function get_packet_info:string(skb:long)
%{
     int ret=-1;
     unsigned int src_port = 0;
     unsigned int dest_port = 0;
     struct udphdr *udp_header;
     struct tcphdr *tcp_header;
     struct sk_buff *skb= (struct sk_buff *)STAP_ARG_skb;
     struct iphdr *ip_header;
     unsigned int src_ip=0,dest_ip=0;
     if(!skb)
     {
         goto EXIT_F;
     }
     ip_header = (struct iphdr *)skb_network_header(skb);
     if(!ip_header)
     {
       goto EXIT_F;
     }
     src_ip = (unsigned int)ip_header->saddr;
     dest_ip = (unsigned int)ip_header->daddr;
#if 0
     if (ip_header->protocol==17) {
            udp_header = (struct udphdr *)skb_transport_header(skb);
            src_port = (unsigned int)ntohs(udp_header->source);
        } else if (ip_header->protocol == 6) {
            tcp_header = (struct tcphdr *)skb_transport_header(skb);
            src_port = (unsigned int)ntohs(tcp_header->source);
            dest_port = (unsigned int)ntohs(tcp_header->dest);
        }
     printk(KERN_INFO "OUT packet info: src ip: %u, src port: %u; dest ip: %u, dest port: %u; proto: %u\n", src_ip, src_port, dest_ip, dest_port, ip_header->protocol);
#endif
    // printk(KERN_DEBUG "IP addres = %pI4  DEST = %pI4\n", &src_ip, &dest_ip);
EXIT_F:
     snprintf(STAP_RETVALUE, MAXSTRINGLEN, "%d.%d.%d.%d",(unsigned int)((unsigned char *)&src_ip)[0],(unsigned int)((unsigned char *)&src_ip)[1],(unsigned int)((unsigned char *)&src_ip)[2],(unsigned int)((unsigned char *)&src_ip)[3]);
%}
# Array to hold the list of drop points we find
global locations
# Note when we turn the monitor on and off
probe begin { printf("Monitoring for dropped packets\n") }
probe end { printf("Stopping dropped packet monitor\n") }
# increment a drop counter for every location we drop at
probe kernel.trace("kfree_skb") {
  SrcIp=get_packet_info($skb)
  //if(SrcIp=="10.0.2.8")//src ip of packet is "10.0.2.8"
 // printf("srcip:%s\r\n",SrcIp)
  if(SrcIp==@1)
  {
    locations[$location] <<< 1 //systemtap Statistical aggregate
    if(symname($location)=="nf_hook_slow")//dump the backtrace if kfree_skb called by nf_hook_slow function
    print_backtrace();
  }
}
# Every 5 seconds report our drop locations
probe timer.sec(5)
{
//  printf("\n=== %s ===\n", ctime(gettimeofday_s()))
  foreach (l in locations-) {
    printf("\n=== %s ===\n", ctime(gettimeofday_s()))
    printf("%d packets dropped at %x (%s)\n",
           @count(locations[l]), l, symname(l))
  }
  delete locations
}
### mydropwatch.stp ends ###

执行方法:

stap -g -v --all-modules mydropwatch.stp 10.0.2.8

执行命令后,对应输出:

14c8b624ebd954e17e690a06e8aa2603.png

从调用栈可知是在ip_local_deliver函数时因为iptables规则导致的丢包,结合内核代码:

c5ecf92d5e8a292e713848537bd7badf.png

nf_hook_slow+0xf3 对于代码188行(先找到对应内核版本的源代码,用crash工具打开对应内核版本的vmlinux,反汇编函数查看指令偏移,定位到源代码行号):

f54a2037ef5b55b2ce118d8ddc7d6ed4.png

可知是在INPUT链丢的包, 但是检查了mangle, nat, filter等表的INPUT链,并无其他drop规则,默认policy均为ACCEPT, 所以这里有点奇怪。

为了确定是否真的匹配上了ACCEPT规则,我在规则前后添加了打印log规则,报文匹配后会打印log出来:

a802057de8a72937db24677400d89d86.png

显示确认一下:

ce07d159597adcfcd72585d8facde7ac.png

通过触发请求,匹配上了第一个打印log的规则,10.0.2.8白名单规则命中计数有新增,而第二log规则没有匹配上,说明报文命中了白名单规则,报文可以通过防火墙:

968e69186b20634f01c8cfd3c7732ab1.png

但为什么服务端没有回syn+ack呢,是不是某种场景触发了netfiler框架的bug,假装accept,实际上把报文悄悄地给丢了?  结合报文和系统环境,看了几遍netfiler代码后,没有看出啥问题,清空iptables规则,停了firewalld,依然丢了,还是丢在 nf_hook_slow,也进一步证明不是普通iptables规则导致的。

如果要继续排查,是不是得遍历下内核数据结构,看看是不是list坏掉了,由于时间比较紧迫,遍历内核数据结构有点麻烦,需要找到netfiler hook表起始地址,再结合数据结构算出偏移,一步一步遍历内存,由于客户机器可以重启(业务已经不正常了),客户相信,重启可以比我们更快解决问题,还是重启大法好3a766ad3518157ea93e3e496d42cfec5.png,但不幸的是,机器重启完后没有恢复,问题依然存在,这个就有意思了。

5. 排查其他netfilter hook(钩子)函数

那么,有没有可能是有其他内核模块在INPUT链中注册了hook函数,drop了对应的包呢?我们使用crash调试内核来找一下:

背景知识

crash是redhat的工程师开发的,主要用来离线分析linux内核转存文件,它整合了gdb工具,功能非常强大。可以查看堆栈,dmesg日志,内核数据结构,反汇编等等。crash支持多种工具生成的转存文件格式,如kdump,LKCD,netdump和diskdump,而且还可以分析虚拟机Xen和Kvm上生成的内核转存文件。同时crash还可以调试运行时系统,直接运行crash即可,ubuntu下内核映象存放在/proc/kcore。

5.1. 从nf_hooks找到ipv4 INPUT链的hook列表

内核hook的组织:

9626771fb95680b0e40f8d000f18cfb8.png

那么对于NFPROTO_IPV4协议的NF_INET_LOCAL_IN链,我们可以找到其链表地址:

3f410c4e269f2dac41858bbda0ea9e14.png

43fe9315a9843f68b1c3e867882bfc39.png

可以看到有一个非标模块resguard_linux引入了非标hook函数net_hook_in_v4,反汇编net_hook_in_v4函数,可知其有一些白名单/黑名单之类的检查:

00b07744310dcee918e813822ba45738.png

由此基本可以确定是这个模块的安全功能利用netfilter hook拦截了访问。

他大爷的,还真的注册了nf hook9bddc2d5b89a40b8967b606276e9d931.png

但要客户认账,还得证明这个包就是这个hook函数丢的,其实已经差不多了。

5.2. 如何证明是net_hook_in_v4返回NF_DROP(0x0)导致的丢包?

可以结合systemtap得到skb地址,然后通过perf probe抓取net_hook_in_v4和nf_iterate的返回值:

脚本:

947de9adcd0dce46e975e91c423db3b2.png

运行结果:

f40e9b5c0538c78f398e1af56b4871f2.png

由此可以看出bb2100结尾的这个skb是因为nf_hook_in_v4导致的丢包。

网上搜索可知该第三方安全模块疑似云锁这类软件提供,他可以通过ip黑白名单控制对网站的访问。

问题算是终于结束了,想着之前催得那么急,真想在线battle一下,然而客户是大爷,不敢想,不敢想a3fe7a8bb2268297089f3627325018fa.png

可以学到什么

1. 大致了解Linux防火墙实现框架:netfilter+iptables;

2. 通过systemtap脚本追踪内核协议栈丢包堆栈信息;

3. 怎么通过堆栈函数和指令偏移找到源代码信息;

4. 一些丢包排查思路;

5. 了解一些工具使用,比如systemtap,crash,iptables,tcpdump等等;

最后,希望本文可以对你有所帮助,谢谢观赏,有任何问题可以在评论区留言bc45c9c63eb19e2d45ff40245f23128d.png,如果觉得文章不错,麻烦一键三连支持93bbe5061a925948cfef769cef9ce223.png3231b9aba666f5a747d416b540755433.png



欢迎加入极客星球圈子,全网专业且高质量学习圈子:

  • 修炼基本功:分享多年基础技术深度理解(比如深入理解系列),基础概念深度解析等等;

  • 扩展技术和商业视野:真正的分享海内外技术发展,大厂技术内幕,业界解决方案;

  • 校招/高薪/跳槽涨薪/大厂:关于一切找工作问题分享,面试问题,简历修改,面试经验,面试问题答疑,各类大厂制定后端学习路线和指导;

  • 职场普升/技术专家:分享各种不同公司宝贵的职场普升经验,核心员工,职场潜规则, 团队合作,做事经验,普升经验,技术深耕经验,少走弯路;

  • 专属交流群:高手交流,开阔眼界,分享心得,每天成长,厚积薄发,任何技术问题,任何疑难杂症,都可以咨询,讨论,交流!

   详细了解:极客星球  ,现在加入超级优惠,早点加入一起学习成长,早点突破成长瓶颈:

a9ff673822e109c810f40bcb35946728.png

扫码加入

577e93f42cddcee6c848417bba99e55a.jpeg

计算机网络硬核指南|网络设计核心思想

求点赞关注,在看,分享三连c8bee8d1d51e4b49ad99e01ed1df515e.png

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

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

相关文章

有奖征文 | 夙兴夜寐,铸梦网安

出品&#xff5c;MS08067实验室&#xff08;www.ms08067.com&#xff09; 本文作者&#xff1a;潜龙勿用 01 时光荏苒&#xff0c;流年岁月如白驹过隙&#xff0c;不停飞逝于眼前&#xff0c;在这车马星驰的人间&#xff0c;踏入网络安全领域已然三年有余。我也终于从一开始的不…

左移右移 2022年国赛 思维

思路&#xff1a; 简单的思维题&#xff0c;应该从后往前遍历操作。如果后面的对数i操作过&#xff0c;则前面对数i的操作都可以无视。可以通过栈这种数据结构实现后往前遍历。 AC代码&#xff1a; import java.io.*; import java.util.*; public class Main{public static …

Linux常用命令——groupdel命令

在线Linux命令查询工具 groupdel 用于删除指定的工作组 补充说明 groupdel命令用于删除指定的工作组&#xff0c;本命令要修改的系统文件包括/ect/group和/ect/gshadow。若该群组中仍包括某些用户&#xff0c;则必须先删除这些用户后&#xff0c;方能删除群组。 语法 gro…

LC3-仿真器的安装

LC3-仿真器安装 参考&#xff1a;Download and Install LC-3 | CS 131 - Computer Organization (comp-org-etext.netlify.app) 如觉得本文写的不够详细&#xff0c;可参考如上网址。 介绍 小型计算机LC-3 汇编环境是一种模拟指令架构&#xff08;ISA&#xff09;&#xff0c;…

wpf 3d复习1

之前研究过一段wpf 3d显示机械臂的代码&#xff1b;复习一下看一下&#xff1b; 它的摄像机位置是&#xff0c;0.491531,0.298732,0.321531&#xff1b; 我想把看到物体变小&#xff1b;就是摄像机移远&#xff1b;把摄像机坐标都乘以3&#xff0c;变为 &#xff0c; …

chatgpt赋能python:Python平均值函数简介

Python平均值函数简介 Python是一种广泛使用的编程语言&#xff0c;因为它易于学习&#xff0c;语法简单&#xff0c;可以完成广泛的任务和应用程序开发。 在Python编程中&#xff0c;平均值函数是最基本、最常用的函数之一。平均值可以用来表示一组数据集的中心趋势指标。让…

微软为 VS Code 带来 C# 开发套件

微软于今天在 Marketplace 上架了一款适用于 Visual Studio Code 的官方 C# 开发套件 —— C# Dev Kit&#xff0c;通过更好地管理、测试&#xff0c;以及提供全新的 AI 功能&#xff0c;为 Linux、macOS 和 Windows 平台的开发者带来了更好的 C# 开发体验。 根据微软官方提供的…

关于语言模型私有化部署的讨论 | AIGC实践

上周在与TC同行关于AIGC实践的线上交流中&#xff0c;大家普遍比较关心的一个实践切入点是&#xff1a;语言模型的私有化部署——简单来说&#xff0c;就是在企业内部&#xff0c;部署一个属于自己的“ChatGPT”&#xff0c;对于本行业/专业知识&#xff0c;以及企业独有的产品…

【学习日记2023.6.7】之 MyBatisPlus入门

文章目录 MybatisPlus1. 入门案例1.1 SpringBoot整合MyBatisPlus入门程序 2. MyBatisPlus概述2.1 MyBatis介绍2.2 MyBatisPlus特性 3. MyBatisPlus的CRUD操作4. MyBatisPlus分页功能5. 开启MyBatisPlus日志5.1 解决日志打印过多问题5.1.1 取消初始化spring日志打印5.1.2 取消Sp…

基于SpringBoot+Vue的学生考勤管理系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…

【Web服务器】基于Nginx搭建LNMP架构

文章目录 一、安装 MySQL 数据库1. 安装Mysql环境依赖包2. 创建运行用户3. 编译安装4. 修改mysql 配置文件5. 更改mysql安装目录和配置文件的属主属组6. 设置路径环境变量7. 初始化数据库8. 添加mysqld系统服务9. 修改mysql 的登录密码10. 授权远程登录 二、编译安装 nginx 服务…

2024」预备研究生mem-论据和结论为简单句(下)

一、论据和结论为简单句-建立联系 二、结论包含完成推理 改版&#xff1a; 三、课后题

盘点一个Python网络爬虫问题

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 在天愿作比翼鸟&#xff0c;在地愿为连理枝。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者群【刘桓鸣】问了一个Python网络爬虫的问…

8自由度并联腿机器狗实现行走功能

1. 功能说明 本文示例将实现R309a样机8自由度并联腿机器狗行走的功能。 2. 并联仿生机器人结构设计 机器狗是一种典型的并联仿生四足机器人&#xff0c;其腿部结构主要模仿了四足哺乳动物的腿部结构&#xff0c;主要由腿部的节段和旋转关节组成。在设计机器狗的腿部结构时&…

实用教学Prompt 提示词实战:如何用 ChatGPT 指导高考语文作文写作

又是一年高考季&#xff0c;牵动着广大学生和家长的心。7 日上午&#xff0c;语文科目考试结束。 今年高考语文共7套试卷&#xff1a;全国甲卷、全国乙卷、新课标Ⅰ卷、新课标Ⅱ卷、北京卷、天津卷、上海卷。 以高考语文作文题目来实践检验一下&#xff0c;如何用合适的提问词&…

chatgpt赋能python:Python将首字母变成大写——提升SEO排名的一种简单方法

Python将首字母变成大写——提升SEO排名的一种简单方法 在SEO行业中&#xff0c;优化关键字密度和网站结构是常规且必要的工作。但是&#xff0c;除此之外&#xff0c;我们也应该注意到一些看似微不足道但可能对网站排名产生影响的细节。比如&#xff0c;对于文章标题和正文的…

Mocha AE:Track 模块

当对跟踪踪结果不是很满意的时候&#xff0c;可尝试更改下 Track&#xff08;跟踪&#xff09;模块中的选项之后重新跟踪。 Input 输入 Clip 剪辑 选择要跟踪的素材。 --Input 输入 --Layer Below 下方图层 Track Individual Fields 跟踪单个场 针对隔行扫描素材&#xff0c;…

【IMX6ULL驱动开发学习】01.安装交叉编译环境【附下载地址】

第一步&#xff08;下载工具链&#xff09;&#xff1a; 从官网上下载交叉编译工具链 https://snapshots.linaro.org/gnu-toolchain/ 按照以下步骤选择 可以选择最新的&#xff08;我也忘记我用的哪个版本了&#xff0c;都可以用问题不大&#xff09; 第二步&#xff08;…

【Rust日报】2023-06-06 motus 一个非常方便的命令行密码生成工具

motus 一个非常简单的命令行密码生成工具 Motus是一个命令行应用&#xff0c;帮你轻松生成安全密码。 它的用户界面非常简单、优雅&#xff0c;跟 1Password 的密码生成器一样&#xff0c;让你感觉很舒服。Motus 默认会把生成的密码复制到你的剪贴板&#xff0c;用起来非常方便…