Linux下发邮件乱码问题

作为系统管理员教程要写脚本生成报告,并将自动将邮件放到指定的人。然而收到的邮件经常有乱码(中文)。下面是解决方法:

例如cat test.sh:

#!/bin/bash  
export LANG=UTF-8  
/usr/local/mysql/bin/mysql -uroot -ppassword -e “select * from name” > /tmp/test$(date +%m%d).txt (test.txt有中文)  
/usr/local/bin/iconv -f UTF-8 -t GB2312 /tmp/”test$(date +%m%d).txt” | /bin/mail -s “test[$(date -d "1 day ago" +%D)]”  [email protected]

Linux下配置多网卡多网关

大家好,今天给大家介绍一下Linux下配置多网卡多网关的方法。@Hi-Linux

场景一 多运营商线路

比较典型的一种场景:一台 Linux 服务器上有三个网口并接入三个不同运营商的网络,以实现不同运营商用户访问其对应的网络线路,来减少网络延时。

服务器及对应网络信息如下:

一台 Ubuntu 16.04 server,这里一共使用三块网卡。假定网络信息如下:

未分类

这里 IP 只是为了区分各运营商线路做的示例,实际情况请以运营商给出的网络信息调整。

下面我们来看如何实现这样的需求:

在 Linux 下一台多网卡服务器不能同时配置两个及以上的默认网关,因为默认网关(Default Gateway)只能配置一个,通过 gateway 参数配置的网关在这里实际为默认路由。

这里通过配置 Linux 下策略路由来实现,通过原线路返回的策略路由可以实现多线多 IP 同时在线。让从同一运营商过来的请求由原运营商线路返回,比如:电信IP过来的请求按照电信路由返回,从网通IP过来的求从网通路由返回。

配置网络

  • 首先配置三块网卡的基本网络信息。
$ vim /etc/network/interfaces

auto enp0s5
iface enp0s5 inet static
address 192.168.100.212
netmask 255.255.255.0

auto enp0s6
iface enp0s6 inet static
address 192.168.110.213
netmask 255.255.255.0

auto enp0s7
iface enp0s7 inet static
address 192.168.120.214
netmask 255.255.255.0
  • 重启网络
$ /etc/init.d/networking restart
  • 查看配置好的网络情况
$ ip a|grep enp0s
2: enp0s5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.100.212/24 brd 192.168.100.255 scope global enp0s5
3: enp0s6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.110.213/24 brd 192.168.110.255 scope global enp0s6
4: enp0s7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.120.214/24 brd 192.168.120.255 scope global enp0s7
  • 查看各网卡当前路由
$ ip route show
192.168.100.0/24 dev enp0s5  proto kernel  scope link  src 192.168.100.212
192.168.110.0/24 dev enp0s6  proto kernel  scope link  src 192.168.110.213
192.168.120.0/24 dev enp0s7  proto kernel  scope link  src 192.168.120.214

增加路由表

Linux 中的路由由路由规则和路由表组成。路由规则指定当数据包满足规则时,应转交到哪个路由表;路由表根据数据包的信息,选择下一跳。

可通过 ip rule 看当前的路由策略,如:

$ ip rule
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

从这里也可以看出在内核中最多支持 32768 条路由规则。这里的 main 表是系统主要的路由表,所有的路由规则都写在这个表中。

  • 查看 main 表
$ ip route list table main
192.168.100.0/24 dev enp0s5  proto kernel  scope link  src 192.168.100.212
192.168.110.0/24 dev enp0s6  proto kernel  scope link  src 192.168.110.213
192.168.120.0/24 dev enp0s7  proto kernel  scope link  src 192.168.120.214

Linux 中支持 256 张路由表,编号为 0 到 255,可直接使用编号操作,也可使用编号的别名操作,编号和其别名的对应关系在 /etc/iproute2/rt_tables 文件中。

默认有 local,main,default 三个路由表,这三个路由表的名称命名就来自 /etc/iproute2/rt_tables。

$ cat /etc/iproute2/rt_tables
#
# reserved values
#
255 local
254 main
253 default
0   unspec
#
# local
#
#1  inr.ruhep

注:数字范围为0-255,但0、255、254、253是保留的,不能使用。

  • 增加三个路由表

在 /etc/iproute2/rt_tables 配置文件里面添加三个不同的路由表别名。增加三个路由表分别是: enp0s5:ChinaTel、enp0s5:ChinaCnc、enp0s5:ChinaEdu。

$ echo "101 ChinaTel" >> /etc/iproute2/rt_tables
$ echo "102 ChinaCnc" >> /etc/iproute2/rt_tables
$ echo "103 ChinaEdu" >> /etc/iproute2/rt_tables

因为这三个路由表的只是用来响应来自不同接口的,所以只需要每个路由表里面建立默认网关即可。

$ ip route add default via 192.168.100.1 dev enp0s5 table ChinaTel
$ ip route add default via 192.168.110.1 dev enp0s6 table ChinaCnc
$ ip route add default via 192.168.120.1 dev enp0s7 table ChinaEdu

如果要指定某一源 IP,可以加上 src 参数。

$ ip route add default via 192.168.100.1 dev eth0 src 192.168.100.212 table ChinaTel
  • 查看新增路由表中内容
$ ip route show table ChinaTel
default via 192.168.100.1 dev enp0s5

$ ip route show table ChinaCnc
default via 192.168.110.1 dev enp0s6

$ ip route show table ChinaEdu
default via 192.168.120.1 dev enp0s7
  • 增加路由原路返回规则,使来自不同的口的走不同的路由表。
$ ip rule add from 192.168.100.212 table ChinaTel
$ ip rule add from 192.168.110.212 table ChinaCnc
$ ip rule add from 192.168.120.212 table ChinaEdu

注意:此处原路是广义上的说法,并不是请求的路径与响应的路径完全相同。

如果要指定规则优先级,可以加上 pref 参数。pref 即路由表内序号,如果不加 pref,则将在已有的规则最小序号前插入。

$ ip rule add from 192.168.100.212/32 table ChinaTel pref 100
  • 查看新增的路由规则
$ ip rule
0:  from all lookup local
32763:  from 192.168.120.212 lookup ChinaEdu
32764:  from 192.168.110.212 lookup ChinaCnc
32765:  from 192.168.100.212 lookup ChinaTel
32766:  from all lookup main
32767:  from all lookup default

如果需要修改某一条路由规则,可根据优先级删除指定路由规则后重新增加:

$ ip rule del prio 32767

至此访问三个网段中的任意一个地址都能够连通了。即便是服务器上本身的默认路由都没有设置,也能够让外面的用户正常访问。如果你要在默认路由表增加一个默认路由,可以使用如下命令:

$ ip route add default via 192.168.100.1 dev enp0s5
$ ip route show table main
default via 192.168.100.1 dev enp0s5
192.168.100.0/24 dev enp0s5  proto kernel  scope link  src 192.168.100.212
192.168.110.0/24 dev enp0s6  proto kernel  scope link  src 192.168.110.213
192.168.120.0/24 dev enp0s7  proto kernel  scope link  src 192.168.120.214

main 表是系统主要的路由表,所有的默认路由规则都写在这个表中。

命令汇总

# 清空路由表ChinaTel
$ ip route flush table ChinaTel
# 为路由表 ChinaTel 添加默认路由 192.168.100.1
$ ip route add default via 192.168.100.1 dev enp0s5 table ChinaTel
# 根据源 IP 决定路由表
$ ip rule add from 192.168.100.212 table ChinaTel

# 清空路由表ChinaCnc
$ ip route flush table ChinaCnc
# 为路由表 ChinaCnc 添加默认路由 192.168.110.1
$ ip route add default via 192.168.110.1 dev enp0s6 table ChinaCnc
# 根据源 IP 决定路由表
$ ip rule add from 192.168.110.212 table ChinaCnc

# 清空路由表ChinaEdu
$ ip route flush table ChinaEdu
# 为路由表 ChinaEdu 添加默认路由 192.168.120.1
$ ip route add default via 192.168.120.1 dev enp0s7 table ChinaEdu
# 根据源 IP 决定路由表
$ ip rule add from 192.168.120.212 table ChinaEdu

测试

验证从 192.168.100.212 的包的路由选择

$ ip route get 8.8.8.8 from 192.168.100.212

# 结果为
8.8.8.8 from 192.168.100.212 via 192.168.100.1 dev enp0s5
cache
  • 验证从 192.168.110.213 的包的路由选择
$ ip route get 8.8.8.8 from 192.168.110.213

# 结果为

8.8.8.8 from 192.168.110.213 via 192.168.110.1 dev enp0s6
cache
  • 验证从 192.168.120.214 的包的路由选择
$ ip route get 8.8.8.8 from 192.168.120.214

# 结果为

8.8.8.8 from 192.168.120.214 via 192.168.120.1 dev enp0s7
cache
  • 外部测试
$ ping  192.168.100.212
$ ping  192.168.110.213
$ ping  192.168.120.214

以上几个 IP 均能 Ping 通。

保存路由设置

以上的路由设置会在系统或网络重启后被清理。因此需要将它保存下来,以防止系统或网络重启后失效。

方法一(推荐)

ip route save 可保存表的信息,如果表的项非常多,这个操作起来非常简单;ip rule 没有专门的保存命令,这里通过脚本实现。

先保存指定路由表的信息,这里以 ChinaTel 为例:

$ ip route save table ChinaTel > /root/route-ChinaTel.rules

恢复时可使用

$ ip route flush table ChinaTel && ip route restore table ChinaTel < /root/route-ChinaTel.rules

对规则的保存可使用以下的小脚本

$ vim ip-rule-dump.sh

#!/bin/sh
# ip-rule-dump.sh
# 参数: table 编号或别名,无参数时 dump 除 local 之外的全部规则

# 获取 table 别名
if [ -n "$1" ]; then
name=$(grep -v '^[[:blank:]]*#' /etc/iproute2/rt_tables |
grep "[[:blank:]]*$1[[:blank:]]" | head -n 1 | awk '{print $2}')
[ -z "$name" ] && name="$1"
fi
[ -z "$name" ] && name=".*"

# 获取并使用别名过滤规则
ip rule show | grep -v  "^0:" | grep -oP "from.*[[:blank:]]$name[[:blank:]]$" |
sed -e 's/lookup/table/g'

给脚本赋予权限并保存指定的路由规则

$ chmod +x ip-rule-dump.sh
$ ./ip-rule-dump.sh ChinaTel > /root/rule-ChinaTel.rules

对规则的恢复可使用以下的小脚本

$ vim ip-rule-restore.sh

#!/bin/sh
# ip-rule-restore.sh
# 参数: dump 文件路径

if [ -n "$1" ] && [ -f "$1" ]; then
cat $1 | while read line; do
sudo ip rule add $line
done
fi

给脚本赋予权限并恢复指定的路由规则

$ chmod +x ip-rule-restore.sh
$ ip rule del table ChinaTel >/dev/null 2>&1 || :
$ ./ip-rule-restore.sh /root/rule-ChinaTel.rules

开机加载

如果需要在网卡准备完成就加载,就需要在 /etc/network/interfaces 的对应网卡上,加上 post-up 的操作了,这里以加载电信路由信息为例:

$ iface enp0s5 inet static
...
post-up ( ip rule del table ChinaTel >/dev/null 2>&1 || : ) && 
bash /root/ip-rule-restore.sh /root/rule-ChinaTel.rules && 
ip route flush table ChinaTel && 
ip route restore table ChinaTel < /root/route-ChinaTel.rules

方法二

直接把命令加入启动脚本中,以防止网络重启或系统重启后配置失效。

配置 networking 启动脚本文件 在结尾 exit 0 之前增加如下内容:

  • 如果是 ubuntu/debian,网络启动脚本是 /etc/init.d/networking

  • 如果是 RedHat/centos,网络启动脚本是 /etc/rc.d/init.d/network

这里以 ubuntu 为例:

$ vi /etc/init.d/networking

ip route flush table ChinaTel
ip route add default via 192.168.100.1 dev enp0s5 table ChinaTel
ip rule add from 192.168.100.212 table ChinaTel
ip route flush table ChinaCnc
ip route add default via 192.168.110.1 dev enp0s6 table ChinaCnc
ip rule add from 192.168.110.212 table ChinaCnc
ip route flush table ChinaEdu
ip route add default via 192.168.120.1 dev enp0s7 table ChinaEdu
ip rule add from 192.168.120.212 table ChinaEdu
exit 0

退出并重启网络测试是否生效

$ /etc/init.d/networking restart

场景二 给指定网段分别设置网关

这种方法使用的是默认路由表,增加到指定网段的路由。

  • 使用 route 指令
$ route add -net 192.168.100.0/24 gw 192.168.100.1 dev enp0s5
$ route add -net 192.168.110.0/24 gw 192.168.110.1 dev enp0s6
$ route add -net 192.168.120.0/24 gw 192.168.120.1 dev enp0s7

参数说明

-net 设置到某个网段的路由

-host 设置到某台主机的路由

gw 出口网关 IP地址

dev 出口网关 物理设备名

  • 使用 ip 指令
# 推荐使用 replace 指令
$ ip route replace  192.168.100.0/24 via 192.168.100.1 dev enp0s5 onlink
$ ip route replace  192.168.110.0/24 via 192.168.110.1 dev enp0s6 onlink
$ ip route replace  192.168.120.0/24 via 192.168.120.1 dev enp0s7 onlink

# 直接使用 add 指令,会报 RTNETLINK answers: File exists 错。如果要使用 add 指令,可先删除原默认的路由规则后再增加。
$ ip route del 192.168.100.0/24
$ ip route add 192.168.100.0/24 via 192.168.100.1 dev enp0s5 onlink

注意:一块网卡只能设置一个网关,多个网关会发生冲突而无法成功配置。

如需增加默认路由,可使用以下指令:

  • 使用 route 指令
$ route add default gw 192.168.100.1 dev enp0s5
  • 使用 ip 指令
$ ip route add  default via 192.168.100.1 dev enp0s5

如有多余的配置,可使用下面的命令进行删除路由。

  • 使用 route 指令
$ route del -net 192.168.100.0/24 gw 192.168.100.1

或者

$ route del -net 192.168.100.0/24 dev enp0s5
  • 使用 ip 指令
$ ip route del 192.168.100.0/24

在Linux中查找用户帐户信息和登录详细信息的11种方法

本文将介绍 11 种在 Linux 系统查找用户相关信息的有用方法。这里,我们会讲解在系统中获取一个用户账户详细信息、展示登录详细信息以及用户行为数据的命令。

如果你想要在 Linux 中添加用户,可以使用 useradd 工具,如果希望修改一个现有用户账户的属性,就可使用下面的指南中所提到的 usermod 命令:

➤ 关于 useradd 命令的 15 个实用示例

The Complete Guide to “useradd” Command in Linux – 15 Practical Examples

➤ 关于 usermod 命令的 15 个实用示例

A Complete Guide to Usage of ‘usermod’ command – 15 Practical Examples with Screenshots

首先,我们会来看看如何使用命令查找一个用户的账户信息,然后再来跟大家讲解查看登录详细信息的那些命令。

1. id 命令

id 是用来展示一个实时活动用户以及组 ID 的命令行工具,如下所示:

$ id tecmint uid=1000(tecmint) gid=1000(tecmint) groups=1000(tecmint),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),130(sambashare) 

2. groups 命令

groups 命令可以被用来展示一个用户所归属的所有组的信息,像下面这样:

$ groups tecminttecmint : tecmint adm cdrom sudo dip plugdev lpadmin sambashare 

3. finger 命令

finger 命令可以被用来查找 Linux 上的一个用户的信息。在许多 Linux 系统上,它并没被预装。
想要在你的系统上安装它,可以在终端里运行这个命令:

$ sudo apt install finger#Debian/Ubuntu 

$ sudo yum install finger#RHEL/CentOS 

$ sudo dnf install finger#Fedora 22+  

它会显示出一个用户的真实名称、主目录、shell,登录的名称以及时间,还有如下所示的许多信息:

$ finger tecmintLogin: tecmint        Name: TecMint 
Directory: /home/tecmint            Shell: /bin/bash 
On since Fri Sep 22 10:39 (IST) on tty8 from :0 
2 hours 1 minute idle 
No mail. 
No Plan.  

4. getent 命令

getent 是一个可以从特定系统数据库的 Name Service Switch (NSS 名字服务交换器) 库获取到信息的命令行工具。
要获取一个用户账户的详细信息,可以像下面这样使用 passwd 数据库和 username 来做到。

$ getent passwd tecminttecmint:x:1000:1000:TecMint,,,:/home/tecmint:/bin/bash 

5. grep 命令

grep 命令是一个强大的模式搜索工具,可以在绝大多数 Linux 系统上使用。你可以用它来从系统账户文件 /etc/passwd 中查找出关于一个特定用户的信息,如下所示:

$ grep -i tecmint /etc/passwdtecmint:x:1000:1000:TecMint,,,:/home/tecmint:/bin/bash

6. lslogins 命令

lslogins 命令会展示出系统中现有用户的相关信息, -u 标记可用来标识只展示用户的账户。

$ lslogins -uUID USER       PROC PWD-LOCK PWD-DENY LAST-LOGIN GECOS 
0 root        144                              root 
1000 tecmint      70                     10:39:07 TecMint,,, 
1001 aaronkilik    0                               
1002 john          0                              John Doo  

7. users 命令

users 命令会展示当前已经登录系统的所有用户的用户名,像这样:

$ userstecmint 

aaron  

8. who 命令

who 命令可以用来展示那些登录了系统的用户,包括了它们是从哪里连接到系统上来的终端信息。

$ who -utecmint tty8 2017-09-22 10:39 02:09 2067 (:0) 

9. w Command

w 命令会展示出所有登录了系统的用户,还有它们都做了些什么事情。

$ w12:46:54 up  2:10,  1 user,  load average: 0.34, 0.44, 0.57 
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT 
tecmint  tty8     :0               10:39    2:10m  4:43   0.46s cinnamon-sessio  

10. last 或者 lastb 命令

last/lastb 命令会展示一个最近登录系统的用户列表。

$ last OR$ last -a #show hostname on the last column 

最近登录系统的用户列表

tecmint  tty8         Fri Sep 22 10:39    gone - no logout  :0 
reboot   system boot  Fri Sep 22 10:36   still running      4.4.0-21-generic 
tecmint  tty8         Thu Sep 21 10:44 - down   (06:56)     :0 
reboot   system boot  Thu Sep 21 10:42 - 17:40  (06:58)     4.4.0-21-generic 
tecmint  tty8         Wed Sep 20 10:19 - down   (06:50)     :0 
reboot   system boot  Wed Sep 20 10:17 - 17:10  (06:52)     4.4.0-21-generic 
tecmint  pts/14       Tue Sep 19 15:15 - 15:16  (00:00)     tmux(14160).%146 
tecmint  pts/13       Tue Sep 19 15:15 - 15:16  (00:00)     tmux(14160).%145 
...

要是想显示那些在特定时间访问过系统的用户,可以像下面这样使用 -p 选项:

$ last -ap nowtecmint  tty8         Fri Sep 22 10:39    gone - no logout  :0 
reboot   system boot  Fri Sep 22 10:36   still running      4.4.0-21-generic 
wtmp begins Fri Sep  1 16:23:02 2017  

11. lastlog 命令

lastlog 命令可以用来查找最近登录那些或者某个特定用户的详细信息,如下所示:

$ lastlog OR$ lastlog -u tecmint #show lastlog records for specific user tecmint 

最近登录用户的记录:

Username         Port     From             Latest 
root                                       **Never logged in** 
kernoops                                   **Never logged in** 
pulse                                      **Never logged in** 
rtkit                                      **Never logged in** 
saned                                      **Never logged in** 
usbmux                                     **Never logged in** 
mdm                                        **Never logged in** 
tecmint          pts/1    127.0.0.1        Fri Jan  6 16:50:22 +0530 2017 
..

如果你还知道其它的什么命令行技巧或者是某个查看用户详情的命令,可以跟我们共享一下哦。

linux下编译安装php7

1、从官网下载PHP安装包

wget http://hk2.php.net/get/php-7.1.8.tar.bz2/from/this/mirror

2、下载下来的文件为mirror镜像,通过mv命令重命名成tar.bz2文件

mv mirror php-7.1.8.tar.bz2

3、解压压缩文件

tar jxf php-7.1.8.tar.bz2

4、安装php所需的依赖扩展和程序

yum install gd zlib zlib-devel openssl openssl-devel libxml2 libxml2-devel libjpeg libjpeg-devel libpng libpng-devel

5、安装前配置,注意–enable-fpm为必须,在linux系统中php作为一个单独的进程存在

./configure --prefix=/usr/local/php7.1.8/ 
    --with-gd 
    --enable-gd-native-ttf 
    --enable-mysqlnd 
    --with-mysql=mysqlnd 
    --with-pdo-mysql=mysqlnd 
    --with-openssl 
    --enable-mbstring 
    --enable-fpm

6、编译安装

make && make install

每个开发者应该了解的 10 个 Linux 命令

作为一名软件工程师,我做过的最明智的投资就是学习 Linux。因为,在日常工作中,我们会经常与 Linux 系统打交道。而今天,作为一名 30 多岁的工程师,我仍受益于几年前我碰巧学过的那些知识,所以技术学习需要不断积累,不积跬步无以至千里。另外,在另一篇博客文章中,我将更详细地解释为什么 Linux 对于软件开发人员来说更加务实。

在本文中,我将分享一些小众却十分有用的 Linux 命令。如果你使用 Macbook,那刚刚好。因为我推荐的大多数命令也能应用于 OSX 系统。

10. file

返回给定信息的类型。例如,你可以输出图像的尺寸信息:

file logo.png

返回:

> PNG image data, 16 x 16, 8-bit/color RGBA, non-interlaced

9. iotop, powertop, nethogs

你将如何监控 Linux 系统中发生的状况? 这三个命令可以解决你的燃眉之急。

  • Iotop:通过磁盘写入对进程排序,并显示程序写入到磁盘的数量与频次。
  • Powertop:监控程序的电源使用情况。如果你无法及时充电时,这个命令就很重要了。
  • Nethogs:列出每个进程所使用的带宽。

8. tee

将数据重定向到给定文件和屏幕上。例如,添加一个新的条目到 hosts 文件:

echo "127.0.0.1 foobar" | sudo tee -a /etc/hosts

7. pidof, kill 和 pkill

这三条重要的命令将帮助你控制系统中运行的程序。

Pidof:输出正在运行程序的进程 ID。例如,以下命令将输出 nginx 的进程 ID:

pidof nginx

你还可以通过 kill 命令,以及相应的数字来终止 nginx 进程:

kill -USR2 $(pidof nginx)'

pkill 是一个快捷命令,可以按照进程名称终止所有的进程:

pkill -f nginx

6. tmux

如果你还没有安装 tmux 的话,我极力推荐你安装它。Tmux 是一款优秀的终端中的窗口和会话管理器。译者注:如果你想详细了解 Tmux,参见本篇文章。

5. tree

以树状结构列出目录内容。同时,通过设置相应的参数还可以只显示目录名称:

tree -d

4. find

当我们在指定目录下寻找具体文件时,这个命令将帮你大忙。我将在这里介绍几个简单的用例:

示例 1 – 列出所有的 CSS 文件(包括子目录):

find . -type f -name "*.css"

示例 2 – 列出所有的 CSS 与 HTML 文件:

find . -type f ( -name "*.css" -or -name "*.html" )

3. htop

Htop 是一个著名的进程查看器。它拥有漂亮、多彩的命令行界面,以及一些实用的字母快捷键:

  • – 增量进程过滤器;
  • / – 搜索进程;
  • , – 选择排序标准;
  • k – 终止进程;
  • u – 筛选某一特定用户进程;
  • t – 显示/隐藏树形结构;
  • 和 + – 展开/折叠选定的进程树;
  • H – 显示/隐藏用户线程。

2. chroot

这个命令的神奇之处在于,它可以帮助你在指定目录中打开新的 TTY 。那么,你就可以创建一个文件夹,在其中设置新的 Linux 系统,并随时切换到该“子系统”。

1. dialog

方便与用户交互的简易命令。例如,下面的命令就显示了一个漂亮的输入框:

dialog --title "Oh hey" --inputbox "Howdy?" 8 55

上述介绍的大多数命令都可应用在 OSX 系统上,并且支持许多其他类型的对话:消息框、菜单、确认对话框、进度条等。另外,我所编写《 Happy Hacking Linux 》 (http://azer.bike/happy-hacking-linux/) 的安装向导中也应用了上述相关命令。

Linux上Raid卡的简单配置与使用

使用 RAID 可以提高服务器的性能。不同 RAID 的级别,性能会有所不同。它通过容错和高可用性来保存我们的数据。

下面记录在linux上配置和使用raid卡的过程。

资源

  1. Linux主机
  2. Raid卡(LSI MegaRAID SAS 9271-8i)
  3. 两块希捷1T机械硬盘

工具

  1. Raid工具:MegaCli64或storcli64
  2. fdisk(分区)
  3. mkfs(格式化分区文件系统)
  4. df(查看分区挂载情况)

Raid卡真容

未分类

Raid卡

图中蓝线框出的两个插口是MinSATA的插口,可以连接Mni SATA转接线,接硬盘数据口和备用电源。

未分类

Mini SATA接口线(不是我的手)

安装

未分类
安装结构图

RAID卡插在PCI的扩展槽上,Mini SATA转接线中的数据口接在硬盘上,同时硬盘接电源,转接线的电源线可以不用(备用电源线)。

至此硬件安装基本完成。
要想RAID卡工作还有必不可少的一步就是安装驱动,这里涉及到Linux的Kernel的编译问题。在较新的Kernel中大多已经集成了RAID驱动,这里我们从新编译一下。
cd到Kernel源码目录执行:

make menuconfig

要编译Raid驱动,依赖PCI模块,所以我们需要把PCI support 模块编译进内核。

未分类

进入PCI配置

未分类

按Y选择编译PCI support

之后在”Device Drivers” >>”SCSI device support”>>”SCSI low-level drivers”下在 “LSI Logic MegaRAID SAS RAID Module”上按Y,把此模块编译进kernel中。
最后执行以下命令编译内核

make -j 9

之后改一下grub配置,上传编译好的内核文件,改好启动引导之后就可以重启设备了,不出意外将会系统启动前看到Raid初始化的打印输出。
开机之后运行以下命令可以查看Raid卡参数:

storcli64 /c0 show all#或MegaCli -AdpAllInfo -aAll

双盘创建Raid1:

storcli /c0 add vd raid1 drives=252:5,7 pdperarray=2

创建好之后先用fdisk做好分区然后用mkfs命令格式化分区文件系统,之挂载分区就行了。

后记:

其实搞硬件,最重要的一步就是硬件设备安装的时候一定要装好,要不然….

Linux中grep命令的12个实践例子

你是否遇到过需要在文件中查找一个特定的字符串或者样式,但是不知道从哪儿开始?那么,就请grep来帮你吧。

未分类

grep是每个Linux发行版都预装的一个强有力的文件模式搜索工具。无论何种原因,如果你的系统没有预装它的话,你可以很容易的通过系统的包管理器来安装它(Debian/Ubuntu系中的apt-get和RHEl/CentOS/Fedora系中的yum)。

$ sudo apt-get install grep #Debian/Ubuntu $ sudo yum install grep #RHEL/CentOS/Fedora 

我发现使用现实世界中的真实例子让你投身其中是让你接触grep命令的最容易方式。

1. 搜索和寻找文件

假设你已经在你的电脑上安装了一个全新的Ubuntu,然后你打算卸载Python。你浏览网页寻找教程,但是你发现存在两个不同版本的Python在使用,而你不知道你的Ubuntu安装器到底在你的系统中安装了哪个版本的Python,也不知道它安装了哪些模块。解决这个烦恼只需简单的运行以下命令:

$ sudo dpkg -l | grep -i python 

输出例子

ii  python2.7         2.7.3-0ubuntu3.4 Interactive high-level object-oriented language (version 2.7)
   ii  python2.7-minimal 2.7.3-0ubuntu3.4 Minimal subset of the Python language (version 2.7)
   ii  python-openssl    0.12-1ubuntu2.1  Python wrapper around the OpenSSL library
   ii  python-pam        0.4.2-12.2ubuntu4 A Python interface to the PAM library

首先,我们运行dpkg -l列出你系统上安装的.deb包。接着,我们使用管道将输出结果传输给命令grep -i python,这一步可以简单解释为把结果传输给grep然后过滤出所有含有python的项,并返回结果。–i选项用于忽略大小写,因为 grep 是大小写敏感的。使用选项-i是个好习惯,除非你打算进行更细节的搜索。

2. 搜索和过滤文件

grep还可以在一个或多个文件里用于搜索和过滤。让我们来看一个这样的情景:

你的Apache网页服务器出现了问题,你不得不从许多专业网站里找一个发帖询问。好心回复你的人让你粘贴上来你的/etc/apache2/sites-available/default-ssl文件内容。假如你能移除掉所有的注释行,那么对你,对帮你的人,以及所有阅读该文件的人,不是更容易发现问题吗?你当然可以很容易的做到!只需这样做就可以了:

$ sudo grep -v "#" /etc/apache2/sites-available/default-ssl 

选项-v是告诉grep命令反转它的输出结果,意思就是不输出匹配的项,做相反的事,打印出所有不匹配的项。这个例子中,有#的是注释行(译注:其实这个命令并不准确,包含“#”的行不全是注释行。关于如何精确匹配注释行,可以了解更多的关于正则表达式的内容。)。

3. 找出所有的mp3文件

grep命令对于过滤来自于标准输出的结果非常有用。例如,假设你的一个文件夹里面全是各种格式的音乐文件。你要找出艺术家jayZ的所有mp3格式的音乐文件,里面也不要有任何混合音轨。使用find命令再结合管道使用grep就可以完成这个魔法:

$ sudo find . -name ".mp3" | grep -i JayZ | grep -vi "remix"" 

在这个例子中,我们使用find命令打印出所有以.mp3为后缀名的文件,接着将其使用管道传递给grep -i过滤和打印出名字为“JayZ”的文件,再使用管道传送给grep -vi以便过滤掉含有“remix”的项。

35个Linux中find命令的实践例子: http://www.tecmint.com/35-practical-examples-of-linux-find-command/

4. 在搜索字符串前面或者后面显示行号

另外两个选项是-A和-B之间的切换,是用以显示匹配的行以及行号,分别控制在字符串前或字符串后显示的行数。Man页给出了更加详细的解释,我发现一个记忆的小窍门:-A=after、-B=before。

$ sudo ifconfig | grep -A 4 etho $ sudo ifconfig | grep -B 2 UP

5. 在匹配字符串周围打印出行号

grep命令的-C选项和例4中的很相似,不过打印的并不是在匹配字符串的前面或后面的行,而是打印出两个方向都匹配的行(译注:同上面的记忆窍门一样:-C=center,以此为中心): $ sudo ifconfig | grep -C 2 lo

6. 计算匹配项的数目

这个功能类似于将grep输出的结果用管道传送给计数器(wc程序),grep内建的选项可以达到同样的目的:

$ sudo ifconfig | grep -c inet6 

7. 按给定字符串搜索文件中匹配的行号

当你在编译出错时需要调试时,grep命令的-n选项是个非常有用的功能。它能告诉你所搜索的内容在文件的哪一行:

$ sudo grep -n "main" setup.py 

8. 在所有目录里递归的搜索

假若你要在当前文件夹里搜索一个字符串,而当前文件夹里又有很多子目录,你可以指定一个-r选项以便于递归的搜索: $ sudo grep -r “function” *

9. 进行精确匹配搜索

传递-w选项给grep命令可以在字符串中进行精确匹配搜索(译注:包含要搜索的单词,而不是通配)。例如,像下面这样输入:

$ sudo ifconfig | grep -w “RUNNING” 

将打印出含有引号内匹配项的行。另外,你还可以试一下这个:

$ sudo ifconfig | grep -w “RUN” 

搜索这个匹配项时,若搜索的东西里面没有这样的一个单独的单词,将什么也不会返回。

10. 在Gzip压缩文件中搜索

我们还要关注一下grep的衍生应用。第一个是zgrep,这个与zcat很相似,可以用于gzip压缩过的文件。它有与grep相似的命令选项,使用方式也一样:

$ sudo zgrep -i error /var/log/syslog.2.gz 

11. 在文件中匹配正则表达式

egrep是另一个衍生应用,代表着“扩展全局正则表达式”。它可以识别更多的正则表达式元字符,例如at + ? | 和()。在搜索源代码文件时,egrep是一个非常有用的工具,还有其他的一些零碎代码文件的搜索需要,使得这样的搜索能力成为必需。可以在grep命令中使用选项-E来启用它。

$ sudo grep -E

12. 搜索一个固定匹配字符串

fgrep用于在一个文件或文件列表中搜索固定样式的字符串。功能与grep -F同。fgrep的一个通常用法为传递一个含有样式的文件给它:

$ sudo fgrep -f file_full_of_patterns.txt file_to_search.txt 

这仅仅是grep命令的开始,你可能已经注意到,它对于实现各种各样的需求简直是太有用了。除了这种我们运行的这种只有一行的命令,grep还可以写成cron任务或者自动的shell脚本去执行。保持好奇心,试验一下man页的各个选项,为实现你的目的写出一些grep表达式吧。

Linux 查看空间使用情况

在日常的Linux巡检中,我们会遇到文件系统目录使用空间很高的情况,例如如下利用”df -h “查看到根目录空间使用超过80%。而我们仅仅知道是根目录空间使用过高,这样是不够的。还需要知道是目录还是文件让根目录空间使用过高。通常我们使用的命令是”du -sh *”。

第一步:查看Linux系统的文件系统使用情况,如下可以看到根目录”/”已经使用81%。

[root@hostname ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda6              67G   51G   13G  81% /
tmpfs                  16G  152K   16G   1% /dev/shm
/dev/sda3              99G  188M   94G   1% /arch
/dev/sda1             197G  188M  187G   1% /u01
/dev/sda2             197G   50G  138G  27% /u02

第二步:进入根目录,利用du -sh 命令查询各个目录或者文件占用空间的情况,因为/u02是独立的文件系统,所以可以忽略。我们关注的是root这个目录,占用了空间47G。

[root@hostname ~]# cd /

[root@hostname /]# du -sh *
20K     arch
7.6M    bin
27M     boot
324K    dev
36M     etc
36K     home
136M    lib
26M     lib64
16K     lost+found
4.0K    media
0       misc
4.0K    mnt
0       net
8.0K    opt
4.0K    orbit-root
--省略/proc目录统计的报错
0       proc
47G     root    ##根目录文件系统使用最大的目录
15M     sbin
0       selinux
4.0K    srv
0       sys
80K     tmp
20K     u01
49G     u02

第三步:进入root目录,其实也是root用户的主目录。我们从ls命令可以猜到可能是【apache-tomcat-6.0.36-linux】这个tomcat的程序目录占用比较多。

[root@hostname /]# cd root
[root@hostname ~]# ls
anaconda-ks.cfg  apache-tomcat-6.0.36-linux  Desktop  Documents  Downloads  install.log  install.log.syslog  Music  Pictures  Public  Templates  Videos

第四步:通过统计发现,确实是【apache-tomcat-6.0.36-linux】这个目录占用了47G。但是到此问题还没有结束,因为既然是应用程序的目录,根据我的经验很可能是tomcat的日志文件占用空间比较多。

[root@hostname ~]# du -sh *
4.0K    anaconda-ks.cfg
47G     apache-tomcat-6.0.36-linux
4.0K    Desktop
4.0K    Documents
4.0K    Downloads
56K     install.log
12K     install.log.syslog
4.0K    Music
4.0K    Pictures
4.0K    Public
4.0K    Templates
4.0K    Videos

第五步:既然看到有tomcat的目录,很可能这个tomcat运行着,利用ps命令查看是否有tomcat的进程,一般可以过滤java这个关键词。如下,果然有tomcat在运行着。那么很可能占用空间最多就是tomcat的日志文件。

[root@hostname ~]# ps -ef|grep java
root      4879  4836  0 08:26 pts/0    00:00:00 grep java
root     11864     1 47 Aug16 ?        26-03:11:29 /usr/bin/java -Djava.util.logging.config.file=/root/apache-tomcat-6.0.36-linux/conf/logging.properties -Xms512m -Xmx1024m -XX:PermSize=128M -XX:MaxPermSize=256m -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/root/apache-tomcat-6.0.36-linux/endorsed -classpath /root/apache-tomcat-6.0.36-linux/bin/bootstrap.jar -Dcatalina.base=/root/apache-tomcat-6.0.36-linux -Dcatalina.home=/root/apache-tomcat-6.0.36-linux -Djava.io.tmpdir=/root/apache-tomcat-6.0.36-linux/temp org.apache.catalina.startup.Bootstrap start

第六步:进入tomcat的程序目录,查看哪个目录占用的空间最大。如下,发现是一个【fare】的目录占用了46G,而【logs】是日志目录却占用了23M。

[root@hostname ~]# cd apache-tomcat-6.0.36-linux
[root@hostname apache-tomcat-6.0.36-linux]# ls
backup  bin  conf  fare  lib  LICENSE  logs  NOTICE  RELEASE-NOTES  RUNNING.txt  temp  webapps  work
[root@hostname apache-tomcat-6.0.36-linux]# du -sh *
92K     backup
882M    bin
108K    conf
46G     fare
6.8M    lib
40K     LICENSE
23M     logs
4.0K    NOTICE
12K     RELEASE-NOTES
16K     RUNNING.txt
7.9M    temp
188M    webapps
7.1M    work

第七步:继续一探究竟【fare】目录里面到底存放的是什么类型的目录或者文件。如下看到有很多类似日志文件,如common.log和pricing.log。通过和开发人员沟通之后,确定确实日志文件。

[root@hostname apache-tomcat-6.0.36-linux]# cd fare
[root@hostname fare]# ls
common.log             common.log.2017-09-21  common.log.2017-10-03     pricing.log.2017-09-10  pricing.log.2017-09-22  pricing.log.2017-10-04
common.log.2017-09-10  common.log.2017-09-22  common.log.2017-10-04     pricing.log.2017-09-11  pricing.log.2017-09-23  pricing.log.2017-10-05
common.log.2017-09-11  common.log.2017-09-23  common.log.2017-10-05     pricing.log.2017-09-12  pricing.log.2017-09-24  pricing.log.2017-10-06
common.log.2017-09-12  common.log.2017-09-24  common.log.2017-10-06     pricing.log.2017-09-13  pricing.log.2017-09-25  pricing.log.2017-10-07
common.log.2017-09-13  common.log.2017-09-25  common.log.2017-10-07     pricing.log.2017-09-14  pricing.log.2017-09-26  pricing.log.2017-10-08
common.log.2017-09-14  common.log.2017-09-26  common.log.2017-10-08     pricing.log.2017-09-15  pricing.log.2017-09-27  pricing.log.2017-10-09
common.log.2017-09-15  common.log.2017-09-27  common.log.2017-10-09     pricing.log.2017-09-16  pricing.log.2017-09-28  spring.log
common.log.2017-09-16  common.log.2017-09-28  common.zip                pricing.log.2017-09-17  pricing.log.2017-09-29  struts2.log
common.log.2017-09-17  common.log.2017-09-29  framework.log             pricing.log.2017-09-18  pricing.log.2017-09-30  xwork2.log
common.log.2017-09-18  common.log.2017-09-30  hibernate.log             pricing.log.2017-09-19  pricing.log.2017-10-01
common.log.2017-09-19  common.log.2017-10-01  hibernate.log.2017-01-03  pricing.log.2017-09-20  pricing.log.2017-10-02
common.log.2017-09-20  common.log.2017-10-02  pricing.log               pricing.log.2017-09-21  pricing.log.2017-10-03

第八步:继续查看哪个目录或者文件占用的空间最大,发现都是common.log和pricing.log相关的文件占用的空间最大,都是700M以上。至此,已经查明占用根目录”/”空间最多的原因是tomcat的日志文件太多,而且每一个日志文件都很大。

[root@hostname fare]# du -sh *|sort -h
0       framework.log
0       hibernate.log.2017-01-03
0       spring.log
0       struts2.log
0       xwork2.log
4.0K    hibernate.log
17M     common.zip
215M    pricing.log
216M    common.log
667M    pricing.log.2017-10-08
668M    common.log.2017-10-08
674M    common.log.2017-10-05
674M    pricing.log.2017-10-05
678M    common.log.2017-10-07
678M    pricing.log.2017-10-07
679M    common.log.2017-10-06
679M    pricing.log.2017-10-06
683M    common.log.2017-10-04
683M    pricing.log.2017-10-04
690M    pricing.log.2017-09-10
691M    common.log.2017-09-10
711M    common.log.2017-09-12
711M    pricing.log.2017-09-12
719M    pricing.log.2017-09-11
720M    common.log.2017-09-11
737M    common.log.2017-09-30
737M    pricing.log.2017-09-28
737M    pricing.log.2017-09-30
738M    common.log.2017-09-28
742M    common.log.2017-09-29
742M    pricing.log.2017-09-29
744M    pricing.log.2017-10-09
745M    common.log.2017-10-09
751M    common.log.2017-10-01
751M    pricing.log.2017-10-01
754M    common.log.2017-09-13
754M    pricing.log.2017-09-13
760M    common.log.2017-10-03
760M    pricing.log.2017-10-03
783M    pricing.log.2017-10-02
784M    common.log.2017-10-02
791M    pricing.log.2017-09-18
792M    common.log.2017-09-18
797M    common.log.2017-09-27
797M    pricing.log.2017-09-27
804M    common.log.2017-09-17
804M    common.log.2017-09-19
804M    pricing.log.2017-09-17
804M    pricing.log.2017-09-19
808M    common.log.2017-09-26
808M    pricing.log.2017-09-26
815M    pricing.log.2017-09-24
816M    common.log.2017-09-24
821M    common.log.2017-09-14
821M    pricing.log.2017-09-14
821M    pricing.log.2017-09-23
822M    common.log.2017-09-23
826M    common.log.2017-09-25
826M    pricing.log.2017-09-25
827M    common.log.2017-09-16
827M    pricing.log.2017-09-15
827M    pricing.log.2017-09-16
828M    common.log.2017-09-15
831M    common.log.2017-09-22
831M    pricing.log.2017-09-22
851M    common.log.2017-09-21
851M    pricing.log.2017-09-21
860M    common.log.2017-09-20
860M    pricing.log.2017-09-20

第九步:从文件的命令规律,可以看出日志文件日期保留一个月,检查root用户是否有定时删除日志文件计划。如下命令查看所示,确实有每天凌晨03:15进行日志文件删除的计划。但是由于日志文件太多和根目录空间大小原因,导致根目录空间使用比例过高。在有部署自动监控工具,如zabbix等,会自动发送告警。

[root@hostname ~]# crontab -l
15 3 * * * /u02/shell/rm_log_pricing.sh
[root@hostname ~]# cat /u02/shell/rm_log_pricing.sh
find /root/apache-tomcat-6.0.36-linux/bin/fare/  -name "common.log.2*" -mtime +30 | xargs rm -f
find /root/apache-tomcat-6.0.36-linux/bin/fare/  -name "pricing.log.2*" -mtime +30 | xargs rm -f

总结:

从运维的角度,不建议tomcat等应用程序部署在和Linux操作系统相关的文件系统中,尤其是直接部署在根目录下。一般都建议使用独立的文件系统来部署应用程序,无论从IO性能监控,文件系统空间使用监控都是有利的。

Linux Loader 机制与内核模块修复

0x0 前言

在吃着月饼喝着茶的闲暇时间里,突然接到某单位的应急通知。赶往现场进行初步勘察后,发现攻击者手段非常暴力,直接删除系统相关关键模块(包括 PAM 模块、基础内核驱动模块等),导致后续用户无法登录操作系统。

在尝试恢复 PAM 模块后,正常登录系统,但由于缺少基础的核心模块,网络、USB 挂载等仍无法正常使用。在下载部分二进制驱动包进行安装后,重启开始出现问题(截图为后期复现):

未分类

确认 /lib/modules/ 下确实存在此文件,但重启依然出现此问题。

而由于对 Linux Loader 机制的不熟悉,现场并未能解决此问题(菜。同时在不确定攻击者是否也删除了正常业务程序组件的情况下,恢复的成本较大,于是备份关键数据,提取相关样本与日志后,对系统进行重装,恢复正常业务。

0x1 Linux 启动与内核加载

1.1 bootloader

首先,还是从我们的老朋友 BIOS 进行加电自检(POST,Power-On Self-Test)后,开始读取 MBR 记录。MBR 为 512 字节大小的扇区,其中前 446 字节硬编码着 bootloader 程序。BIOS 从 MBR 记录读取 bootloader 程序,将其加载到内存,并运行该程序。

对于不同的操作系统,有不同的 bootloader 程序,一般在安装操作系统时,安装程序会向 MBR 写入 bootloader 程序。如 Windows 操作系统,使用自带的 bootloader 程序。对于 Linux 发行版,一般使用新版的 GRUB2 来生成并写入 bootloader。

bootloader 的工作便是载入内核文件,使操作系统正常运行。

1.2 内核文件

在 Linux 中,由 bootloader 载入的内核文件位于 /boot 节点下:

[root@centos boot]# ls --format=single-column /boot
config-2.6.32-696.el6.x86_64 # 内核编译时启用的配置信息与模块设定
efi # EFI 引导程序
grub # GRUB 引导程序支持
initramfs-2.6.32-696.el6.x86_64.img # 虚拟文件系统,主角 ;-)
symvers-2.6.32-696.el6.x86_64.gz # 驱动模块符号表
System.map-2.6.32-696.el6.x86_64 # 内核符号表
vmlinuz-2.6.32-696.el6.x86_64 # 内核文件

如上,vmlinuz 便是 bootloader 载入的 Linux 内核文件,内核文件主要负责检测基础的硬件设施,并载入相关驱动,这些驱动一般位于 /lib/modules/<内核版本>/ 目录下。

那么 initramfs 是干嘛的?当内核启动时,需要往 /lib/modudles 下读取驱动文件,以支持 SATA、USB 等接口的设备,但是明显 /lib/modules 是存储于 SATA 磁盘中,没有 SATA 驱动的情况下也无法读取挂载,这里就出现了先有鸡还是先有蛋的问题。

而 initramfs 便是来解决这个问题,initramfs 事实上是一个具有根目录结构的文件,其中包含基础的应用程序,以及核心的内核模块,例如 SCSI、SATA、USB 等,用于支持最基础的外部设备。

1.3 解剖 initramfs

新建目录,将 initramfs 拷贝到目标目录下:

[root@centos ~]# mkdir /tmp/initramfs
[root@centos ~]# cp /boot/initramfs-2.6.32-696.el6.x86_64.img /tmp/initramfs/initramfs.img

initramfs 使用 gzip 进行压缩,将其解压:

[root@centos ~]# cd /tmp/initramfs/
[root@centos initramfs]# file initramfs.img 
initramfs.img: gzip compressed data, from Unix, last modified: Wed Oct  4 17:17:17 2017, max compression
[root@centos initramfs]# mv initramfs.img initramfs.gz
[root@centos initramfs]# gzip -d initramfs.gz 

在解压完成后,实际上文件使用 cpio 进行归档,最后我们使用 cpio 将其解压出来:

[root@centos initramfs]# file initramfs
initramfs: ASCII cpio archive (SVR4 with no CRC)

# -i 解压文件
# -d 必要时创建目录
# -H newc 指定类型为 SVR4 的归档文件
# --no-absolute-filenames 不要将文件解压覆盖到绝对路径
[root@centos initramfs]# cpio -i -d -H newc --no-absolute-filenames < initramfs
108638 blocks

从最后的目录结构可以看到 initramfs 的真实内容:

[root@centos initramfs]# ll
total 54432
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 bin
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 cmdline
drwxr-xr-x. 3 root root     4096 Oct  5 22:50 dev
-rw-r--r--. 1 root root       23 Oct  5 22:50 dracut-004-409.el6_8.2
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 emergency
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 etc
-rwxr-xr-x. 1 root root     8989 Oct  5 22:50 init
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-finished
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-settled
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 initqueue-timeout
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 lib
drwxr-xr-x. 3 root root     4096 Oct  5 22:50 lib64
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 mount
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 netroot
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-mount
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-pivot
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-trigger
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 pre-udev
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 proc
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sbin
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sys
drwxr-xr-x. 2 root root     4096 Oct  5 22:50 sysroot
drwxrwxrwt. 2 root root     4096 Oct  5 22:50 tmp
drwxr-xr-x. 7 root root     4096 Oct  5 22:50 usr
drwxr-xr-x. 4 root root     4096 Oct  5 22:50 var

列一下 lib/modules/<内核版本>/kernel/drivers 下的驱动文件:

[root@centos initramfs]# ls lib/modules/2.6.32-696.el6.x86_64/kernel/drivers/
acpi
ata
atm
auxdisplay
bcma
block
bluetooth
cdrom
<...snippets...>

initramfs 中包含最核心的驱动程序,bootloader 在启动时,将 initramfs 临时挂载到根目录,在内核文件正常加载驱动后,对其进行卸载,并挂载真正的根目录节点。

最后,内核程序启动 init / systemd 对系统服务进行加载。

1.4 bootloader 配置

在 Linux 发行版下,bootloader 通常由 GRUB 程序进行管理,而 bootloader 又负责加载内核文件,较新的发行版一般使用新的 GRUB2 进行引导。

由于笔者使用的是 CentOS 6.X,所以此时默认还是旧版的 GRUB 引导管理程序,但不同版本配置上大同小异,所以以旧版为例。

默认情况下,/boot/grub 下(新版为/boot/grub2)存放 GRUB 的配置文件:

[root@centos ~]# ls /boot/grub
grub.conf # GRUB 的引导菜单配置文件
stage1
stage2
<...snippets...>

可以注意到目录下有 stage1 和 stage2 文件,这个其实便是 bootloader 程序。由于 MBR 区域只有可怜的 512 字节,而 bootloader 程序相对都会比较大,所以 GRUB 将启动分为两个阶段,真正存在于 MBR 处的代码便是 stage1 程序,再由此加载真正的 bootloader 程序 stage2。

再看看主配置文件 /boot/grub/grub.conf 的内容:

# grub.conf generated by anaconda

default=0
timeout=5

title CentOS 6 (2.6.32-696.el6.x86_64)
    root (hd0,0)
    kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos-lv_root nomodeset rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos/lv_swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_centos/lv_root  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
    initrd /initramfs-2.6.32-696.el6.x86_64.img

通过配置项名称应该都可以猜到相关的功能,例如 default 设置默认的启动菜单为 Centos 6 项,默认超时为 5 秒钟。

在 title 中,则定义了菜单项:

root (hd0,0)
kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/mapper/vg_centos-lv_root nomodeset rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_centos/lv_swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_centos/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
initrd /initramfs-2.6.32-696.el6.x86_64.img

root 指定 /boot 节点的位置,如果是多个磁盘,则从 hd0、hd1 等依次排列。后面的 0 代表所在的分区位置。

GRUB 从 0 开始索引分区,新版 GRUB2 则从 1 开始索引分区,磁盘索引一致,都是从 0 开始。

kernel 指令负责载入内核文件,包括载入的根目录位置、语言、键盘等参数。

initrd 负责挂载 initramfs 虚拟文件系统。

0x2 内核模块依赖重建

2.1 内核模块

Linux 中的内核模块通常与内核进行分离,作为独立的模块进行加载,当然也可以将其编译到内核中。独立的内核模块存放于 /lib/modules/<内核版本> 下。

该目录下的文件 modules.dep,记录了内核模块位置、依赖等信息。对于现在各种各样的设备驱动,手工配置依赖信息非常繁琐,所以当加入驱动后,可以通过 depmod 自动生成依赖信息:

depmod -a
依赖信息会被写入到 modules.dep 文件中,内核通过该文件对驱动进行正确加载。

2.2 问题重现

从引导过程中可以发现,vmlinuz 内核主要依赖 /lib/modules 下的内核驱动来对外部设备提供支持。

而在这起事件中,攻击者恶意删除了/lib/modules 下的所有文件。

于是在后续安装驱动中,/lib/modules 的内容被同步到 initramfs 中,但此时目录下已然没有完整的驱动信息。所以内核在挂载 initramfs 后,无法正常加载驱动程序,提示无法找到 modules.dep 文件,此时并非读取真正根目录下的 /lib/modules :-)。

2.3 修复内核模块

对于 /lib/modules 下的内核模块,正常通过编译 Linux 内核来生成,当然也可以用过 yum / apt 等在线包管理工具来重新安装 Linux 内核。

在机器与网络隔离的情况下,无法通过网络下载编译完的二进制文件,也许只能通过自行编译内核来修复。

但编译内核也需要对应的编译工具、环境、源码包等。另一种更简单的方式,可以下载对应的发行版的镜像,来进行修复。

首先通过镜像引导,进入 rescue 救援模式终端,由于发行版的版本、内核型号都相同,同时镜像也是跑在相同的机器上,所以载入的驱动也是一致。

通常进入救援模式时,都会自动帮你挂载原机的系统分区,例如 CentOS 将其挂在到 /mnt/sysimage 下。

1)先将所有驱动模块拷贝到原本的系统节点:

cp -R /lib/modules/2.6.32-696.el6.x86_64 /mnt/sysimage/lib/modules/

2)切换 /mnt/sysimage 为根目录:

chroot /mnt/sysimage

此时访问 / 下的任何内容,实际上为 /mnt/sysimage 。

3)进入 /boot 节点,重构 initramfs 镜像,记得备份:

cd /boot
cp initramfs-2.6.32-696.el6.x86_64.img initramfs-2.6.32-696.el6.x86_64.org

# -f 覆盖原始 initramfs 镜像
# -v 显示详细信息
dracut -f -v initramfs-2.6.32-696.el6.x86_64.img 2.6.32-696.el6.x86_64

dracut 用于重构 initramfs 镜像,最后的内核版本号要对应 /lib/modules 下的版本。

4)如果过程中修改了其他文件(例如修改了 shadow 等文件),由于 SELinux 的缘故,需要加入 SELinux 重建标识:

touch /.autorelabel

重启,首次进入时,等待 SELinux 重新建立策略:

未分类

再次重启后,正常进入系统,基本模块修复:

未分类

0x4 总结

  • 内核通过 initramfs 载入核心驱动为基础的外部设备提供支持
  • 内核模块位于 /lib/modules/<内核版本> 下,modules.dep 记录模块索引,使用 depmod -a 可以自动建立依赖信息
  • 使用 dracut 可以对 initramfs 进行重建,将 /lib/modules/ 下的核心模块打包到虚拟文件系统当中
  • 在 SELinux 的上下文下,需要建立 /.autorelabel 通知 SELinux 重新建立策略

总体而言都是在干运维的活,但是 Loader 的加载机制还是十分有趣。

mysql手动删除BINLOG的方法

在MySQL中执行以下命令:

PURGE {MASTER | BINARY} LOGS TO ‘log_name'

PURGE {MASTER | BINARY} LOGS BEFORE ‘date'

PURGE {MASTER|BINARY} LOGS BEFORE DATE_SUB(NOW(),INTERVAL 7 DAY);

例如:

mysql>PURGE MASTER LOGS TO ‘mysql-bin.010′;

mysql>PURGE MASTER LOGS BEFORE ‘2008-06-22 13:00:00′;

mysql>PURGE MASTER LOGS BEFORE DATE_SUB( NOW( ), INTERVAL 7 DAY);