-
-
Notifications
You must be signed in to change notification settings - Fork 9
Add. safe mode to mmdb object
#11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
dbc9df5
610fc82
f22d865
c69fa0b
6ce8387
900d78d
76b1ba9
3b3524a
d14ce3c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,11 +14,23 @@ local geodb_mt = { | |
| local data_types = {} | ||
| local getters = {} | ||
|
|
||
| local function open_db(filename) | ||
| local fd = assert(io.open(filename, "rb")) | ||
| local function fail(safe, ...) | ||
| if safe then return nil, ... end | ||
| error(..., 2) | ||
| end | ||
|
|
||
| local function open_db(safe, filename) | ||
| local fd, err = io.open(filename, "rb") | ||
| if not fd then | ||
| return fail(safe, err) | ||
| end | ||
|
|
||
| local contents, err = fd:read("*a") | ||
| fd:close() | ||
| assert(contents, err) | ||
|
|
||
| if not contents then | ||
| return fail(safe, err) | ||
| end | ||
|
|
||
| local start_metadata do | ||
| -- Find data section seperator; at most it's 128kb from the end | ||
|
|
@@ -29,11 +41,12 @@ local function open_db(filename) | |
| start_metadata = e + 1 | ||
| end | ||
| if start_metadata == nil then | ||
| error("Invalid MaxMind Database") | ||
| return fail(safe, "Invalid MaxMind Database") | ||
| end | ||
| end | ||
|
|
||
| local self = setmetatable({ | ||
| safe = not not safe; | ||
| contents = contents; | ||
| start_metadata = start_metadata; | ||
| data = nil; | ||
|
|
@@ -47,7 +60,7 @@ local function open_db(filename) | |
|
|
||
| local getter = getters[data.record_size] | ||
| if getter == nil then | ||
| error("Unsupported record size: " .. data.record_size) | ||
| return fail(self.safe, "Unsupported record size: " .. tostring(data.record_size)) | ||
| end | ||
| self.left, self.right, self.record_length = getter.left, getter.right, getter.record_length | ||
|
|
||
|
|
@@ -320,10 +333,10 @@ getters[32] = { | |
| function geodb_methods:search(bits, node) | ||
| node = node or 0 | ||
| local seen = { [node] = true } | ||
| for _, direction in ipairs(bits) do | ||
| for i = 1, #bits do | ||
|
||
| local offset = node * self.record_length + 1 | ||
| local record_value | ||
| if direction then | ||
| if bits[i] then | ||
| record_value = self:right(offset) | ||
| else | ||
| record_value = self:left(offset) | ||
|
|
@@ -368,12 +381,17 @@ end | |
|
|
||
| local function ipv4_to_bit_array(str) | ||
| local o1, o2, o3, o4 = str:match("(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)%.(%d%d?%d?)") | ||
| assert(o1, "invalid IPv4 address") | ||
| if not o1 then | ||
| return nil, "invalid IPv4 address" | ||
| end | ||
| o1 = tonumber(o1, 10) | ||
| o2 = tonumber(o2, 10) | ||
| o3 = tonumber(o3, 10) | ||
| o4 = tonumber(o4, 10) | ||
| assert(o1 <= 255 and o2 <= 255 and o3 <= 255 and o4 <= 255, "invalid IPv4 address") | ||
| if not (o1 <= 255 and o2 <= 255 and o3 <= 255 and o4 <= 255) then | ||
| return nil, "invalid IPv4 address" | ||
| end | ||
|
|
||
| return { | ||
| math.floor(o1 / 128) % 2 == 1; | ||
| math.floor(o1 / 64) % 2 == 1; | ||
|
|
@@ -411,7 +429,11 @@ local function ipv4_to_bit_array(str) | |
| end | ||
|
|
||
| function geodb_methods:search_ipv4(str) | ||
| return select(2, self:search(ipv4_to_bit_array(str), self.ipv4_start)) | ||
| local bits, err = ipv4_to_bit_array(str) | ||
| if not bits then | ||
| return fail(self.safe, err) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to call |
||
| end | ||
| return select(2, self:search(bits, self.ipv4_start)) | ||
| end | ||
|
|
||
| local function ipv6_split(str) | ||
|
|
@@ -420,7 +442,7 @@ local function ipv6_split(str) | |
| for u16 in str:gmatch("(%x%x?%x?%x?):?") do | ||
| n = n + 1 | ||
| u16 = tonumber(u16, 16) | ||
| assert(u16, "invalid IPv6 address") | ||
| if not u16 then return nil, "invalid IPv6 address" end | ||
|
||
| components[n] = u16 | ||
| end | ||
| return components, n | ||
|
|
@@ -429,17 +451,21 @@ end | |
| local function ipv6_to_bit_array(str) | ||
| local a, b = str:match("^([%x:]-)::([%x:]*)$") | ||
| local components, n = ipv6_split(a or str) | ||
| if not components then return nil, n end | ||
| if a ~= nil then | ||
| local end_components, m = ipv6_split(b) | ||
| assert(m+n <= 7, "invalid IPv6 address") | ||
| if not end_components then return nil, m end | ||
| if m+n > 7 then return nil, "invalid IPv6 address" end | ||
| for i = n+1, 8-m do | ||
| components[i] = 0 | ||
| end | ||
| for i = 8-m+1, 8 do | ||
| components[i] = end_components[i-8+m] | ||
| end | ||
| else | ||
| assert(n == 8, "invalid IPv6 address") | ||
| if n ~= 8 then | ||
| return nil, "invalid IPv6 address" | ||
| end | ||
| end | ||
| -- Now components is an array of 16bit components | ||
| local bits = {} | ||
|
|
@@ -453,9 +479,14 @@ local function ipv6_to_bit_array(str) | |
| end | ||
|
|
||
| function geodb_methods:search_ipv6(str) | ||
| return select(2, self:search(ipv6_to_bit_array(str))) | ||
| local bits, err = ipv6_to_bit_array(str) | ||
| if not bits then | ||
| return fail(self.safe, err) | ||
| end | ||
| return select(2, self:search(bits)) | ||
| end | ||
|
|
||
| return { | ||
| open = open_db; | ||
| open = function(...) return open_db(false, ...) end; | ||
|
||
| open_safe = function(...) return open_db(true, ...) end; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returnon own line