├── README.md ├── ip.py ├── qqwry.py └── qqwry_iconv.py /README.md: -------------------------------------------------------------------------------- 1 | # geoip-utils 2 | 3 | download [GeoIP.dat and GeoLiteCity.dat](www.maxmind.com/download/geoip/database/) 4 | download [qqwry.rar](http://update.cz88.net/soft/qqwry.rar) 5 | 6 | convert qqwry.dat.gbk to qqwry.dat(utf8) 7 | 8 | python qqwry_iconv.py 9 | 10 | search ip by qqwry.dat 11 | 12 | python qqwry.py 114.112.57.180 13 | 14 | search ip by geoip 15 | 16 | pip install pygeoip 17 | python ip.py -------------------------------------------------------------------------------- /ip.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding=utf-8 -*- 3 | 4 | # http://www.ywjt.org/index/archives/746.html 5 | # http://dev.maxmind.com/geoip/geolite 6 | # Geo-Region:省份,22=BEIJING=北京 7 | 8 | import os.path 9 | import re 10 | import pygeoip 11 | from subprocess import Popen, PIPE, STDOUT 12 | 13 | from sqlalchemy import * 14 | 15 | url="http://ip.taobao.com/service/getIpInfo.php?ip=" 16 | 17 | gi = pygeoip.GeoIP("./data/GeoLiteCity.dat", pygeoip.MEMORY_CACHE) 18 | 19 | def get_login_ipaddrs(host, table, user, passwd, sqltext): 20 | db = create_engine('mysql://%s:%s@%s/%s?charset=utf8'%(user, passwd, host, table), echo=False) 21 | conn = db.connect() 22 | c = conn.execute(sqltext) 23 | entries = [row['f_ip'] for row in c.fetchall()] 24 | conn.close() 25 | return entries 26 | 27 | def get_player_ip(sid): 28 | #sqltext = "select f_ip from gm_login_num where f_login_time > DATE_SUB(CURDATE(), INTERVAL 3 DAY);" 29 | sqltext = "select f_ip from gm_login_num;" 30 | return get_login_ipaddrs("192.168.1.21", "webgame_%s"%(sid), "webgame", "game", sqltext) 31 | 32 | # def get_player_ip(): 33 | # #cmd_netstat = " netstat -nat | grep ESTABLISHED | awk '{split($4,a,\":\"); a[1]}' " 34 | # cmd_netstat = "netstat -ant | grep ESTABLISHED | grep 44" 35 | # output,error = Popen(cmd_netstat, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT).communicate() 36 | # ipaddrs = [] 37 | # for m in re.finditer('(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})[\.|:]\d+\s+ESTABLISHED', output): 38 | # ipaddrs += [m.group(1)] 39 | # return ipaddrs 40 | 41 | def count_ip(ipaddrs, city): 42 | count = 0 43 | ips = [] 44 | for ip in ipaddrs: 45 | ret = ip_detail(ip) 46 | if ret == city: 47 | ips += [ip] 48 | return city, len(ipaddrs), len(ips), ips 49 | 50 | def ip_detail(ip): 51 | ret = gi.record_by_addr(ip) 52 | return ret["city"] 53 | 54 | def main(): 55 | #print count_ip(["125.70.82.110", "1.203.190.72", "1.203.146.200", "115.171.255.52", "222.128.174.241", "1.203.148.176", "125.70.81.240", "123.124.2.85"], "Beijing") 56 | print count_ip(["115.170.86.204", "114.249.229.33", "114.250.168.29", "122.85.158.181"], "Beijing") 57 | return 58 | for sid in ['s8','s11','s12']: 59 | #for sid in ['s8']: 60 | ipaddrs = get_player_ip(sid) 61 | print count_ip(ipaddrs, "Beijing") 62 | 63 | if __name__ == '__main__': 64 | main() 65 | -------------------------------------------------------------------------------- /qqwry.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | import sys 5 | import socket 6 | from struct import pack, unpack 7 | 8 | UTF8_DAT = True 9 | 10 | class IPInfo(object): 11 | def __init__(self, dbname): 12 | self.dbname = dbname 13 | f = file(dbname, 'r') 14 | self.img = f.read() 15 | f.close() 16 | (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8]) 17 | self.indexCount = (self.lastIndex - self.firstIndex) / 7 + 1 18 | 19 | def getString(self, offset = 0): 20 | o2 = self.img.find('\0', offset) 21 | utf8 = self.img[offset:o2] 22 | if not UTF8_DAT: 23 | utf8 = unicode(utf8,'gbk').encode('utf-8') 24 | return utf8 25 | 26 | def getLong3(self, offset = 0): 27 | s = self.img[offset: offset + 3] 28 | s += '\0' 29 | return unpack('I', s)[0] 30 | 31 | def getAreaAddr(self, offset = 0): 32 | byte = ord(self.img[offset]) 33 | if byte == 1 or byte == 2: 34 | p = self.getLong3(offset + 1) 35 | return self.getAreaAddr(p) 36 | else: 37 | return self.getString(offset) 38 | 39 | def getAddr(self, offset, ip = 0): 40 | img = self.img 41 | o = offset 42 | byte = ord(img[o]) 43 | 44 | if byte == 1: 45 | return self.getAddr(self.getLong3(o + 1)) 46 | 47 | if byte == 2: 48 | cArea = self.getAreaAddr(self.getLong3(o + 1)) 49 | o += 4 50 | aArea = self.getAreaAddr(o) 51 | return (cArea, aArea) 52 | 53 | if byte != 1 and byte != 2: 54 | cArea = self.getString(o) 55 | o = self.img.find('\0',o) + 1 56 | aArea = self.getString(o) 57 | return (cArea, aArea) 58 | 59 | def find(self, ip, l, r): 60 | if r - l <= 1: 61 | return l 62 | 63 | m = (l + r) / 2 64 | o = self.firstIndex + m * 7 65 | new_ip = unpack('I', self.img[o: o+4])[0] 66 | if ip <= new_ip: 67 | return self.find(ip, l, m) 68 | else: 69 | return self.find(ip, m, r) 70 | 71 | def getIPAddr(self, ip): 72 | ip = unpack('!I', socket.inet_aton(ip))[0] 73 | i = self.find(ip, 0, self.indexCount - 1) 74 | o = self.firstIndex + i * 7 75 | o2 = self.getLong3(o + 4) 76 | (c, a) = self.getAddr(o2 + 4) 77 | return (c, a) 78 | 79 | def output(self, first, last): 80 | for i in range(first, last): 81 | o = self.firstIndex + i * 7 82 | ip = socket.inet_ntoa(pack('!I', unpack('I', self.img[o:o+4])[0])) 83 | offset = self.getLong3(o + 4) 84 | (c, a) = self.getAddr(offset + 4) 85 | print "%s %d %s/%s" % (ip, offset, c, a) 86 | 87 | 88 | def main(): 89 | i = IPInfo('QQWry.Dat') 90 | (c, a) = i.getIPAddr(sys.argv[1]) 91 | print '%s %s/%s' % (sys.argv[1], c, a) 92 | 93 | if __name__ == '__main__': 94 | # import sys 95 | # reload(sys) 96 | # sys.setdefaultencoding('utf-8') 97 | main() 98 | -------------------------------------------------------------------------------- /qqwry_iconv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding: utf-8 3 | 4 | '''用Python脚本查询纯真IP库 5 | 6 | QQWry.Dat的格式如下: 7 | 8 | +----------+ 9 | | 文件头 | (8字节) 10 | +----------+ 11 | | 记录区 | (不定长) 12 | +----------+ 13 | | 索引区 | (大小由文件头决定) 14 | +----------+ 15 | 16 | 文件头:4字节开始索引偏移值+4字节结尾索引偏移值 17 | 18 | 记录区: 每条IP记录格式 ==> IP地址[国家信息][地区信息] 19 | 20 | 对于国家记录,可以有三种表示方式: 21 | 22 | 字符串形式(IP记录第5字节不等于0x01和0x02的情况), 23 | 重定向模式1(第5字节为0x01),则接下来3字节为国家信息存储地的偏移值 24 | 重定向模式(第5字节为0x02), 25 | 26 | 对于地区记录,可以有两种表示方式: 字符串形式和重定向 27 | 28 | 最后一条规则:重定向模式1的国家记录后不能跟地区记录 29 | 30 | 索引区: 每条索引记录格式 ==> 4字节起始IP地址 + 3字节指向IP记录的偏移值 31 | 32 | 索引区的IP和它指向的记录区一条记录中的IP构成一个IP范围。查询信息是这个 33 | 范围内IP的信息 34 | 35 | ''' 36 | 37 | import sys 38 | import socket 39 | from struct import pack, unpack 40 | 41 | class IpInfo: 42 | pass 43 | 44 | class WryDat(): 45 | def load(self, dbname): 46 | f = file(dbname, 'r') 47 | self.img = f.read() 48 | f.close() 49 | (self.first_idx, self.last_idx) = unpack('II', self.img[:8]) 50 | self.load_indexes() 51 | 52 | def get_iprange(self, idx): 53 | next_idx = idx + 4 54 | iprange = unpack('I', self.img[idx:idx+4])[0] 55 | return iprange, next_idx 56 | 57 | def get_addr_by_offset(self, idx): 58 | next_idx = idx + 3 59 | offset = unpack("I", self.img[idx:idx+3]+"\0")[0] 60 | #print hex(idx), hex(next_idx) 61 | byte = ord(self.img[offset]) 62 | if byte == 0x01 or byte == 0x02: 63 | addr = self.get_addr_by_offset(offset+1)[0] 64 | else: 65 | addr = self.get_addr_by_string(offset)[0] 66 | return addr, next_idx 67 | 68 | def get_addr_by_string(self, idx): 69 | next_idx = self.img.find('\0', idx)+1 70 | #print hex(idx), hex(next_idx) 71 | try: 72 | area_utf8 = unicode(self.img[idx:next_idx],'gbk').encode('utf-8') 73 | #print area_utf8 74 | return area_utf8, next_idx 75 | except: 76 | pass 77 | return "", next_idx 78 | 79 | def load_ipinfo(self, offset): 80 | ipinfo = IpInfo() 81 | 82 | ipinfo.iprange, idx = self.get_iprange(offset) 83 | byte = ord(self.img[idx]) 84 | if byte == 0x01: 85 | ipinfo.country, idx = self.get_addr_by_offset(idx+1) 86 | ipinfo.area = "" 87 | else: 88 | if byte == 0x02: 89 | ipinfo.country, idx = self.get_addr_by_offset(idx+1) 90 | else: 91 | ipinfo.country, idx = self.get_addr_by_string(idx) 92 | 93 | byte = ord(self.img[idx]) 94 | if byte == 0x01 or byte == 0x02: 95 | ipinfo.area, idx = self.get_addr_by_offset(idx+1) 96 | else: 97 | ipinfo.area, idx = self.get_addr_by_string(idx) 98 | 99 | return ipinfo 100 | 101 | def load_indexes(self): 102 | self.indexes = [] 103 | idx = self.first_idx 104 | while idx <= self.last_idx: 105 | (ipaddr, offset) = unpack("II", self.img[idx:idx+7]+"\0") 106 | idx += 7 107 | ipinfo = self.load_ipinfo(offset) 108 | self.indexes += [(ipaddr, ipinfo)] 109 | 110 | def save(self, newdb): 111 | countries = {} 112 | areas = {} 113 | new_img = "" 114 | # records 115 | for i in xrange(len(self.indexes)): 116 | ipinfo = self.indexes[i][1] 117 | idx = len(new_img) + 8 118 | ipinfo.offset = idx 119 | new_img += pack("I", ipinfo.iprange) 120 | if(countries.has_key(ipinfo.country)): 121 | offset = countries[ipinfo.country] 122 | new_img += chr(0x02) if len(ipinfo.area)>0 else chr(0x01) 123 | new_img += pack("I", offset)[0:3] 124 | else: 125 | countries[ipinfo.country] = idx +4 126 | new_img += ipinfo.country 127 | 128 | if len(ipinfo.area)>0: 129 | if(areas.has_key(ipinfo.area)): 130 | offset = areas[ipinfo.area] 131 | new_img += chr(0x02) 132 | new_img += pack("I", offset)[0:3] 133 | else: 134 | areas[ipinfo.area] = idx +4 135 | new_img += ipinfo.area 136 | 137 | # indexes 138 | first_idx = len(new_img) + 8 139 | for i in xrange(len(self.indexes)): 140 | new_img += pack("II", self.indexes[i][0], self.indexes[i][1].offset)[0:7] 141 | # header 142 | last_idx = first_idx + 7 * len(self.indexes) 143 | new_img = pack('II', first_idx, last_idx) + new_img; 144 | f = file(newdb, 'w') 145 | f.write(new_img) 146 | f.close() 147 | 148 | 149 | if __name__ == '__main__': 150 | wry = WryDat() 151 | wry.load("qqwry.dat.gbk") 152 | wry.save("qqwry.dat") --------------------------------------------------------------------------------