Keep learning, keep living...

0%

流量控制Traffic Control简称TC,表示网络设备接收和发送数据包的排队机制。比如,数据包的接收速率、发送速率、多个数据包的发送顺序等。

Linux实现了流量控制子系统,它包括两部分:

  • 内核部分的traffic control框架
  • 用户态的规则配置工具:iproute2软件包中的tc程序

它们有些类似于内核态的netfilter框架和用户态的iptables程序。但相较于netfilter, 关于tc的资料非常少,并且也较为古老,彻底理解它的机制还是需要对照源码。

Traffic Control的作用包括以下几种:

  • 调整(Shaping): 通过推迟数据包发送来控制发送速率,只用于网络出方向(egress)
  • 时序(Scheduling):调度不同类型数据包发送顺序,比如在交互流量和批量下载类型数据包之间进行发送顺序的调整。只用于网络出方向(egress)
  • 监督(Policing): 根据到达速率决策接收还是丢弃数据包,用于网络入方向(ingress)
  • 丢弃(Dropping): 根据带宽丢弃数据包,可以用于出入两个方向
阅读全文 »

在一些业务环境的VMware Guest虚拟机上安装我们的内核模块后,偶尔虚拟机会变成无响应的状态。重启后登录系统查看,处于无响应状态的那段时间在/var/log/messages中却没有任何信息,完全没有分析问题原因的头绪。

经过调研,找到两种方法可以帮助排查定位这类系统失去响应的问题,分别是:

  • 发送NMI: Non-Maskable Interupt给虚拟机
  • VMware内存快照
阅读全文 »

最近CentOS7服务器上遇到一个系统崩溃:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[92957.332974] BUG: unable to handle kernel NULL pointer dereference at 0000000000000a30
[92957.332981] IP: [<ffffffffc086077d>] nf_ct_deliver_cached_events+0x2d/0x110 [nf_conntrack]

......

[92957.333112] CPU: 1 PID: 5027 Comm: Verdict3 Kdump: loaded Tainted: G OE ------------ T 3.10.0-1160.el7.x86_64 #1
[92957.333114] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 12/12/2018
[92957.333116] task: ffff893cad135280 ti: ffff893c4f524000 task.ti: ffff893c4f524000
[92957.333118] RIP: 0010:[<ffffffffc086077d>] [<ffffffffc086077d>] nf_ct_deliver_cached_events+0x2d/0x110 [nf_conntrack]
[92957.333125] RSP: 0018:ffff893c4f527810 EFLAGS: 00010246
[92957.333127] RAX: 0000000000000000 RBX: ffff893ca41e5140 RCX: ffffffffa035de80
[92957.333128] RDX: ffff893c4f527fd8 RSI: 0000000000000200 RDI: ffff893ca41e5140
[92957.333130] RBP: ffff893c4f527850 R08: 0000000000000000 R09: ffff893ca41e5178
[92957.333131] R10: 0000000000000001 R11: ffff893ca41e5140 R12: ffff893ca41e5140
[92957.333132] R13: ffff893c9491a500 R14: ffffffffa0367e40 R15: 0000000000000000
[92957.333135] FS: 00007fbda1d78700(0000) GS:ffff893d3fd00000(0000) knlGS:0000000000000000
[92957.333137] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[92957.333138] CR2: 0000000000000a30 CR3: 000000007fda4000 CR4: 00000000001607e0
[92957.333202] Call Trace:
[92957.333221] [<ffffffffc08372ce>] ipv4_confirm+0x4e/0x100 [nf_conntrack_ipv4]
[92957.333227] [<ffffffff9fc94e38>] nf_iterate+0x98/0xe0
[92957.333231] [<ffffffff9fc96240>] nf_reinject+0x160/0x1b0
[92957.333239] [<ffffffffc0a48566>] nfqnl_recv_verdict+0x216/0x310 [nfnetlink_queue]
[92957.333244] [<ffffffff9f9b4716>] ? nla_parse+0xb6/0x120
[92957.333247] [<ffffffffc09b03a2>] nfnetlink_rcv_msg+0x162/0x270 [nfnetlink]
[92957.333251] [<ffffffffc09b0240>] ? nfnetlink_net_exit_batch+0x70/0x70 [nfnetlink]
[92957.333254] [<ffffffff9fc9249b>] netlink_rcv_skb+0xab/0xc0
[92957.333257] [<ffffffffc09b089f>] nfnetlink_rcv+0x28f/0x575 [nfnetlink]
[92957.333260] [<ffffffff9fc90773>] ? __netlink_lookup+0xd3/0x130
[92957.333263] [<ffffffff9fc91e20>] netlink_unicast+0x170/0x210
[92957.333267] [<ffffffff9f99ca72>] ? memcpy_fromiovec+0x62/0xb0
[92957.333269] [<ffffffff9fc921c8>] netlink_sendmsg+0x308/0x420
[92957.333272] [<ffffffff9fc343a6>] sock_sendmsg+0xb6/0xf0
[92957.333277] [<ffffffff9fd86c8f>] ? __schedule+0x3af/0x860
[92957.333279] [<ffffffff9fc35269>] ___sys_sendmsg+0x3e9/0x400
[92957.333284] [<ffffffff9f712040>] ? futex_wake+0x90/0x180
[92957.333287] [<ffffffff9f714d2a>] ? do_futex+0x12a/0x5a0
[92957.333289] [<ffffffff9fc36921>] __sys_sendmsg+0x51/0x90
[92957.333292] [<ffffffff9fc36972>] SyS_sendmsg+0x12/0x20
[92957.333296] [<ffffffff9fd93f92>] system_call_fastpath+0x25/0x2a
阅读全文 »

SSH不仅可以使用远程管理主机,还可以利用SSH客户端和SSH服务器之间的加密连接为其他服务实际中继服务,这一般称为SSH隧道(SSH Tunneling)或者SSH端口转发

SSH端口转发分为三种类型:

  • 动态端口转发
  • 本地端口转发
  • 远程端口转发

无论是哪种端口转发,整个过程都涉及四个角色:

  • 业务客户端
  • SSH客户端
  • SSH服务器
  • 业务服务端

这些角色进程并不要求都位于独立主机上,它们可以位于同一台主机上,使用localhost或者127.0.0.1进行网络访问。

本文基于这4种角色来简要说明这三种端口转发的过程。三种端口转发都依赖SSH客户端SSH服务器建立一个加密连接在二者之间转发数据。

阅读全文 »

近期我们的BASH脚本中遇到一个BUG,最终分析到是变量值为空时没有用""包裹导致的。

我们使用一个测试脚本来进行分析。测试脚本t.sh内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

kof=""

if [ ! -f $kof ]; then
echo "1"
fi

if [ ! -f "$kof" ]; then
echo "2"
fi

echo "END"

测试脚本的执行结果如下:

1
2
3
[root@default ~]# bash t.sh
2
END

可以看到当变量$kof为空时,第一个if语句块中的语句没有被执行,而第二个if语句块中的语句被执行了。这两个语句块的差别就在于第二个语句块中的$kof变量用""进行了包裹。

阅读全文 »

近期遇到一个服务器上内核模块无法卸载的问题。执行rmmod命令返回错误信息:

1
Device or resource busy

通过Google搜索,发现其他人也遇到过类似的问题,原因基本指向是编译内核模块的gcc版本和编译内核的gcc版本不一致。

于是开始检查我们的环境。

阅读全文 »

seccomp代表secure computing,是早在2.6.12版本就引入到内核的特性,用来限制进程可以使用的系统调用。它作用于进程里的线程(task)。

最初,seccomp只允许使用read, write, _exit, sigreturn4个系统调用,调用其他系统调用时,内核会发送SIGKILL信号终止进程。当时seccomp的提出主要是想用于出租空闲的CPU算力。这种模式叫做STRICT模式。它限制过于严格,在实际应用上并没有太多发展。Linus Torvald甚至建议把它从内核中砍掉。

阅读全文 »

OTPOne Time Password的缩写,是进一步加强身份认证的安全性的校验方法, 一般配合常规密码一起使用。OTP动态生成,只使用一次。手机验证码就是典型的OTP方式。用户请求一个短信验证码, 服务器随机生成一个验证码,然后临时存储起来,通过短信发送给用户。用户在系统上输入验证码发送回服务器,服务器根据临时存储的验证码进行校验。

生成OTP业内有许多标准算法,比如SHA-1。所有这些算法都包括两部分输入:

  • 种子值(seed):静态值,和帐号关联的密钥
  • 可变因子(moving factor):每次生成OTP都变化的部分
阅读全文 »

之前的文章<<使用eBPF和BCC调查创建文件的进程>>介绍了基于BCC来实现eBPF程序。BCC实现了对eBPF的封装,用户态部分提供Python API, 内核态部分使用的eBPF程序还是通过C语言来实现。运行时BCC会把eBPFC程序编译成字节码、加载到内核执行,最后再通过用户空间的前端程序获取执行状态。
可以在BCCBPF调用中,指定参数debug=4, 我们可以看到BCC的执行过程, 如:

1
2
3
4
5
6
7
from bcc import BPF
BPF(text="""
#include <linux/ptrace.h>
int kprobe__tty_write(struct pt_regs *ctx, struct file *file, const char __user *buf, size_t count) {
return 0;
}
""", debug=4)

eBPF编程的门槛还是比较高的,在当前还是快速发展的情况,API也还不稳定,对程序员的C语言、编译过程和内核等知识都有比较高的要求。BCC把这些都封装起来给用户提供了一个更为简单的使用框架。但本身也存在的一些问题,比如:

  • 每次执行时都需要重新编译
  • 执行程序的机器都需要安装内核头文件

eBPF: extended Berkeley Packet Filter是对BPF(现在称为cBPF: classic BPF)的扩展, 现在尽管还叫做BPF, 但应用场景已经远远超过了它的名称的范畴。它的应用范围的扩大主要得益于这几方面:

  • 内核中BPF字节码虚拟机扩展为一个通用的执行引擎
  • 执行可节码的安全校验
  • JIT支持,可以直接将字节码指令转成内核可执行的原生指令运行

这样在安全性、可编程性和性能方面的提升都使得eBPF在包过滤以外的其他领域获取巨大的应用空间。

阅读全文 »

在我们的一个CentOS 7.8系统上,/tmp目录下偶尔会有一些随机名称的文件产生。业务比较久远,已经不清楚这些文件的来源,需要确定是哪个进程在创建它们。

LinuxVFS: Virtual File System通用文件模型的方式在物理存储介质上的文件系统和用户接口之间建立一个虚拟文件系统的抽象层。其中最重要的两个结构是:

  • inode: 存放文件的一般信息,每个inode结构都有自己的编号,这个号码唯一标识了文件系统中的文件。
  • dentry: 存放文件名称信息,以及与对应文件进行链接的有关信息。

VFS创建文件的最主要的步骤是:

  1. 为要创建的文件创建一个dentry结构
  2. 为要创建的文件创建一个inode结构并分配inode编号
  3. inode编号和文件名映射关系保存在所分配的dentry结构中
  4. dentry写入到父目录的数据区
阅读全文 »