From 52adf874897744986d20f39ba24a6e545c7e0b5c Mon Sep 17 00:00:00 2001 From: evazion Date: Mon, 1 Mar 2021 18:09:15 -0600 Subject: [PATCH] Fix #4666: Broken network link for some IPs. --- app/controllers/ip_addresses_controller.rb | 2 +- app/logical/danbooru/ip_address.rb | 14 ++ app/logical/ip_lookup.rb | 2 + app/views/ip_addresses/_info.html.erb | 128 ++++++++++-------- .../ip_addresses_controller_test.rb | 5 + 5 files changed, 94 insertions(+), 57 deletions(-) diff --git a/app/controllers/ip_addresses_controller.rb b/app/controllers/ip_addresses_controller.rb index e0ab7ffd4..3887c20fd 100644 --- a/app/controllers/ip_addresses_controller.rb +++ b/app/controllers/ip_addresses_controller.rb @@ -17,7 +17,7 @@ class IpAddressesController < ApplicationController def show @ip_address = authorize IpAddress.new(ip_addr: params[:id]) - @ip_info = @ip_address.lookup.response + @ip_info = @ip_address.ip_addr.ip_info respond_with(@ip_info) end end diff --git a/app/logical/danbooru/ip_address.rb b/app/logical/danbooru/ip_address.rb index c1d25df37..a5a359053 100644 --- a/app/logical/danbooru/ip_address.rb +++ b/app/logical/danbooru/ip_address.rb @@ -24,6 +24,20 @@ module Danbooru end end + # If we're being reverse proxied behind Cloudflare, then Tor connections + # will appear to originate from 2405:8100:8000::/48. + # https://blog.cloudflare.com/cloudflare-onion-service/ + def is_tor? + Danbooru::IpAddress.new("2405:8100:8000::/48").include?(ip_address) + end + + def include?(other) + other = Danbooru::IpAddress.new(other) + return false if (ipv4? && other.ipv6?) || (ipv6? && other.ipv4?) + + ip_address.include?(other.ip_address) + end + # "1.2.3.4/24" if the address is a subnet, "1.2.3.4" otherwise. def to_s ip_address.size > 1 ? ip_address.to_string : ip_address.to_s diff --git a/app/logical/ip_lookup.rb b/app/logical/ip_lookup.rb index 8c1eb7430..54aa98c1b 100644 --- a/app/logical/ip_lookup.rb +++ b/app/logical/ip_lookup.rb @@ -17,6 +17,7 @@ class IpLookup def ip_info return {} if ip_addr.is_local? + return {} if ip_addr.is_tor? return {} if response.blank? { @@ -45,6 +46,7 @@ class IpLookup end def is_proxy? + return true if ip_addr.is_tor? response[:security].present? && response[:security].values.any? end diff --git a/app/views/ip_addresses/_info.html.erb b/app/views/ip_addresses/_info.html.erb index a8f13f1c9..646dba354 100644 --- a/app/views/ip_addresses/_info.html.erb +++ b/app/views/ip_addresses/_info.html.erb @@ -1,70 +1,84 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - <% if ip_info.dig(:carrier, :name).present? %> + <% if ip_info[:country].present? %> - - + + <% end %> + + <% if ip_info[:network].present? %> + + + + + <% end %> + - - + + + + <% if ip_address.ip_addr.is_tor? %> + + + + + <% end %> + + + + + + + <% if ip_info[:asn].present? %> + + + + + <% end %> + + <% if ip_info[:organization].present? %> + + + + + <% end %> + + <% if ip_info[:carrier].present? %> + + + + + <% end %> + @@ -72,6 +86,8 @@
- <%= embedded_map(ip_info.dig(:location, :latitude), ip_info.dig(:location, :longitude), 300, 200) %> + <% if ip_info[:latitude].present? && ip_info[:longitude].present? %> + <%= embedded_map(ip_info[:latitude], ip_info[:longitude], 300, 200) %> + <% end %>
diff --git a/test/functional/ip_addresses_controller_test.rb b/test/functional/ip_addresses_controller_test.rb index ad98fd5d3..3b57817e8 100644 --- a/test/functional/ip_addresses_controller_test.rb +++ b/test/functional/ip_addresses_controller_test.rb @@ -51,6 +51,11 @@ class IpAddressesControllerTest < ActionDispatch::IntegrationTest get_auth ip_address_path("1.2.3.4"), @user assert_response 403 end + + should "work for a Tor address" do + get_auth ip_address_path("2405:8100:8000::1"), @mod + assert_response :success + end end end end
Location - <% if ip_info.dig(:location, :city) %> - <%= ip_info.dig(:location, :city) %>, - <% end %> - <% if ip_info.dig(:location, :region, :name).present? %> - <%= ip_info.dig(:location, :region, :name) %>, - <% end %> - <%= ip_info.dig(:location, :country, :name) %> -
Network - <%= link_to ip_info.dig(:connection, :route), ip_addresses_path(search: { ip_addr: ip_info.dig(:connection, :route) }) %> - (<%= link_to "info", "https://ipinfo.io/AS#{ip_info.dig(:connection, :asn)}/#{ip_info.dig(:connection, :route)}" %>) -
Proxy<%= ip_address.lookup.is_proxy? ? "yes" : "no" %>
IP Banned - <% if IpBan.ip_matches(ip_address.ip_addr.to_s).exists? %> - yes (<%= link_to "info", ip_bans_path(search: { ip_addr: ip_address.to_s }) %>) - <% else %> - no - <% end %> -
Type<%= ip_info.dig(:connection, :type) %>
ASN - <%= link_to "AS#{ip_info.dig(:connection, :asn)}", "https://ipinfo.io/AS#{ip_info.dig(:connection, :asn)}" %> -
Organization - <%= ip_info.dig(:connection, :organization) %> -
Mobile Carrier<%= ip_info.dig(:carrier, :name) %>Location + <% if ip_info[:city] %> + <%= ip_info[:city] %>, + <% end %> + <% if ip_info[:region].present? %> + <%= ip_info[:region] %>, + <% end %> + <%= ip_info[:country] %> +
Network + <%= link_to ip_info[:network], ip_addresses_path(search: { ip_addr: ip_info[:network] }) %> + (<%= link_to "info", "https://ipinfo.io/AS#{ip_info[:asn]}/#{ip_info[:network]}" %>) +
Website<%= external_link_to("http://#{ip_info.dig(:connection, :domain)}") %>Proxy?<%= ip_address.ip_addr.is_proxy? ? "Yes" : "No" %>
Tor?Yes
IP Banned? + <% if IpBan.ip_matches(ip_address.ip_addr.to_s).exists? %> + Yes (<%= link_to "info", ip_bans_path(search: { ip_addr: ip_address.ip_addr.to_s }) %>) + <% else %> + No + <% end %> +
ASN + <%= link_to "AS#{ip_info[:asn]}", "https://ipinfo.io/AS#{ip_info[:asn]}" %> +
Organization + <%= ip_info[:organization] %> +
Mobile Carrier<%= ip_info[:carrier] %>
Details
-
<%= JSON.pretty_generate(ip_info) %>
+
<%= JSON.pretty_generate(ip_address.lookup.response) %>