My goal is to store in Redis:
- Plain IP addresses like
228.228.228.228
- IP networks like
228.228.228.0/24
in order to check in request/response cycle whether or not
current IP xxx.yyy.xxx.vvv
is inside( contained by):
- Plain ips
or
- Ip network ( for example
228.228.228.228
inside228.228.228.0/24
)
Overall amount of ips and networks – few 1000 items.
Question is – what is the best way (best structure) to store both plain ips and networks in Redis and make aforementioned check without fetching data from Redis?
Thanks.
P.S. Current IP is already known.
UPDATE
Ok, lets simplify it a bit with example.
I have 2 ips and 2 networks in where I want to check if certain ip is contained.
# 2 plain ip
202.76.250.29
37.252.145.1
# 2 networks
16.223.132.0/24
9.76.202.0/24
There are 2 possible ways where exact ip might be contained:
1)Just in plain ips. For example 202.76.250.29
contained in the structure above and 215.08.11.23
is not contained simply by definition.
2)Ip might be contained inside network. For example 9.76.202.100
contained inside networks 9.76.202.0/24
but not contained inside list of plain ips as there are no any exact ip = 9.76.202.100.
Little bit of of explanation about ip networks. Very simplified.
Ip network represents range of ips. For example ipv4 network "192.4.2.0/24"
represents 256 ip addresses:
IPv4Address('192.4.2.1'), IPv4Address('192.4.2.2'),
…
…
…
IPv4Address('192.4.2.253'), IPv4Address('192.4.2.254')
In another words ip network is a range of ip addresses
from '192.4.2.1' up to '192.4.2.254'
In our example 9.76.202.100
contained inside networks 9.76.202.0/24
as one of this addresses inside the range.
My idea is like this:
Any ip address can be represented as integer. One of our ip addresses
202.76.250.29
converted to integer is 3394042397
.
As ip network is a range of ips, so that it is possible to convert it in a range of integers by converting first and last ip in range in integers.
For example one of our networks 16.223.132.0/24
represents range between IPv4Address('16.223.132.1')
and IPv4Address('16.223.132.254')
. Or integers range from 283083777
up to 283083781
with step 1
.
Individual ip can be represented as range between it’s integer and it’s integer + 1 (lower bound included, upper bound excluded).
Obviously search in plain ips can be done by putting them to SET
and then using SISMEMBER
. But what about searching inside networks. Can we do some trick with ranges maybe?
2
Answers
"Best" is subjective(in memory, in speed etc) but you may use two sets/hash to store them. Since they are unique both
hashes
andsets
would be fine. If you prefer you can use a single set/hash to save both ip and network ip addresses but i would prefer separate since they are two different type of data sets(just like database tables).Then you can use either of those
SISMEMBER
with O(1) time complexityHEXISTS
with O(1) time complexity.It can be handled on application level with multiple commands or lua script(in a single transaction).
Depending on your choice add to your keys with
SADD
andHSET
(the field value would be 1).—
Edit: (hope i get it right)
For the range of network addresses create sets from the integers surrounding two dots such as 12.345.67.1-12.345.67.254 range will be represented as
12.345.67
and you will add this to the set. When you want to search for12.345.67.x
it will be parsed into12.345.67
in your application level and you will check withSISMEMBER
. Same can be done with hash withHEXISTS
.Since ip addresses contain four different numbers with three dots, you will discard last dot and last number and the rest will be representing(i assume) the network range.
For IPs you can use Set and query by certain IP within O(1) time.
For IP range, I think you can use List with Lua Script for query. List will have O(n) time for searching, but since you only have 1000 items, O(N) and O(1) will not have a huge difference for Redis in memory query.