使用的qqwry库(ip地址定位)地址: https://github.com/out0fmemory/qqwry.dat

查询脚本: https://pypi.org/project/qqwry-py3/

脚本只在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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import os
from time import sleep
import re
from urllib import request
import socket
import json
from qqwry import QQwry
import logging


def login_info():
    tmp = []
    infos = os.popen('who /var/log/wtmp')
    pat = re.compile(r'.*\((.*)\)')
    for line in infos:
        if pat.findall(line):
            tmp.append(line.strip('\n'))

    return tmp


def ip_location(ip):
    if ip == 'localhost':
        ip = '127.0.0.1'
    q = QQwry()
    q.load_file('qqwry.dat')
    res = q.lookup(ip)

    return res[0]


def notify(hostname, user, datetime, ip, token, location):
    notify_title = str(hostname) + '异地登陆告警'
    notify_text = '### ' + str(hostname) + '异地登陆告警: ' + '\n' \
                  + '##### 登陆地址: ' + str(ip) + '(' + str(location) + ')' + '\n' \
                  + '##### 登陆时间: ' + str(datetime) + '\n' \
                  + '##### 登陆用户: ' + str(user)

    params = {
        "msgtype": "markdown",
        "markdown": {
            "title": notify_title,
            "text": notify_text
        }
    }
    params = bytes(json.dumps(params), 'utf8')
    url = 'https://oapi.dingtalk.com/robot/send?access_token='+str(token)
    headers = {'Accept-Charset': 'utf-8', 'Content-Type': 'application/json'}

    req = request.Request(url=url, data=params, headers=headers, method='POST')
    request.urlopen(req).read()


def get_diff(list_login_info_new):
    count = 0
    for line in list_login_info_new:
        if line not in list_login_info_first:
            tmp_list = re.split(r'\s+', line)
            tmp_list2 = re.split('[()]', tmp_list[4])
            tmp_location = ip_location(tmp_list2[1])
            if '局域网' in tmp_location or '本机' in tmp_location:
                pass
            elif '上海市' not in tmp_location or tmp_list[0] != 'root':
                notify(socket.gethostname(), tmp_list[0], tmp_list[2] + " " + tmp_list[3], tmp_list2[1],
                       'dingtalk token', tmp_location)

                count += 1
            logging.info('Ip %s location is: %s', tmp_list2[1], tmp_location)


LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
DATE_FORMAT = "%m/%d/%Y %H:%M:%S"

logging.basicConfig(filename='monitor_ssh_login.log', level=logging.INFO, format=LOG_FORMAT, datefmt=DATE_FORMAT)


if __name__ == '__main__':
    list_login_info_first = login_info()

    while True:
        sleep(10)
        list_login_info_new = login_info()
        if len(list_login_info_new) != len(list_login_info_first):
            logging.info('Discover login user!')
            get_diff(list_login_info_new)
            list_login_info_first = list_login_info_new
        else:
            logging.info('No login user!')