我想在弹性搜索中存储IPv4和IPv6子网(CIDR格式),并在其中搜索包含IP地址(/ 32和/ 128)。
可悲的是,elasticsearch(最多1.5.1)只有原始类型和IPv4类型,只能用于存储/ 32个地址,而不能用于子网。
答案 0 :(得分:1)
Elasticsearch提供(签名)整数类型,它匹配IPv4和long,可用于存储,索引和搜索IPv6地址,分为两个64位整数。
用于创建elasticsearch索引,映射,存储和搜索的示例python代码如下:
import ipaddr
from elasticsearch import Elasticsearch
es = Elasticsearch(['http://localhost:9200'])
pm = es.indices.put_mapping
es.indices.delete(index='ips', ignore=[400, 404])
es.indices.create(index='ips', ignore=400)
pm(index='ips', doc_type='ip',
body={
"ip":{
"properties":{
"ipv4":{"type":"nested",
"properties":{
"first":{"type":"integer" },
"last":{"type":"integer" }
}
},
"ipv6":{"type":"nested",
"properties":{
"lofirst":{"type":"long" },
"lolast":{"type":"long" },
"hifirst":{"type":"long" },
"hilast":{"type":"long" }
}
}
}
}
}
)
def cidrtoes(ip):
'''
Convert IP address or network to ES-stored format
:param ip: IPv4 or IPv6 address or network in CIDR notation
:returns: dictionary which can be added to ES document
'''
ipnet = ipaddr.IPNetwork(ip)
if ipnet.version == 4:
s = {'first':int(ipnet) - 2 ** 31,
'last':int(ipnet[-1]) - 2 ** 31}
elif ipnet.version == 6:
s = {'lofirst':(int(ipnet) & 2 ** 64 - 1) - 2 ** 63,
'lolast':(int(ipnet[-1]) & 2 ** 64 - 1) - 2 ** 63,
'hifirst':(int(ipnet) >> 64) - 2 ** 63,
'hilast':(int(ipnet[-1]) >> 64) - 2 ** 63}
return s
def ip4toes(address):
'''
Convert IPv4 address to ES-stored format
:param address: IPv4 address
:returns: IPv4 converted to signed integer
'''
ip = ipaddr.IPAddress(address)
return int(ip) - 2 ** 31
def ip6toes(address):
'''
Convert IPv6 address to ES-stored format
:param address: IPv6 address
:returns: IPv6 address converted to low and high 64 bit signed integers
'''
ip = ipaddr.IPAddress(address)
return [(int(ip) & 2 ** 64 - 1) - 2 ** 63, (int(ip) >> 64) - 2 ** 63 ]
doc = {'ipv4':[cidrtoes('0.0.0.0/24'), cidrtoes('0.0.1.0/24'), cidrtoes('255.255.255.255')],
'ipv6':[cidrtoes('::/64'), cidrtoes('1::/64'), cidrtoes('2::3')],
}
es.index(index="ips", doc_type="ip", body=doc)
es.indices.flush(index="ips")
# IPv4 query
ip = '0.0.1.0'
searchip = ip4toes(ip)
s = es.search(index='ips', doc_type='ip', body=
{"query":{
"filtered":{
"filter":{'nested':{
'path':'ipv4',
'filter':{
'and':[
{"range": {"first": {'lte':searchip}}},
{"range": {"last": {'gte':searchip}}},
]
}
}
}
}
}
}
)
print "IPv4 result", s
# IPv6 query
ip = '2::3'
lo = ip6toes(ip)[0]
hi = ip6toes(ip)[1]
s = es.search(index='ips', doc_type='ip', body=
{"query":{
"filtered":{
"filter":{'nested':{
'path':'ipv6',
'filter':{
'and':[
{"range": {"lofirst": {'lte':lo}}},
{"range": {"lolast": {'gte':lo}}},
{"range": {"hifirst": {'lte':hi}}},
{"range": {"hilast": {'gte':hi}}},
]
}
}
}
}
}
}
)
print "IPv6 result", s