File size: 8,586 Bytes
e326fe5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
import ipaddress
import maxminddb
from fastapi import FastAPI, Request
import json
import datetime
import logging
import sys
import os
from logging.handlers import RotatingFileHandler

LOG_FILE = os.path.join('/code', 'ip_query.log')

try:
    formatter = logging.Formatter('%(message)s')
    log_handler = RotatingFileHandler(
        LOG_FILE,
        maxBytes=10*1024*1024,
        backupCount=5,
        encoding='utf-8'
    )
    log_handler.setFormatter(formatter)
    logger = logging.getLogger('ip_query')
    logger.setLevel(logging.INFO)
    logger.addHandler(log_handler)
    startup_log = {
        "时间": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "事件": "系统启动",
        "状态": "成功"
    }
    logger.info(json.dumps(startup_log, ensure_ascii=False))
except Exception as e:
    print(f"日志初始化失败: {e}")
    sys.exit(1)

city_reader = maxminddb.open_database('GeoLite2-City.mmdb')
asn_reader = maxminddb.open_database('GeoLite2-ASN.mmdb')
cn_reader = maxminddb.open_database('GeoCN.mmdb')
lang = ["zh-CN", "en"]
asn_map = {
    9812: "东方有线",
    9389: "中国长城",
    17962: "天威视讯",
    17429: "歌华有线",
    7497: "科技网",
    24139: "华数",
    9801: "中关村",
    4538: "教育网",
    24151: "CNNIC",
    38019: "中国移动", 139080: "中国移动", 9808: "中国移动", 24400: "中国移动", 134810: "中国移动", 24547: "中国移动",
    56040: "中国移动", 56041: "中国移动", 56042: "中国移动", 56044: "中国移动", 132525: "中国移动", 56046: "中国移动",
    56047: "中国移动", 56048: "中国移动", 59257: "中国移动", 24444: "中国移动",
    24445: "中国移动", 137872: "中国移动", 9231: "中国移动", 58453: "中国移动",
    4134: "中国电信", 4812: "中国电信", 23724: "中国电信", 136188: "中国电信", 137693: "中国电信", 17638: "中国电信",
    140553: "中国电信", 4847: "中国电信", 140061: "中国电信", 136195: "中国电信", 17799: "中国电信", 139018: "中国电信",
    134764: "中国电信", 4837: "中国联通", 4808: "中国联通", 134542: "中国联通", 134543: "中国联通",
    59019: "金山云",
    135377: "优刻云",
    45062: "网易云",
    37963: "阿里云", 45102: "阿里云国际",
    45090: "腾讯云", 132203: "腾讯云国际",
    55967: "百度云", 38365: "百度云",
    58519: "华为云", 55990: "华为云", 136907: "华为云",
    4609: "澳門電訊",
    13335: "Cloudflare",
    55960: "亚马逊云", 14618: "亚马逊云", 16509: "亚马逊云",
    15169: "谷歌云", 396982: "谷歌云", 36492: "谷歌云",
}

def get_as_info(number):
    r = asn_map.get(number)
    if r:
        return r

def get_des(d):
    for i in lang:
        if i in d['names']:
            return d['names'][i]
    return d['names']['en']

def get_country(d):
    r = get_des(d)
    if r in ["香港", "澳门", "台湾"]:
        return "中国" + r
    return r

def province_match(s):
    arr = ['内蒙古', '黑龙江', '河北', '山西', '吉林', '辽宁', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '海南', '四川', '贵州', '云南', '陕西', '甘肃', '青海', '广西', '西藏', '宁夏', '新疆', '北京', '天津', '上海', '重庆']
    for i in arr:
        if i in s:
            return i
    return ''

def de_duplicate(regions):
    regions = filter(bool, regions)
    ret = []
    [ret.append(i) for i in regions if i not in ret]
    return ret

def get_addr(ip, mask):
    network = ipaddress.ip_network(f"{ip}/{mask}", strict=False)
    first_ip = network.network_address
    return f"{first_ip}/{mask}"

def get_maxmind(ip: str):
    ret = {"ip": ip}
    asn_info = asn_reader.get(ip)
    if asn_info:
        as_ = {"number": asn_info["autonomous_system_number"], "name": asn_info["autonomous_system_organization"]}
        info = get_as_info(as_["number"])
        if info:
            as_["info"] = info
        ret["as"] = as_

    city_info, prefix = city_reader.get_with_prefix_len(ip)
    ret["addr"] = get_addr(ip, prefix)
    if not city_info:
        return ret
    
    if "location" in city_info:
        location = city_info["location"]
        ret["location"] = {
            "latitude": location.get("latitude"),
            "longitude": location.get("longitude")
        }
    
    if "country" in city_info:
        country_code = city_info["country"]["iso_code"]
        country_name = get_country(city_info["country"])
        ret["country"] = {"code": country_code, "name": country_name}
    
    if "registered_country" in city_info:
        registered_country_code = city_info["registered_country"]["iso_code"]
        ret["registered_country"] = {"code": registered_country_code, "name": get_country(city_info["registered_country"])}
        
    regions = [get_des(i) for i in city_info.get('subdivisions', [])]

    if "city" in city_info:
        c = get_des(city_info["city"])
        if (not regions or c not in regions[-1]) and c not in country_name:
            regions.append(c)
            
    regions = de_duplicate(regions)
    if regions:
        ret["regions"] = regions
    
    return ret

def get_cn(ip: str, info={}):
    ret, prefix = cn_reader.get_with_prefix_len(ip)
    if not ret:
        return
    info["addr"] = get_addr(ip, prefix)
    regions = de_duplicate([ret["province"], ret["city"], ret["districts"]])
    if regions:
        info["regions"] = regions
        info["regions_short"] = de_duplicate([province_match(ret["province"]), ret["city"].replace('市', ''), ret["districts"]])
    if "as" not in info:
        info["as"] = {}
    info["as"]["info"] = ret['isp']
    if ret['net']:
        info["type"] = ret['net']
    return ret

def get_ip_info(ip):
    info = get_maxmind(ip)
    if "country" in info and info["country"]["code"] == "CN" and ("registered_country" not in info or info["registered_country"]["code"] == "CN"):
        get_cn(ip, info)
    return info

def query():
    while True:
        try:
            ip = input('IP:   \t').strip()
            info = get_ip_info(ip)
            print(f"网段:\t{info['addr']}")
            if "location" in info:
                print(f"经纬度:\t{info['location']['latitude']}, {info['location']['longitude']}")
            if "as" in info:
                print(f"ISP:\t", end=' ')
                if "info" in info["as"]:
                    print(info["as"]["info"], end=' ')
                else:
                    print(info["as"]["name"], end=' ')
                if "type" in info:
                    print(f"({info['type']})", end=' ')
                print(f"ASN{info['as']['number']}", end=' ')
                print(info['as']["name"])
            if "registered_country" in info and ("country" not in info or info["country"]["code"] != info["registered_country"]["code"]):
                print(f"注册地:\t{info['registered_country']['name']}")
            if "country" in info:
                print(f"使用地:\t{info['country']['name']}")
            if "regions" in info:
                print(f"位置:    \t{' '.join(info['regions'])}")
        except Exception as e:
            print(e)
            raise e
        finally:
            print("\n")
            
app = FastAPI()

@app.get("/")
async def api(request: Request, ip: str = None):
    client_ip = request.headers.get("x-forwarded-for") or request.headers.get("x-real-ip") or request.client.host
    query_ip = ip.strip() if ip else client_ip
    result = get_ip_info(query_ip)
    log_data = {
        "时间": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "访问IP": client_ip,
        "查询IP": query_ip,
        "请求头": dict(request.headers),
        "查询结果": result
    }
    logger.info(json.dumps(log_data, ensure_ascii=False))
    return result

@app.get("/{ip}")
async def path_api(request: Request, ip: str):
    client_ip = request.headers.get("x-forwarded-for") or request.headers.get("x-real-ip") or request.client.host
    result = get_ip_info(ip)
    log_data = {
        "时间": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        "访问IP": client_ip,
        "查询IP": ip,
        "请求头": dict(request.headers),
        "查询结果": result
    }
    logger.info(json.dumps(log_data, ensure_ascii=False))
    return result

if __name__ == '__main__':
    query()
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8080, server_header=False, proxy_headers=True)