Skip to content

Commit 9336f8a

Browse files
author
Aaron Meihm
authored
Merge pull request #294 from ameihm0912/auth_ip_geo
initial auth_ip_geo analysis sandbox with cidr module
2 parents 0892c44 + b175347 commit 9336f8a

File tree

18 files changed

+757
-3
lines changed

18 files changed

+757
-3
lines changed

cmake/sandbox_ep_test.cmake

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ COMMAND ${CMAKE_COMMAND} -E copy_directory
1616
${CMAKE_CURRENT_SOURCE_DIR}/tests
1717
${CMAKE_CURRENT_BINARY_DIR})
1818

19+
if(COPY_TEST_MAXMINDDB)
20+
add_custom_target(${MODULE_NAME}_copy_test_maxminddb_city ALL COMMAND ${CMAKE_COMMAND} -E copy
21+
${CMAKE_SOURCE_DIR}/maxminddb/tests/GeoIP2-City-Test.mmdb
22+
${CMAKE_CURRENT_BINARY_DIR}/GeoIP2-City-Test.mmdb)
23+
add_custom_target(${MODULE_NAME}_copy_test_maxminddb_isp ALL COMMAND ${CMAKE_COMMAND} -E copy
24+
${CMAKE_SOURCE_DIR}/maxminddb/tests/GeoIP2-ISP-Test.mmdb
25+
${CMAKE_CURRENT_BINARY_DIR}/GeoIP2-ISP-Test.mmdb)
26+
endif()
27+
1928
include_directories(${CMAKE_BINARY_DIR})
2029
if(LUA51) # build against installed lua 5.1
2130
find_program(LUA NAMES lua lua.bat)

cmake/sandbox_module.cmake

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ add_custom_target(${MODULE_NAME}_copy_tests ALL COMMAND ${CMAKE_COMMAND} -E copy
5151
${CMAKE_CURRENT_SOURCE_DIR}/tests
5252
${CMAKE_CURRENT_BINARY_DIR})
5353

54+
if(COPY_TEST_MAXMINDDB)
55+
add_custom_target(${MODULE_NAME}_copy_test_maxminddb ALL COMMAND ${CMAKE_COMMAND} -E copy
56+
${CMAKE_SOURCE_DIR}/maxminddb/tests/GeoIP2-City-Test.mmdb
57+
${CMAKE_CURRENT_BINARY_DIR}/GeoIP2-City-Test.mmdb)
58+
add_custom_target(${MODULE_NAME}_copy_test_maxminddb_isp ALL COMMAND ${CMAKE_COMMAND} -E copy
59+
${CMAKE_SOURCE_DIR}/maxminddb/tests/GeoIP2-ISP-Test.mmdb
60+
${CMAKE_CURRENT_BINARY_DIR}/GeoIP2-ISP-Test.mmdb)
61+
endif()
62+
5463
include_directories(${CMAKE_BINARY_DIR})
5564
if(LUA51) # build against the installed Lua 5.1
5665
set(CPACK_PACKAGE_NAME "lua51-${PROJECT_NAME}")

lpeg/CMakeLists.txt.lpeg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
6-
project(lpeg VERSION 1.0.10 LANGUAGES C)
6+
project(lpeg VERSION 1.0.11 LANGUAGES C)
77

88
set(CPACK_PACKAGE_NAME luasandbox-${PROJECT_NAME})
99
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Lua LPeg Module (Parsing Expression Grammars)")

lpeg/modules/lpeg/ip_address.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
* `host_field` - returns the host as a Heka message field table `{value="127.0.0.1", representation="ipv4"}`
1515
* 'v4_field' - converts a version 4 ip address into a Heka message field
1616
* `v6_field` - converts a version 6 ip address into a Heka message field
17+
* 'v4_octets' - converts a version 4 ip address into an array of octets
1718
--]]
1819

1920
-- Imports
2021
local string = require "string"
2122
local l = require "lpeg"
23+
local tonumber = tonumber
2224
l.locale(l)
2325

2426
local M = {}
@@ -31,6 +33,8 @@ local d8 = "1" * l.digit * l.digit
3133
+ l.digit
3234
v4 = d8 * "." * d8 * "." * d8 * "." * d8
3335

36+
local octet = d8 / tonumber
37+
v4_octets = l.Ct(octet * "." * octet * "." * octet * "." * octet)
3438

3539
local h16 = l.xdigit * l.xdigit^-3
3640
local hg = h16 * ":"

moz_security/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
cmake_minimum_required(VERSION 3.0)
6-
project(moz-security VERSION 0.0.11 LANGUAGES C)
6+
project(moz-security VERSION 0.0.12 LANGUAGES C)
77
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mozilla Infrastructure Security Analysis")
88
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${PACKAGE_PREFIX}-streaming-algorithms (>= 0.0.2)")
99
string(REGEX REPLACE "[()]" "" CPACK_RPM_PACKAGE_REQUIRES ${CPACK_DEBIAN_PACKAGE_DEPENDS})
10+
set(COPY_TEST_MAXMINDDB TRUE)
1011
include(sandbox_module)
1112

1213
set(integration_tests
1314
analysis_hh
1415
analysis_sshd_login_monitor
16+
analysis_auth_ip_geo
1517
)
1618

1719
foreach(test IN LISTS integration_tests)

moz_security/modules/iputils.lua

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
--[[
2+
# IP / CIDR Utility Module
3+
4+
iputils can be used for verifying if an IP address is part of a specific set
5+
of CIDR / subnets.
6+
7+
This module is based on lua-resty-iputils, which can be found at
8+
https://github.com/hamishforbes/lua-resty-iputils/.
9+
10+
## Functions
11+
12+
### parse_cidr
13+
14+
Parse an array of CIDR subnet specifications where each entry is a string.
15+
Returns a list of the subnets in binary form for later use in ip_in_cidrs.
16+
17+
If a subnet mask is not specified with a subnet entry, it will default to 32.
18+
19+
```lua
20+
local ipu = require("iputils")
21+
22+
local subnets = ipu.parse_cidrs({ "10.0.0.0/24", "192.168.1.0/24" })
23+
```
24+
25+
*Arguments*
26+
- cidrs (table) - Array of subnets to parse, each in string format
27+
28+
*Return*
29+
- bincidrs (table) - Parsed subnets in binary format
30+
31+
### ip_in_cidrs
32+
33+
Returns true if an IP address is in a list of binary CIDR representations
34+
as returned by parse_cidrs. Returns false if not present, or nil if an
35+
error occurs.
36+
37+
```lua
38+
local ipu = require("iputils")
39+
40+
local subnets = ipu.parse_cidrs({ "10.0.0.0/24", "192.168.1.0/24" })
41+
inlist = ipu.ip_in_cidrs("10.0.0.1", subnets)
42+
```
43+
44+
*Arguments*
45+
- ip (string) - IP address to verify
46+
- bincidrs (table) - Parsed subnets returned from parse_cidrs
47+
48+
*Returns*
49+
- flag (boolean) - True if in subnets, false if not, nil if error
50+
51+
--]]
52+
53+
local ipairs = ipairs
54+
local tonumber = tonumber
55+
local tostring = tostring
56+
local type = type
57+
58+
local ipa = require("lpeg.ip_address")
59+
local bit = require("bit")
60+
local string = require("string")
61+
62+
local M = {}
63+
setfenv(1, M)
64+
65+
66+
-- Precompute binary subnet masks
67+
local bin_masks = {}
68+
for i=0,32 do
69+
bin_masks[tostring(i)] = bit.lshift((2^i)-1, 32-i)
70+
end
71+
72+
73+
-- Precompute inverted binary subnet masks
74+
local bin_inverted_masks = {}
75+
for i=0,32 do
76+
local i = tostring(i)
77+
bin_inverted_masks[i] = bit.bxor(bin_masks[i], bin_masks["32"])
78+
end
79+
80+
81+
local function split_octets(input)
82+
return ipa.v4_octets:match(input)
83+
end
84+
85+
86+
local function unsign(bin)
87+
if bin < 0 then
88+
return 4294967296 + bin
89+
end
90+
return bin
91+
end
92+
93+
94+
local function ip2bin(ip)
95+
if type(ip) ~= "string" then
96+
return nil
97+
end
98+
99+
local octets = split_octets(ip)
100+
if not octets or #octets ~= 4 then
101+
return nil
102+
end
103+
104+
-- Return the binary representation of an IP and a table of binary octets
105+
local bin_ip = 0
106+
107+
for i,octet in ipairs(octets) do
108+
bin_ip = bit.bor(bit.lshift(octet, 8*(4-i) ), bin_ip)
109+
end
110+
111+
return unsign(bin_ip), octets
112+
end
113+
114+
115+
local function split_cidr(input)
116+
local pos = string.find(input, "/", 0, true)
117+
if not pos then
118+
return { input }
119+
end
120+
return { string.sub(input, 1, pos-1), string.sub(input, pos+1, -1) }
121+
end
122+
123+
124+
local function parse_cidr(cidr)
125+
local mask_split = split_cidr(cidr, '/')
126+
local net = mask_split[1]
127+
local mask = mask_split[2] or "32"
128+
local mask_num = tonumber(mask)
129+
130+
if not mask_num or (mask_num > 32 or mask_num < 0) then
131+
return nil
132+
end
133+
134+
local bin_net = ip2bin(net) -- Convert IP to binary
135+
if not bin_net then
136+
return nil
137+
end
138+
local bin_mask = bin_masks[mask] -- Get masks
139+
local bin_inv_mask = bin_inverted_masks[mask]
140+
141+
local lower = bit.band(bin_net, bin_mask) -- Network address
142+
local upper = bit.bor(lower, bin_inv_mask) -- Broadcast address
143+
return unsign(lower), unsign(upper)
144+
end
145+
146+
147+
function parse_cidrs(cidrs)
148+
local out = {}
149+
local i = 1
150+
for _,cidr in ipairs(cidrs) do
151+
local lower, upper = parse_cidr(cidr)
152+
if not lower or not upper then
153+
return nil
154+
else
155+
out[i] = { lower, upper }
156+
i = i + 1
157+
end
158+
end
159+
return out
160+
end
161+
162+
163+
function ip_in_cidrs(ip, cidrs)
164+
local bin_ip, bin_octets = ip2bin(ip)
165+
if not bin_ip then
166+
return nil, bin_octets
167+
end
168+
169+
for _,cidr in ipairs(cidrs) do
170+
if bin_ip >= cidr[1] and bin_ip <= cidr[2] then
171+
return true
172+
end
173+
end
174+
return false
175+
end
176+
177+
178+
return M

0 commit comments

Comments
 (0)