For years I have been determined a users location with the help of Geocoder, looking up the IPv4 address. By firing
request.location, I determined the location, and if the country was multilingual, I looked up the browser language setting to set the appropriate language. When I feed an IPv6 address to my Rails app, the IP address returns :::1, which isn't very helpful.
Unfortunately, IPv6 poses a challenge when it comes to determining a visitors location. Is there any proven way of working with IPv6 on Ruby-on-Rails?
I have googled my way through the internet but didn't come across a specific solution.
You can do this with the ipaddr library. It supports ipv4 and ipv6:
$ require 'ipaddr'
$ ipaddr = IPAddr.new "3ffe:505:2::1"
$ p ipaddr
#=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
$ p ipaddr.to_s
#=> "3ffe:505:2::1"
If you want more advanced functionality, try the ipaddress gem which also supports ipv6.
You can use Geocoder.search() to search by an ipv6 address:
Geocoder.search(ipaddr)
Geocoder.search('2607:fea8:1360:f7d:dce7:b7f0:e0b6:1014')
Related
Using Delphi 7 with Indy10, I need to create an IPv6 to IPv4 proxy for a service that doesn't support IPv6. I can manage that fine. The only issue I'm facing is, if they enter a domain name rather than an IP address, how can I determine if the destination server is only accessible via IPv6 and not IPv4? If IPv4 is available, I would prefer to send the request directly rather than going through the proxy.
Is using TIdDNSResolver the only solution?
I found code for with 2 functions for using it, one returning an IPv4 and the other an IPv6 address. Presumably the IPv4 function will return nothing if there is only IPv6 available.
But the functions both require a DNS server to be specified. How am I to find one? Is there some way to use the default DNS server to find the IP addresses, perhaps using a Windows API and not Indy?
You actually have several questions in your question. I will answer this one: "How do I find a DNS server address?".
One answer is: call GetAdaptersAddresses in the IpHelper API. This call will return many addresses including the DNS address. In the documentation there is a C++ example you can translate to Delphi.
Another answer is to use command line IPCONFIG /ALL. In the output, you'll find the DNS address.
A third answer is to use a WMI query. See this question.
In Ruby on Rails, how can I get the IP Address of a client? I want that when a user visits a certain page, Rails gets their ip address and displays it on the screen.
In my controller I've tried:
request.remote_ip
but it is returning ::1 which to my knowledge is IPv6. I would like to get the IPv4 address of the client. How can I achieve this? I would only need to do this once per client since I'm only checking the ip address of the first device that they use to visit my page.
You can use either
request.ip that returns the ip, whether it is a local proxy ip
address (localhost address) or not.
request.remote_ip is smarter and gets the ip address of the client
outside of local proxies and this is the best that is an interpretation of all the available IP address information and it will make a best-guess.
(request.remote_ip)Determines originating IP address. REMOTE_ADDR is the standard but
will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
HTTP_X_FORWARDED_FOR are set by proxies so check for these if
REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma- delimited
list in the case of multiple chained proxies; the last address which
is not trusted is the originating IP.
Are you certain that ::1 is not sufficient? That is the local host; if you publish the site to anywhere requiring layer 3 transport it should render the appropriate IPv4 or IPv6 address respectively.
In short, if you disable your local IPv6 stack 127.0.0.1 would render.
My application logs the ip address of each user that logs in, but I've noticed that it's logging the IP address of our load balancer instead of the actual client ip. Researching the issue, I believe it's because our load balancers use publically routable ip addresses, and Rails is ignoring the X-Forwarded-For header assuming it's been spoofed. The solution appears to be to 'whitelist' the range of ip's used by our load balancers.
My question is, exactly how do I do that, for rails 4.1.x? Here's what I have now in config/environments/production.rb:
config.action_dispatch.custom_proxies = %r{
^100\.30 | # production environment load balancers
^200\.40 | # dev environment load balancers
}x
I tried to format it like the TRUSTED_PROXIES in remote_ip.rb, but maybe it should be a string or an array, or a differently formatted regex? Any help on the details are much appreciated. Bonus upvote if you can suggest an integration test that would catch this configuration breaking in a future version of rails. :-)
UPDATE
I've tried multiple ways to update this, and had slightly more success using config.action_dispatch.trusted_proxies. This keeps my load balancers from getting logged, but leaves all IP addresses logged as '127.0.0.1', whether they're internal or external. In logs/unicorn.log, the ip addresses are coming in as [external address, 10.* address, load balancer address], so I know the problem is at the rack or rails layer, not earlier in apache or nginx. I've also tried to replace the TRUSTED_PROXIES constant with a list that does NOT include the 10.* range (because internal users have that range), but to no apparent effect.
At this point, it looks like Rails 4.1.x is broken for any application that has real users coming from non-public IP addresses, or any application hosted in a network environment that has a load balancer with an external IP address.
As of Rails 4.2 you have to define the proxies in a different way:
config.action_dispatch.trusted_proxies = %w(100.30.0.0/16 200.40.0.0/16).
map { |proxy| IPAddr.new(proxy) }
See https://github.com/rails/rails/issues/5223#issuecomment-199082324
You can add another configutation option config.action_dispatch.ip_spoofing_check so Rails doesn't check for IP spoofing.
The option is described on the rails guide about configuration and on the ActionDispatch::RemoteIp module
i want to get real ip address from user client when visit my website using rails in development mode?
but when i typing request.remote_ip, i get ip address 127.0.0.1??
how to get real ip address???
and when i try curl -H"X-Forwarded-For: 8.8.8.8" http://httpbin.org/ip, i get my real ip address but when i try implements gem https://github.com/geokit/geokit-rails to get country based ip address... my ip it's not valid?
i try this :
IpGeocoder.geocode('my.real.ip.address')
and get error like this :
Geokit::Geocoders::GeocodeError: Geokit::Geocoders::GeocodeError
but if i try ip adrress from example :
IpGeocoder.geocode('12.215.42.19')
it's works
=> Provider: hostip
Street:
City: Aurora
State: TX
Zip:
Latitude: 33.0582
Longitude: -97.5159
Country: US
Success: true
whats wrong in my ip address? i get my real ip address from "curl -H"X-Forwarded-For: 8.8.8.8" http://httpbin.org/ip"
if i wrong plase tell me, thanks
Here's an idea which may help:
Localhost
When you load the Rails server in development, you're accessing your localhost. This means that any requests made to this server are going to be treated as local connections (127.0.0.1)
You have to remember Rails is a server-side technology, which means it can only process requests as received (it has no bearing on where those requests come from). You can see a glimpse of this with the ActiveDispatch::Request middleware:
local?()
True if the request came from localhost, 127.0.0.1.
This means if you send a request to your local Rails server, it'll just treat it as a local request (127.0.0.1)
GeoLocation IP
Your Geolocation worked for your WAN IP (your remote IP) manually
The reason is because the GeoLocation API / service which the gem uses will ping a third-party server, which will either look up the DNS or other geographic locations for that IP:
From GeoKit GitHub:
IP-based location lookup utilizing hostip.info. Provide an IP address,
and get city name and latitude/longitude in return
Like any API, the response will depend on the input. The problem is that because Rails is treating your requests as local (from 12.7.0.0.1), it will only send that IP, which has no bearing on GeoLocation (it's local to your system, not the world)
JS
To get around this, you'll have to find a way to find your system's WAN IP in development, which you may be able to do with JS:
How to get client's IP address using javascript only? (see Chad Grant's answer):
<script type="application/javascript">
function getip(json){
alert(json.ip); // alerts the ip address
}
</script>
<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"></script>
I've not tested this, but hopefully it will give you an ideas as to what might be going wrong
Try using ngrok to create a tunnel to your local server.
I want to get the real IP of my system so that I can further get the location(using geocoder gem). I am using devise gem's trackable module to get the IP of the user. When I try to geocode the IP, it fails because the last_signed_in_ip returned by devise is always 127.0.0.1. I double checked the location permissions in the browser so that doesnt seem to be an issue as it is allowed to track location there. What can be wrong?
Also, is there a better way to find out one's location (apart from tracking IP address and then geocoding it?). Can the user be asked again to allow location tracking from within the application in case he has not allowed it or isnt aware of such setting?
Appreciate all the help in advance.
Thanks
request.remote_ip will solve your problem...
it will never return you your own m/c address, instead If you need the remote address for (testing) your geocoding, I suggest adding 127.0.0.1 to your database table that matches IP addresses with locations
you can hardcode like this for testing purpose:
if request.remote_ip == '127.0.0.1'
# Hard coded remote address
'123.45.67.89'
else
request.remote_ip
end
If you want to return your external IP address programmatically then you need to access your app from that address.
When you visit your app at localhost, request.remote_ip will return 127.0.0.1 because that is your localhost IP address.
To get around this you can either forward your development port (normally 3000) from your router to your PC and then access your app by entering your external IP address into your browser instead of localhost (eg: 123.123.123.123:3000).
Alternatively add your external IP address to your hosts file pointing to localhost (ie: localhost 123.123.123.123) and then browse to your app via your external IP address as above.