linux 脚本 上网限制,一个linux下限制进程的小脚本

缘起

最近在做一门课程设计,需要实现这样的功能:在linux操作系统中部署一个网站,当网站部署完毕后,监控操作系统中的进程,杀死所有不在白名单中的进程,以防止恶意程序运行。大概搜索了下,没有找到现成可用的解决方案,决定自己实现。

设计

在linux中有许多系统必须的进程,若将这些进程都纳入白名单则白名单的配置会很繁琐。

简单起见,我们选择在操作系统启动完成、稳定运行后再运行限制进程的程序,检测新生进程,若不在白名单中则杀死该进程。

已经运行了较长时间的进程则被默认为系统进程而不做处理。

如何检测新生进程?用“ps -aux”命令查看进程,可以看到有名为START的列为进程启动时间,通过启动时间可以得知进程是否新生。该命令输出如下所示:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND

root 1 0.0 0.0 34124 4660 ? Ss 18:09 0:01 /sbin/init

root 2 0.0 0.0 0 0 ? S 18:09 0:00 [kthreadd]

root 3 0.0 0.0 0 0 ? S 18:09 0:00 [ksoftirqd/0]

root 5 0.0 0.0 0 0 ? S 18:09 0:00 [kworker/0:0H]

root 7 0.0 0.0 0 0 ? S 18:09 0:01 [rcu_sched]

但“ps -aux”命令输出的内容太多了,我们实际上只需要PID、START和COMMAND这三列信息就足够了。

用“man ps”查看“ps”命令的帮助,发现竟然有一千多行,还真是个强大的命令。从man手册中,我找到了想要的参数“ps -eo “%p%t%c””,该命令输出如下所示:

PID ELAPSED COMMAND

1 50:59 init

2 50:59 kthreadd

3 50:59 ksoftirqd/0

5 50:59 kworker/0:0H

7 50:59 rcu_sched

8 50:59 rcu_bh

9 50:59 migration/0

10 50:59 watchdog/0

PID和COMMAND都在,START没有了,取而代之的是ELAPSED——运行时长,这样处理起来就更方便了。

读取各个进程的信息,若某个进程的ELAPSED小于一个阈值,则判断该进程是否位于白名单中,若不在白名单中,则杀死它。

如何杀死一个进程呢?我们通过“ps”命令已经知道要杀死的进程的PID了,所以用kill命令就可以杀死进程。

kill命令实际上是在向目标进程发送信号,不加任何参数默认发送的信号是SIGTERM,这一信号是可以被目标进程忽略的,所以这里要加上参数“-KILL”,发送无法忽略的信号SIGKILL,这样能更为有效地杀死进程。

当然,为了避免没有权限而无法杀死进程,杀死进程的操作要有root权限。

进程是在不断产生的,进程检测也需要不断进行。如何周期性地检测进程呢?写一个死循环并sleep当然是一种方法,但在linux中有更方便地crontab(定时任务)。假设我们检测、限制进程的脚本名叫“pctrl.py”(是的,我是用Python实现的),放在目录“/opt/”中,则可以这样做:先用命令“sudo su”切换到root身份,然后执行命令“crontab -e”来编辑定时任务的配置文件,在其中加入一行,内容为:

*/1 * * * * /usr/bin/python /opt/pctrl.py

保存并退出后脚本“pctrl.py”便会以root权限每分钟被执行一次。分钟级是crontab所能达到的最小的时间粒度,想要更小的时间粒度,只能在脚本中实现了。例如,我想要每0.5秒检测一次,则脚本中应该有一个120次的循环,每次循环sleep半秒。

最后,日志也是很关键的。所有尝试杀死的进程都可能是恶意程序,记录日志是必要且有价值的。我们设计日志中输出时间、进程号、程序名(COMMAND)和是否成功杀死它,若失败,则也输出失败原因(失败原因即kill命令的输出)。

实现

用Python来实现上述设计。Python执行系统命令使用了库commands,用该库执行系统命令可以返回命令执行结果状态和命令输出,这些都是我们需要的。脚本“pctrl.py”内容如下:

#!/usr/bin/python

# ^_^ coding:utf8 ^_^

###############################################

# sudo su #

# crontab -e #

# */1 * * * * /usr/bin/python /opt/pctrl.py #

###############################################

import os

import sys

import time

import logging

import commands

#配置日志,根据实际情况修改日志路径

logging.basicConfig(level=logging.DEBUG,

format='[%(asctime)s] [%(levelname)s] %(message)s',

datefmt='%Y.%m.%d %H:%M:%S',

filename='/var/log/pctrl.log',

filemode='a+')

#配置白名单,根据实际需要修改白名单内容

white_list = ['/usr/sbin/apache2 -k start']

#杀死进程

def killprocess(pid, comm):

(status, output) = commands.getstatusoutput('kill -KILL ' + pid)

if status == 0:

logging.info('Successfully killed the process ' + pid + ': ' + comm)

elif 'kill: No such process' not in output:

reason = output.replace('\n', '')

logging.warning('Failed to kill the process ' /

+ pid + ': ' + comm + ': '+ reason)

#检测进程

def monitorprocess(timelimit):

(status, output) = commands.getstatusoutput('ps -eo "%p_%t_%c"')

if status == 0:

processes = output.split('\n')[1:]

for process in processes:

process = process.replace(' ', '').split('_')

pid = process[0]

time = process[1].split(':')

time = int(time[0])*60 + int(time[1])

comm = process[2]

if str(os.getpid()) == pid:

#不杀死自己

continue

if comm in white_list:

#不杀死在白名单中的程序

continue

if time < timelimit:

killprocess(pid, comm)

else:

logging.warning('The process of obtaining information failed')

if __name__ == '__main__':

for i in range(0, 120):

monitorprocess(60)

time.sleep(0.5)

测试

将上述脚本部署到测试用的安装了Apache服务器的虚拟机中进程测试。

部署完成后确实无法启动各种耗时较长的程序,而类似ifconfig这样一瞬间就能执行完毕的程序则不受影响。

从另一台机器访问测试虚拟机中的网站,发现Web服务是不受影响的。

查看“pctrl.py”的日志如下所示:

test@test-VirtualBox:~$ cat /var/log/pctrl.log

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6270: crontab

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6271: sh

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6272: sensible-editor

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6280: select-editor

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6294: cron

[2017.09.20 19:41:01] [INFO] Successfully killed the process 6295: sh

[2017.09.20 19:41:04] [INFO] Successfully killed the process 6327: crontab

[2017.09.20 19:41:04] [INFO] Successfully killed the process 6328: sh

[2017.09.20 19:41:04] [INFO] Successfully killed the process 6329: sensible-editor

[2017.09.20 19:41:04] [INFO] Successfully killed the process 6337: editor

[2017.09.20 19:41:37] [INFO] Successfully killed the process 6614: firefox

[2017.09.20 19:41:37] [INFO] Successfully killed the process 6620: firefox

[2017.09.20 19:41:42] [INFO] Successfully killed the process 6680: gnome-screensho

若不关闭crontab而直接重启操作系统,很可能会导致系统无法重启。所以在关机前,一定要先关闭crontab。

总结

整个脚本写完后自己很不满意,怎么看都很幼稚。我虽然用了两年Ubuntu,但并不了解其细节,所以只能想出这种水平的实现方法。

这种方式有诸多缺点:

部署、关闭都很不方便

要频繁检测,不是触发式的,消耗资源较多

恶意程序开机时就运行则无效

恶意进程在0.5秒内执行完毕则无效

恶意进程被隐藏,用ps命令看不到则无效

恶意程序以正常进程子线程的方式运行则无效

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值