免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3137 | 回复: 7

FreeBSD下的stdin读取求助 [已解决,感谢@HH106和@timespace] [复制链接]

论坛徽章:
0
发表于 2014-04-13 23:48 |显示全部楼层
本帖最后由 ljwsy 于 2014-04-15 17:28 编辑

我自己构思了一个“ssh扫描封堵的实现过程”,用的是py实现,经过近两年的运行,效果还不错。脚本是用crontab来运行的,控制粒度为分钟,太低了点,对付慢扫是足够的,而对付脑残不管别人感受的狂扫则有点吃力:开5线程一秒的扫描,一分钟就有300+个记录,等程序反应过来添加防火墙后,这个记录量上升已成事实。

为改变这种现状,打算改用守护进程的方式监控。想法是这样的:脚本进程实时监控auth.log,一旦有新的扫描行则入库;每5分钟从库中提取触犯规则的IP重新生成防火墙规则;在重新生成防火墙规则之间的时间段中,只要某IP产生的扫描记录数超过6条,就把这IP加入临时违规并生成防火墙规则。

为实现上面的想法,我把auth.log重定向为守护进程的stdin,但我用下面的代码“监控”stdin时却只取到进程启动时当前stdin存在的行,新行则取不到(注:因为是测试脚本,不直接用auth.log作为输入,而是改用每分钟都有新行生成的sshdipfw.log)。
  1. #!/usr/local/bin/python

  2. # -*-coding:utf-8-*-
  3. import sys, os, time

  4. fname='/tmp/sshd_new.pid'

  5. def daemonize(stdin='/dev/null',stdout= '/dev/null', stderr= 'dev/null'):
  6.     if os.path.isfile(fname) :
  7.         if (time.time()-os.path.getatime(fname)<300) :
  8.             exit()

  9.     #Perform first fork.
  10.     try:
  11.         pid = os.fork()
  12.         if pid > 0:
  13.             sys.exit(0)  #first parent out
  14.     except OSError, e:
  15.         sys.stderr.write("fork #1 failed: (%d) %s\n" %(e.errno, e.strerror))
  16.         sys.exit(1)

  17.     os.chdir("/")
  18.     os.umask(0)
  19.     os.setsid()
  20.     #fork
  21.     try:
  22.         pid = os.fork()
  23.         if pid > 0:
  24.             sys.exit(0) #second parent out
  25.     except OSError, e:
  26.         sys.stderr.write("fork #2 failed: (%d) %s]n" %(e.errno,e.strerror))
  27.         sys.exit(1)
  28.     #
  29.     for f in sys.stdout, sys.stderr: f.flush()
  30.     si = file(stdin, 'r')
  31.     so = file(stdout,'a+')
  32.     se = file(stderr,'a+',0)
  33.     os.dup2(si.fileno(), sys.stdin.fileno())
  34.     os.dup2(so.fileno(), sys.stdout.fileno())
  35.     os.dup2(se.fileno(), sys.stderr.fileno())
  36.     pid=open(fname,'w')
  37.     print >> pid,'Daemon started with pid %d\n' % os.getpid()
  38.     pid.close()

  39. def _example_main():
  40.     sys.stdout.write('Daemon started with pid %d\n' % os.getpid())
  41.     sys.stdout.write('Daemon stdout output\n')
  42.     sys.stderr.write('Daemon stderr output\n')
  43.     c = 0
  44.     while True:
  45.         for line in sys.stdin:
  46.             sys.stdout.write('%s: %s' %( time.ctime(),line))
  47.             sys.stdout.flush()
  48.             c = c+1
  49.             #time.sleep(1)

  50. if __name__ == "__main__":
  51.     daemonize('/var/log/sshdipfw.log','/var/log/sshdipfw_new.log','/var/log/sshdipfw_new.log')
  52.     _example_main()
复制代码
这是sshdipfw_new.log输出(stdout):
  1. ……
  2. Sun Apr 13 23:30:36 2014: update at 2014-04-13 23:29:00.
  3. Sun Apr 13 23:30:36 2014:               Total rule(s)   ->      86
  4. Sun Apr 13 23:30:36 2014: update at 2014-04-13 23:30:00.
  5. Sun Apr 13 23:30:36 2014:               Total rule(s)   ->      86
复制代码
而新的sshdipfw.log(stdin)多出的几行则不见出现在sshdipfw_new.log(stdout)中:
  1. ……
  2. update at 2014-04-13 23:29:00.
  3.                 Total rule(s)   ->      86
  4. update at 2014-04-13 23:30:00.
  5.                 Total rule(s)   ->      86
  6. update at 2014-04-13 23:31:00.
  7.                 Total rule(s)   ->      86
  8. update at 2014-04-13 23:32:00.
  9.                 Total rule(s)   ->      86
  10. update at 2014-04-13 23:33:00.
  11.                 Total rule(s)   ->      86
  12. update at 2014-04-13 23:34:00.
  13.                 Total rule(s)   ->      86
复制代码
呵呵,由于本人拿着比码农的一半不到的工资,自然水平也不会高到哪里去,通常都是碰到什么问题才会想着去解决什么问题,所以水平提高得非常的慢。在此想请教达人:在_example_main()段我怎样监控,如果有新行则取到新的行(如原来的最后行时间为23:30:00以及它下面的一行,这个点以后的都视为新行),再进行处理(原来我是从从文件头读取再对比时间——这样做效率太低)。

要不坛友有什么更好的办法指点指点也行,反正是要实现这功能:实时监控某文件,有新行则处理。

在此先谢谢您的指导,也谢谢来围观或回帖的坛友。

论坛徽章:
9
2015亚冠之阿尔纳斯尔
日期:2015-09-10 16:21:162015亚冠之塔什干火车头
日期:2015-07-01 16:23:022015年亚洲杯之巴勒斯坦
日期:2015-04-20 17:19:46子鼠
日期:2014-11-13 09:51:26未羊
日期:2014-08-28 18:13:36技术图书徽章
日期:2014-02-21 09:30:15酉鸡
日期:2014-01-14 11:12:49天蝎座
日期:2013-12-09 17:56:53平安夜徽章
日期:2015-12-26 00:06:30
发表于 2014-04-14 09:56 |显示全部楼层
这样试试?利用tail命令

command='tail -f '+/var/log/sshdipfw.log+'|grep "xxx"'  
popen=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)

论坛徽章:
0
发表于 2014-04-14 10:16 |显示全部楼层
回复 2# HH106


    谢谢您的回复,今早来上班后一直在试着各种办法,感觉用管道应该可以解决问题,正不知道具体怎样做时就见您的回复,我再努力奋斗一番……

还有个笨办法是:查文件的存取时间,与原来的有变化则只取后面的100行,这样做就减少了不少的无效行处理时间。

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
发表于 2014-04-14 10:22 |显示全部楼层
如果stdin不是指向交互设备,默认是全缓存,所以遇到换行可能不刷新缓存,试下"si = file(stdin, 'r', buffering=1)"。

如果上面的方法解决不了,那就是另外一个问题了,用常规文件没法单独模拟重定向,就像shell的重定向,要借助os.pipe。

还有一个办法,模拟“tail -f”的行为,直接打开auth.log,定时file.seek文件尾部,有变化就读取变化的部分。如果觉得定时轮询比较低效,可以用select.kqueue,各类BSD系统都支持。

论坛徽章:
11
技术图书徽章
日期:2014-03-01 14:44:34天蝎座
日期:2014-05-21 22:11:59金牛座
日期:2014-05-30 17:06:14
发表于 2014-04-14 10:27 |显示全部楼层
哈,刚回复,才看到楼上有提到tail + subprocess,确实这个更简单,搞定问题就行。

论坛徽章:
0
发表于 2014-04-14 18:37 |显示全部楼层
回复 4# timespace


    感谢提供方向。真心话:由于平时用的少,没有去深入研究,您所提到的方法大致有印象,不敢再问具体实施,只有自己摸索,也权当提高自己水平的之一。

论坛徽章:
0
发表于 2014-04-15 17:25 |显示全部楼层
回复 2# HH106


    这方法真好用,现在被监控文件只要有变动,在stdout文件中不到一秒就体现出来。

    再次表示感谢。

  1. ...
  2.      a=subprocess.Popen(args='/usr/bin/tail -f /var/log/sshdipfw.log',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
  3.     while True:
  4.         c=a.stdout.readline()
  5.         if len(c)>5 :    #忽略空行
  6.             sys.stdout.write('%s: \n\t%s\n' %( time.ctime(),c[:-1]))
  7.             sys.stdout.flush()
复制代码

论坛徽章:
0
发表于 2014-04-15 17:26 |显示全部楼层
回复 5# timespace


    已经完美解决,再次表示感谢。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

DTCC2020中国数据库技术大会

【架构革新 高效可控】2020年12月21日-23日第十一届中国数据库技术大会将在北京隆重召开。

大会设置2大主会场,20+技术专场,将邀请超百位行业专家,重点围绕数据架构、AI与大数据、传统企业数据库实践和国产开源数据库等内容展开分享和探讨,为广大数据领域从业人士提供一场年度盛会和交流平台。

http://dtcc.it168.com


大会官网>>
  

北京盛拓优讯信息技术有限公司. 版权所有 16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122
中国互联网协会会员  联系我们:huangweiwei@it168.com
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP