如何在elasticsearch中存储和搜索多个IPv4和IPv6子网?

时间:2015-04-21 10:48:49

标签: python elasticsearch

我想在弹性搜索中存储IPv4和IPv6子网(CIDR格式),并在其中搜索包含IP地址(/ 32和/ 128)。

可悲的是,elasticsearch(最多1.5.1)只有原始类型和IPv4类型,只能用于存储/ 32个地址,而不能用于子网。

1 个答案:

答案 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