require 'rpatricia' module Paraxial module Checker @allows = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) } @bans = { 'v4' => Patricia.new, 'v6' => Patricia.new(:AF_INET6) } @thread = Thread.new do loop do get_abr sleep(10) end end def self.get_abr uri = URI.parse(Paraxial::Helpers.get_paraxial_url + '/api/abr') headers = { 'Content-Type': 'application/json' } body = { api_key: ENV['PARAXIAL_API_KEY'] } r = Net::HTTP.post(uri, body.to_json, headers) if r.code == '200' put_abr(JSON.parse(r.body)) else 'ab_failed' end end def self.put_abr(abr) # Expected input: a hash # {"allows"=>[{"address"=>[96, 56, 162, 210], "netmask"=>32}], # "bans"=> # [{"address"=>[8193, 3512, 34211, 0, 0, 35374, 880, 29492], "netmask"=>128}, # {"address"=>[111, 56, 162, 210], "netmask"=>32}], # "rules"=>[]} ipv4_a = [] ipv4_b = [] ipv6_a = [] ipv6_b = [] abr.each do |key, value| next if key == 'rules' # skip rules for now value.each do |ip| address = ip['address'] if address.length == 4 if key == 'allows' ipv4_a << address.join('.') elsif key == 'bans' ipv4_b << address.join('.') end elsif key == 'allows' ipv6_a << address.map { |n| n.to_s(16).rjust(4, '0') }.join(':') elsif key == 'bans' ipv6_b << address.map { |n| n.to_s(16).rjust(4, '0') }.join(':') end end end ab = { 'allows' => { 'v4' => ipv4_a, 'v6' => ipv6_a }, 'bans' => { 'v4' => ipv4_b, 'v6' => ipv6_b } } Paraxial::Checker.put(ab) end def self.put(allow_ban) allows = allow_ban['allows'] bans = allow_ban['bans'] @allows = { 'v4' => create_patricia(allows['v4'], 'v4'), 'v6' => create_patricia(allows['v6'], 'v6') } @bans = { 'v4' => create_patricia(bans['v4'], 'v4'), 'v6' => create_patricia(bans['v6'], 'v6') } :ok end def self.create_patricia(list, type) if type == 'v4' p = Patricia.new list.each do |ip| p.add(ip) end p elsif type == 'v6' p = Patricia.new(:AF_INET6) list.each do |ip| p.add(ip) end p else raise 'Wrong type in Paraxial::Checker.create_patricia' end end def self.ban_ip(ip) if ip.include?('.') # IPv4 current_t = @bans['v4'] current_t.add(ip) @bans['v4'] = current_t else # IPv6 current_t = @bans['v6'] current_t.add(ip) @bans['v6'] = current_t end uri = URI.parse(Paraxial::Helpers.get_ban_url) headers = { 'Content-Type': 'application/json' } body = { api_key: ENV['PARAXIAL_API_KEY'], ip_address: ip } r = Net::HTTP.post(uri, body.to_json, headers) if r.code == '200' :ok else :error end end def self.allow_ip?(ip) if ip.include?('.') if !@allows['v4'].search_best(ip).nil? # v4 on allow list true elsif !@bans['v4'].search_best(ip).nil? # v4 on ban list false else # v4 on no list true end elsif !@allows['v6'].search_best(ip).nil? # v6 on allow list true elsif !@bans['v6'].search_best(ip).nil? # v6 on ban list false else # v6 on no list true end end end end