近期我们的BASH
脚本中遇到一个BUG,最终分析到是变量值为空时没有用""
包裹导致的。
我们使用一个测试脚本来进行分析。测试脚本t.sh
内容如下:
1 |
|
测试脚本的执行结果如下:
1 | [root@default ~]# bash t.sh |
可以看到当变量$kof
为空时,第一个if
语句块中的语句没有被执行,而第二个if
语句块中的语句被执行了。这两个语句块的差别就在于第二个语句块中的$kof
变量用""
进行了包裹。
Keep learning, keep living...
近期我们的BASH
脚本中遇到一个BUG,最终分析到是变量值为空时没有用""
包裹导致的。
我们使用一个测试脚本来进行分析。测试脚本t.sh
内容如下:
1 | #!/bin/bash |
测试脚本的执行结果如下:
1 | [root@default ~]# bash t.sh |
可以看到当变量$kof
为空时,第一个if
语句块中的语句没有被执行,而第二个if
语句块中的语句被执行了。这两个语句块的差别就在于第二个语句块中的$kof
变量用""
进行了包裹。
近期遇到一个服务器上内核模块无法卸载的问题。执行rmmod
命令返回错误信息:
1 | Device or resource busy |
通过Google搜索,发现其他人也遇到过类似的问题,原因基本指向是编译内核模块的gcc
版本和编译内核的gcc
版本不一致。
于是开始检查我们的环境。
seccomp
代表secure computing
,是早在2.6.12
版本就引入到内核的特性,用来限制进程可以使用的系统调用
。它作用于进程里的线程(task
)。
最初,seccomp
只允许使用read
, write
, _exit
, sigreturn
4个系统调用,调用其他系统调用时,内核会发送SIGKILL
信号终止进程。当时seccomp
的提出主要是想用于出租空闲的CPU算力。这种模式叫做STRICT
模式。它限制过于严格,在实际应用上并没有太多发展。Linus Torvald
甚至建议把它从内核中砍掉。
OTP
是One Time Password
的缩写,是进一步加强身份认证的安全性的校验方法, 一般配合常规密码一起使用。OTP
动态生成,只使用一次。手机验证码就是典型的OTP
方式。用户请求一个短信验证码, 服务器随机生成一个验证码,然后临时存储起来,通过短信发送给用户。用户在系统上输入验证码发送回服务器,服务器根据临时存储的验证码进行校验。
生成OTP
业内有许多标准算法,比如SHA-1
。所有这些算法都包括两部分输入:
种子值(seed)
:静态值,和帐号关联的密钥可变因子(moving factor)
:每次生成OTP
都变化的部分之前的文章<<使用eBPF和BCC调查创建文件的进程>>介绍了基于BCC
来实现eBPF
程序。BCC
实现了对eBPF
的封装,用户态部分提供Python API, 内核态部分使用的eBPF
程序还是通过C
语言来实现。运行时BCC
会把eBPF
的C
程序编译成字节码、加载到内核执行,最后再通过用户空间的前端程序获取执行状态。
可以在BCC
的BPF
调用中,指定参数debug=4
, 我们可以看到BCC
的执行过程, 如:
1 | from bcc import BPF |
eBPF
编程的门槛还是比较高的,在当前还是快速发展的情况,API也还不稳定,对程序员的C
语言、编译过程和内核等知识都有比较高的要求。BCC
把这些都封装起来给用户提供了一个更为简单的使用框架。但本身也存在的一些问题,比如:
eBPF: extended Berkeley Packet Filter
是对BPF
(现在称为cBPF: classic BPF
)的扩展, 现在尽管还叫做BPF
, 但应用场景已经远远超过了它的名称的范畴。它的应用范围的扩大主要得益于这几方面:
BPF
字节码虚拟机扩展为一个通用的执行引擎JIT
支持,可以直接将字节码指令转成内核可执行的原生指令运行这样在安全性、可编程性和性能方面的提升都使得eBPF
在包过滤以外的其他领域获取巨大的应用空间。
在我们的一个CentOS 7.8
系统上,/tmp
目录下偶尔会有一些随机名称的文件产生。业务比较久远,已经不清楚这些文件的来源,需要确定是哪个进程在创建它们。
Linux
以VFS: Virtual File System
通用文件模型的方式在物理存储介质上的文件系统和用户接口之间建立一个虚拟文件系统的抽象层。其中最重要的两个结构是:
inode
: 存放文件的一般信息,每个inode
结构都有自己的编号,这个号码唯一标识了文件系统中的文件。dentry
: 存放文件名称信息,以及与对应文件进行链接的有关信息。VFS
创建文件的最主要的步骤是:
dentry
结构inode
结构并分配inode
编号inode
编号和文件名映射关系保存在所分配的dentry
结构中dentry
写入到父目录的数据区SOCKS
是一个比较简单的通用代理协议,用于在客户端与服务器之间代理网络数据包。最新的版本是5
, 所以一般叫做SOCKS5
,协议规范是RFC1928。但SOCKS5
并不兼容之前的SOCKS4
和SOCKS4A
。SOCKS5
在SOCKS4
的基础上添加了UDP
转发功能和校验
机制。
SOCKS5
的工作过程简单可以归纳为协商、请求、和转发三个阶段。以TCP
代理场景来看, 一般流程是:
SOCKS5
支持不同的请求类型,包括CONNECT
, BIND
, UDPASSOCIATE
等。其中,2-4完成协商阶段,5-7完成请求阶段,之后进入转发阶段。
当前常用的校验方法是USERNAME/PASSWORD
(RFC1929)和GSS-API
(RFC1961),具体的校验过程是由不同校验方法来自定义的。
使用USERNAME/PASSWORD
校验方法的TCP
代理时序图如下:
我们的业务Docker
镜像是在centos/systemd镜像基础上构建的,业务进程由systemd
来启动。最近需要对业务逻辑进行改造,需要识别传入的环境变量。看上去是相当简单的改动,但在我们的进程中加入读取环境变量的逻辑却发现读取不到传入的变量内容,最终定位原因是在systemd
的环境变量的处理。
在一台CentOS 7.0
服务器(内核版本号:3.10.0-123.el7.x86_64
)上安装我们的安全防护程序后,会出现curl
访问网址超时5秒的情况。现象如下:
1 | [root@localhost ~]# time curl -s www.baidu.com -o /dev/null |
通过strace
分析程序调用的过程:
1 | strace -f -tt -o curl.strace curl -s www.baidu.com -o /dev/null |
从strace
输出可以看到, 第一次curl
调用sendmmsg
同时发送了两个DNS
数据包,分别是A
记录和AAAA
记录请求,但是只收到了A
记录响应包:
然后等待5秒超时后,依次调用sendto
和recvfrom
串行处理两个DNS
请求, 这次两个DNS
响应全部收到后,继续向下执行:
而从抓包结果分析,tcpdump
只能看到第一次同时发送的两个DNS
请求中的A
记录请求,AAAA
记录请求数据包被内核协议栈丢弃了:
1 | 17:04:24.772049 IP 10.10.10.89.57416 > 114.114.114.114.53: 37081+ A? www.baidu.com. (31) |
Kubernetes
没有给本地环境(Bare-metal
, On-Premise
)提供负载均衡实现,LoadBalancer
类型的服务主要在各大公有云厂商上能够得到原生支持。在本地环境创建LoadBalancer
类型的服务后,服务的EXTERNAL-IP
会一直处于<pending>
状态。这是因为在本地环境没有相应的controller
来处理这些LoadBalancer
服务。比如:
1 | [root@master1 vagrant]# kubectl get svc |
之前的文章<<基于LVS DR模式的Kubernetes Service External-IP实现>>介绍了手动设置EXTERNAL-IP
的方式实现外部负载均衡。本文通过在本地环境实现一个简单的controller
来处理LoadBalancer
类型服务自动实现负载均衡器。架构示意如图:
LoadBalancer
是位于Kubernetes
集群外的独立集群。可以通过ECMP
将请求分散到不同的LoaderBalancer
节点上,LoadBalancer
再将请求分发到Kubernetes
的node
上。