分类:linux

Linux TC

tc - 显示/操作流量控制(traffic control)设置

tc 用于配置 Linux 内核中的流量控制。流量控制包括以下几个方面:

整形(SHAPING)当流量被整形时,其传输速率会受到控制。整形不仅仅是降低可用带宽,它还用于平滑流量的突发,以改善网络行为。整形发生在出口端(egress)。

调度(SCHEDULING)通过调度数据包的传输,可以改善需要交互的流量的表现,同时保证大流量传输的带宽。重新排序也称为优先级设置,仅在出口端发生。

检测(POLICING)整形处理的是传输中的流量,而检测处理的是到达的流量。因此,检测发生在入口端(ingress)。

丢弃(DROPPING)超出设定带宽的流量也可能会被立即丢弃,这在入口端和出口端都会发生。

流量处理由三种对象控制:qdiscs、classes 和 filters。

qdisc 是 “队列规则 (queueing disciplin)” 的简称,对于理解流量控制至关重要。每当内核需要将数据包发送到接口时,它会被排入配置好的 qdisc 中。紧接着,内核会尽可能多地从 qdisc 中取出数据包,交给网络适配器驱动。

简单的 QDISC 是 “pfifo”,它不进行任何处理,仅仅是一个纯粹的先进先出(FIFO)队列。它在网络接口暂时无法处理流量时,会存储这些流量。

一些 qdiscs 可以包含 classes,这些 classes 进一步...

ChatGPT 带你学习 iptables

对于 iptables 学习,反复看过 man iptables 命令,但是缺乏归纳总结,不用就忘了。现在好了,直接让 ChatGPT 帮我画一些系统框图辅助记忆。

这个图表演示了 iptables 中 5 个 Chain 处理的先后关系,其中:

  • INPUT Chain 用于处理进入本地计算机的网络数据包;
  • PREROUTING Chain 用于处理数据包路由前的操作,例如修改目标 IP 地址;
  • ROUTING Chain 用于处理数据包的路由过程,例如根据路由表进行转发;
  • FORWARD Chain 用于处理转发给其他计算机的网络数据包;
  • POSTROUTING Chain 用于处理数据包路由后的操作,例如修改源 IP 地址;
  • OUTPUT Chain 用于处理从本地计算机发出的网络数据包;
  • INPUT Chain:允许来自特定 IP 地址的 SSH 连接

  • PREROUTING Chain:将来自特定 IP 地址的数据包重定向到另一台计算机

  • ROUTING Chain:将来自特定 IP 地址的数据包标记为优先级 1

  • FORWARD Chain:允许从特定网卡转发特定端口的数据包

  • POSTROUTING Chain:将来自特定 IP 地址的数据包修改为指定 IP 地址并从指定网卡发出

  • OUTPUT Chain:允许从本地计算机发出到特定 IP 地址和端口的数据包

GCC 未使用函数、变量和文件优化策略

GCC 优化过于复杂,这里探索 GCC 对未使用的代码和变量以及文件的优化策略。

如下两个文件。

main.c 文件内容如下。

unused.c

  • 默认编译选项,通过可执行文件确定所有变量和函数都未优化。

  • -O1 -O2 -Os 选项,所有static 链接属性的变量和函数被用优化掉。

  • 为 static 链接属性的变量增加 __attribute__((used)) 属性。优化被抑制。

  • 增加 -Wl,--gc-sections 选项,所有的 unused.c 变量和函数,以及 main.c 中的变量全部被优化。

  • 同时使用 -Wl,--gc-sections 和 -O1。进一步优化掉 main.c 中的 static 函数,只剩下最后一个未使用的 extern 函数。

  • 同时使用 -Wl,--gc-sections 和 -O2 或者 -Os 。所有未使用的函数、变量全部被优化。

  • 或者额外指定 -ffunction-sections ,进一步把未使用的函数优化掉。

  • 对于--gc-sections ,通过设置 KEEP 链接抑制变量的优化。注意,并不能对函数使用属性。

固件安全之 TF-A 和 SecureBoot

这里详细介绍基于 ARMv8-A AArch64 固件安全相关,包含 TF-A(Trust Firmware A)。以及基于TF-A OEM厂商对 U-Boot 和 Kernel 实现的安全启动流程 SecureBoot。

对于 TF-A,ARMv8-A AArch64 架构需要满足如下设计需求。

  • 区分不同的异常等级(Exception Level);

对于不同的安全等级区分了可信的世界(Trust World)和非可信世界(Non-Trusted World)。我们的应用程序,内核都工作它认为不可信世界,所以没有办法直接访问一些资源。

  • 不同安全等级下访问不同的硬件资源。

例如一些 OTP/eFUSE区域,在 EL0-EL2 异常等级应用程序是没有办法直接访问的。如果需要访问这些资源,通过 SMC 共享内存通过工作更高等级例如 EL3 的程序实现间接访问。

有了如上认识,接下来我们梳理 TF-A 约定的在不同 EL下的引导程序。

通常地,对于ARM AArch64 如下开机执行如下引导顺序。

BL1 作为 ROM Bootloader 工作在最高安全等级 EL3,它拥有独立的 Trusted...

Linux capabilities

  • 对于权限细节参考man 7 capabilities;
  • 对于-+= eip操作符参考 man 3 cap_from_text;
  • 文档中命令setcap、getcap等都可以通过man命令查看;

我需要在VS Code 调试NuttX应用,它的Sim应用需要cap_net_raw,cap_net_admin权限,否则就无法正常操作HCI设备。

当然网上有一些帖子尝试将VS Code或者GDB运行在root用户,显然这样操作是非常不优雅的。

所以这里尝试给需要调试的应用利用linux capabilities直接给可执行文件设置权限。

此时运行程序,可以通过capsh或者getcaps检查进程确认已经设置成功。

此时通过VS Code启动调试后发现其却没有了需要的文件权限。

看起来是父进程/usr/bin/gdb 启动nuttx进程的时候并没有使用其文件文件属性。

直接测试了gdb ./nuttx确认和上面现象一致,strace确认其通过ptrace创建进程。

怀疑这里是gdb进程没有cap_sys_ptrace权限,添加后再次通过VS Code启用nuttx调试发现其进程已经具有我们需要的权限。

udp发送ip端口发送不可达

众所周知,udp是无连接的,所以忽略udp接收方状态,是否监听对应udp端口以及ip是否存在,直接向udp发送数据,会发生什么?

为了搞清楚这个问题,我们尝试在局域网建立收发设备,然后抓包分析。

从抓包来看,udp数据正常发出。对端设备回复icmp指示端口不可达。

当我们把接收端设备关机,此时udp数据正常发出,直到arp连续三次请求失败。此时抓包显示udp包已经不发送了。

此时,我们跟踪sytem call 确定,发用户空间的sendto 接口仍然显示成功。

此时通过查看arp缓存确定ip状态已经标记为INCOMPLETE。

尝试手动更新arp缓存的mac地址和状态到REACHABLE。

此时udp又重新发了出来。

值得一提的是,在路由器查看arp缓存,发现不管设备断开多久,状态都不会变更为INCOMPLETE而始终是STALE。

vscode 通过数据断点分析segmentation fault

通常地,程序异常,我们借助vscode在ubuntu主动调试,程序会自动在异常代码位置停下来,但是异常分析通常不会这么简单,而是一连串连锁反应。

这里尝试分析,因为程序异常,非法写入了一段正常内存,从而导致多个链路之后异常发生。而对于此问题,最常使用的调试手段就是添加数据断点。

通常直接在某段代码位置添加的代码为函数断点,程序会自动在该位置停下来。同样地,我们可以添加条件断点:

  • 当某个判断条件(例如,变量值为真)满足的时候;
  • 当某段代码连续执行N次的时候;
  • 当某个变量(内存)被读写的时候;

如上前两个条件断点,vsocde 里面的c/c++ extension 已经支持,可以在ide里面点击断点(红色小点)直接编辑,但是最后一个为数据断点还不支持。

需要借助debug console 键入gdb(gnu debugger)命令,

如上操作,成功初始化device_scan_ 成员变量后,程序不再会对变量进行写操作,但是之后该对象的一个成员变量值被异常写入了非法值,当再次用该对象指针打印日志函数时候发生异常。

此时通过p命令查看变量并获取变量首地址。

通过watch命令监控该地址的写操作。

之后全速运行,发现程序在另外一个非法访问该变量位置停了下来,并且通过 Old Value和New Value提示了值变化。

通过分析上下文就可以定位到引发异常的真正原因。

socat

http://www.dest-unreach.org/socat/

socat 是一个命令行工具,用以建立一个双向字节流交换数据。该字节流又可以被构造成不同地址类型,大量的地址选项也同样可以被作用于该流,因此socat非常强大。

filan 是一个打印文件描述符的工具,已经被重构用以调试socat,当然,也可以另做它用。

procan 是一个打印进程信息的工具,同样被重构用以调试socat。

socat 实例包含如下生命周期。

init 阶段解析命令参数,初始化日志打印;

open阶段打开第一个地址并且转发到第二个地址字节流,此阶段可能会阻塞,因此类似socks的复杂地址选项,需要在连接请求或认证对话框完成后才会开始下一阶段。

transfer阶段通过select 参数观察源地址流的读写操作,当可读或者可写时,socat完成到目的流数据转发。

当任意一方流eof,closing阶段开始,socat 主动发送eof操作到对等需要关闭的另外一方尝试优雅的关闭它的写操作的字节流,在运行的时间范围内,socat也可能会继续传输数据到另外一个方向,直到所有的通道被关闭。

命令的地址参数为用户给socat 建立字节流的必要信息。

一个地址规范通常包含一个地址类型的关键词,零或者多个地址参数通过":"间隔,零或者多个地址选项通过","间隔。

关键词指定地址类型(tcp4、open、exec),而对于一些关键字存在...

学习uboot中 U_BOOT_CMD命令参数编程

学习到一个奇淫技能,这里总结如下。方便以后工程实现。

在uboot中大量的命令交互,这些命令都对应其参数、help、和命令处理函数。

通常做法去解析参数名称后遍历每一个命令名称,选择执行。也就是通常的switch、case做法。

uboot给出了不一样的操作。

先看uboot怎么做。

之后对于对应console 键入命令version就能够查找到该命令处理函数 do_version 执行。

接下来,剖析背后细节。

对于do_version通过U_BOOT_CMD完成了函数申明。

include/command.h#L368

include/command.h#L325

include/linker_lists.h#L70

include/command.h#L353

include/command.h#L237

最终U_BOOT_CMD申明定义了结构体类型为cmd_tbl 的变量_u_boot_list_2_cmd_2_version 并且完成了该命令的初始化赋值。

对于如上的变量属性操作__aligned、__attribute__参考6.35 Specifying Attributes of Types。__attribute__(4)表示改结构体变量4字节对齐,__attribute__声明该变量属性可能不...

在linux 下通过vscode调试elf可执行文件

elf 是linux 下可执行可链接文件(executable and linkable format)。通过gcc/make 我们很容易编译出我们需要的elf文件,借助vscode可以在ubuntu图形化调试该程序,再也不用在gdb命令操作了。

如下是elf文件结构,包含文件头(elf header)和代码、数据区索引表(program header table、section header table)和对应代码区、数据区。

明白了如上文件结构,还需要具体解答如下疑惑。

  • 什么文件可以被调试?

    通过file命令对比可以知道用以调试的文件包含 with debug_info。

    可以被调试的文件。

  • debug 版本额外包含什么信息?

    如上可调式的elf文件中增加包含 debug_aranges、debug_info等7个section存储包含数组、文件信息、行数、字符串、宏等调试信息。

    可以通过 --debug-dump=aranges/info/abbrev/line/str/ranges/macro分别显示对应的 区信息。

  • 如何设置debug/release 版本?

    知道了用以调试的程序信息,那么如何编译对应程序的debug版本,通常来说编gcc的 -gdebug 选项和-O优化选项:

有了如上elf文件认识,接下来就是vscode debug程序了,成功编译可执行文件后,通过vscode 建立工程添...