Given a set of rules (must be followed in order), create a function access_ok that determines if the IP is allowed or not
[
{"ALLOW": "192.168.100.0/24"},
{"ALLOW": "192.168.0.5/30"},
{"DENY": "8.8.8.8/0"},
{"ALLOW": "1.2.3.4"},
]Example
access_ok("192.168.100.1") -> True because of the first rule
access_ok("8.8.8.8") -> False because of fourth ruleRules can either be IP or CIDR notation.
My pseudocode approach since I ran out of time to write it all out is below. The idea behind this solution is just converting the octects from the ip string into a byte array or integer for easy comparison. There is an edge case where your prefix is /0 but I haven't figured or tested a solution yet. I was thinking to set the mask to be 0x0000 in that case.
type IPRanges struct {
begin uint32
end uint32
verb string
}
ranges := make([]IPRanges, 1)
/*
for rule in rules:
expandCIDR(rule)
func expandCIDR(rule):
range := IPRanges{}
convert ip into netmask
verb := rule[0]
ip := rule[1] // X.X.X.X or X.X.X.X/X
if ip is not CIDR
parsedIP := ipToByteArray(ip)
range.begin = parsedIP
range.end = parsedIP
range.verb = verb
ranges = append(ranges, range)
return
calculate begin and end of range
192 168 100 0 / 24
1100 0000 | 1010 1000 | 0000 0000 | 0001 0000 | 0000 0000
0xFFFF mask left shifted by 32 - 24
1111 1111 | 1111 1111 | 1111 1111 | 1111 1111 | 0000 0000
begin = ip AND mask
1100 0000 | 1010 1000 | 0000 0000 | 0001 0000 | 0000 0000 => 192.168.100.0
end = ip OR not mask
1100 0000 | 1010 1000 | 0000 0000 | 0001 0000 | 1111 1111 => 192.168.100.255
range.verb = verb
ranges = append(ranges, range)
func access_ok(ip):
parsedIP := ipToByteArray(ip)
for ipRange in ranges:
if bytes.Compare(ipRange.begin, parsedIP) >= 0 && bytes.Compare(ipRange.end, parsedIP) <= 0
return ipRange.verb
return False
func ipToByteArray(ip):
sub, _ := strings.Split(ip, ".")
var parsedIP []byte
for i, s := sub {
octet, _ := strconv.Atoi(s)
parsedIP = append(parsedIP, byte(octet))
}
return parsedIP
*/