Get IPv4 Address from python, even with vpn on - python

So I'm using socket to connect clients to the server. For that, I need the computer's ip. Currently, the best way I found is this:
socket.gethostbyname(socket.gethostname())
I then use requests to tell my clients about my ip, and they connect. The issue here is that when my vpn is on, I get another host and that causes the clients to be unable to connect.
But when I open command prompt and type ipconfig, I get the correct ip regardless of the vpn status. So I need to get the same ip as would be shown under IPv4 in command prompt, is this possible in python?
I'm trying to get the server to work on any device regardless of exceptions such as this.
Thanks!

The way you retrieve the IP addresses of your system (most systems these days have multiple) uses the hostname of your system and therefore depends on i.e. DNS and your local hosts file. It will only give you one address, and can be quite unreliable, as you have seen with your VPN.
I'd recommend using the netifaces package. With it you can retrieve a list of all network interfaces and all their addresses.
An example from the manual:
>>> addrs = netifaces.ifaddresses('en0')
>>> addrs[netifaces.AF_INET]
[{'broadcast': '10.15.255.255', 'netmask': '255.240.0.0', 'addr': '10.0.1.4'}, {'broadcast': '192.168.0.255', 'addr': '192.168.0.47'}]
You should be able to install it with pip. The source repository is here: https://bitbucket.org/al45tair/netifaces

Yeah so I ran into this issue and it seems that ipconfig command does work, so I used the following. It calls ipconfig using subprocess and uses a regex pattern to match the ipv4 line. Since there's two ipv4 lines, and on my machine the VPN appeared as Unknown adapter WindscribeWireguard: before Wireless LAN adapter Wi-Fi: so I ended up matching the last one that appears. It's possible this isn't robust but I'm sure one of my users will let me know then.
from subprocess import check_output
import re
ipv4_pattern = re.compile(r'IPv4 Address.*:\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
def get_ipv4():
ipconfig_output = check_output(['ipconfig'], shell=True, text=True, encoding='iso8859-2')
return ipv4_pattern.findall(ipconfig_output)[-1]

Related

How to use Python SMB connection when you don't know the server's IP?

I'm using PySMB right now:
https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html
and the SMBConnection.connect spec is problematic because it requires knowing the server's IP address.
What about a usage case where I don't know the IP address and looking up the IP address fails? I already went through the steps in https://apple.stackexchange.com/questions/10956/finding-the-remote-ip-address-used-by-a-mounted-smb-share although the server in question isn't a Bonjour service.
I tested using the smb address (that would normally be typed into the Finder's "Connect To Server" option in Mac OS) in the connect function and that didn't work.
Is there an alternative library that takes an SMB address (instead of IP address), or at least a canonical/proper way to translate that into an IP address for this? Either way, please post an example.
I was facing similar kind of issue, did u try making the following changes?
smb = SMBConnection(user_id, password, client, server_name, domain = domain, use_ntlm_v2=True, is_direct_tcp=True)
ip = socket.gethostbyname(server_name)
print(ip)
smb.connect(server_name, 445)

Port forwarding in python to allow socket connections

I start a server using sockets and want to allow clients to connect to it.
self.sock.bind(('0.0.0.0',0)) # 0.0.0.0 will allow all connections and port 0 -> os chooses a open port.
stroke_port=self.sock.getsockname()[1]
self.sock.listen(75)
self.open_port_popup(stroke_port)
Now, for other clients to connect I have port forward it manually and it works fine.
I want to do this in automated fashion. -> I try upnp.
import miniupnpc
def open_port(port_no):
'''this function opens a port using upnp'''
upnp = miniupnpc.UPnP()
upnp.discoverdelay = 10
upnp.discover()
upnp.selectigd()
# addportmapping(external-port, protocol, internal-host, internal-port, description, remote-host)
result=upnp.addportmapping(port_no, 'TCP', upnp.lanaddr, port_no, 'testing', '')
return result
It opens a port shown in the image below. But the port-forwarding list shown in the first image is empty. It doesn't work and clients can't connect. How can I fix this? What am I missing?
I think you made a mistake using upnp.lanaddr as internal-host address. upnp.lanaddr is the address of the upnp device which is your router, you want to use the local address of your server.
If needed take a look at Finding local IP addresses using Python's stdlib if you want to get your server local IP dynamically.
I think that we are missing lot of related info to know what's the main problem here. I see so many people guessing.
By the way, just editing that line
result=upnp.addportmapping(port_no, 'TCP', upnp.lanaddr, port_no, 'testing', '') to
result=upnp.addportmapping('7777', 'TCP', '192.168.1.8', '7777', 'testing', '') would tell you if it works at all.
Doing port testing from localhost it's dummy, you're not under the router at all.
Also, remember to use Try/Except blocks to tell you what's wrong on your code.
try:
print "1" + 1
except Exception as e:
print str(e)
Another way, not fashioned is to use html/web automation, even cURL to make those requests instead using uPnp, this way you don't really need to handle it.
Most of the time ISP don't allow port forwarding, and you spend hours on this trying to forward port.
I went for ngrok - it's a lightweight free of cost (for basic usage) program that tunnels the port and give its own tunneled domain which can be accessed everywhere.
this is interesting question.
from what I could summon I think
GUI shows that UPNP port forwarding rules are added.
so Most likely there is issue in UPNPC configuration.
I doubt you are doing this on Router or similar platform with X-WRT or OpenWRT
the issue I think is you can't use upnp for this or it doesn't work for some strange reason.
I suggest you try this library pytables.
I know you wanted to know why and I am working on figuring out the reason.
this is just for you to get going on this project
and for quick solution
Try this
import subprocess
p = subprocess.Popen(["iptables", "-A", "INPUT", "-p", "tcp", "-m", "tcp", "--dport", "22" , "-j", "ACCEPT"], stdout=subprocess.PIPE)
output , err = p.communicate()
print output

difference between finding ip address by python an cmd

I wrote this code for finding google ip in python
import socket
print socket.gethostbyname('google.com')
.
.
173.194.39.0
but if we use command prompt and ping command for finding google ip result is:216.58.208.36
why there is difference between two results?
Both of those IP addresses resolve to Google.com. We can verify this from the command line with the unix whois command.
$ whois 216.58.208.36
NetRange: 216.58.192.0 - 216.58.223.255
CIDR: 216.58.192.0/19
NetName: GOOGLE
$ whois 173.194.39.0
NetRange: 173.194.0.0 - 173.194.255.255
CIDR: 173.194.0.0/16
NetName: GOOGLE
I ran into this same issue and the cause was that the first command that required an IP address was using a cached DNS entry (because the DNS entry's time to live (TTL) hadn't expired yet) and then by the time the second command was issued the TTL had expired on the cached entry so a new DNS request was made for the domain therefore grabbing a new IP address from the DNS server which happened to be different because the domain had a lot of IP addresses just like Google.com.
Python just relies on the Operating System's DNS resolver (or whatever daemon is running) and as far as I know the socket module doesn't give you the ability to clear the DNS cache before it tries to resolve an address. If you want more control over this functionality you can use DNSPython or something similar. If you are using a daemon for DNS on your operating system (like on Linux, for example) then usually restarting the daemon will force a flush of DNS cache and you find both addresses to the be same (unless you run into the timing issue as described above with the TTL's expiring).
Hostnames are translated to IP addresses through something called a DNS server. When you type a name into a web browser or use a program such as ping, the hostname that you provide (google.com) eventually reaches an authoritative DNS server for that domain-separate from the server that you correspond with for the actual content.
google.com has multiple different servers that can respond to data requests. Depending on the implementation of the different programs you are using to generate the request and other factors such as the network traffic at the time that you make the request, multiple requests from the same host may be directed to different servers by the authoritative DNS server. This is accomplished by returning different IP addresses to your machine.
FWIW, both ping and socket.gethostbyname() for google.com resolve to 216.58.217.14 on my machine, running OS X Yosemite.

Sending traffic from multiple source IPs Scapy

I am trying to send some traffic via python using scapy (on Ubuntu). I am using a range of source IPs (10.0.0.32/29). Everything seems to be working (at least I see the traffic in wireshark and it reaches my firewall) but I am having a problem completing the TCP handshake using the IP addresses that aren't the main IP of the eth0 adapter. Does anyone know if this is possible to do:
Source:
from scapy.all import *
import random
sp=random.randint(1024,65535)
ip=IP(src="10.0.0.234/29",dst="www.google.com")
SYN=TCP(sport=sp, dport=80,flags="S",seq=10)
SYNACK=sr1(ip/SYN)
my_ack=SYNACK.seq+1
ACK=TCP(sport=sp,dport=80,flags="A",seq=11,ack=my_ack)
send(ip/ACK)
payload="SEND TCP"
PUSH=TCP(sport=sp,dport=80,flags="PA",seq=11,ack=my_ack)
send(ip/PUSH/payload)
Because you are behind a NAT/router, you should check it allows you to use the full range of IPs. If it is running DHCP protocol, your eth0 will typically recieve a unique IP adress that will be the only routed in your private network.
Furthermore, you must ensure your kernel knows what IPs are attributed to it, else it will drop response packets. If you want to use the full range of IP, you have two choices :
Create virtual devices with virtual mac adresses, each requesting an IP through DHCP.
Configure your router so it statically routes the full IP table to your host, and alias each IP you intend to use
Once you have done that, there is no reason you wouldn't be able to syn/ack from your multiple source IPs. From distant server point of view, there wouldn't be any difference between what you are trying to do and several machines in a local network requesting a page at the same time.

Availability of IP Address - Python

How to check the availability of an IP address in python?
For example, I wan't to change my system's IP address to 192.168.112.226 statically overriding the dhcp provided address. The default gateway is 192.168.112.1. But I wan't to check before if anyone is using 192.168.112.226 before assigning to myself.
Usually do this in command line from bash. I check with ping 192.168.112.226. If host is unreachable, I use 'ifconfig' and 'route' to assign it to myself.
How to automate this using python?
PS: I prefer python so that I can use python-notify to beautify the output whether success or failure.
This is so bad in so many ways I can't even explain how awfull this is.
Why do you want this? Could you please tell us that, and we could come up with a much better answer than this utterly uggly "sollution"?
If you have a Linux/Unix system, you can make your DHCP client to request the DHCP-server to give you a specific IP address if the DHCP server know it's free. How to do this depends on the distribution.
There are two problems I see that you will create with your "sollution".
As some other has written, you could check to see that the IP is "free" right now, but the machine that own that IP address might start right after your test. Using its IP address, wich you have kidnapped.
If the DHCP server don't know that you have kidnapped an IP address, it could give it out to someone else.
Whatever it will break the network for that computer and yours, generating lots of work, and possible anger for/to the network administrator. And you don't want that, do you?
Okay, if you want to use bash, you can import os module or subprocess module.
for example:
import os
command = os.system('pint 192.168.112.226')
if command == 0: #Sucess
#write os.system() and give it ifconfig and route commands as parameter.
else: print "This IP is used by another person in your network."
you can read more about os.system and subprocess in python, by importing them and writing help(subprocess) for example.
You can use socket.gethostbyaddr() to find if IP Address is being in use or not.
import sys, os, socket
# Stores the IP Address
ip_address = sys.argv[1]
try:
socket.gethostbyaddr(ip_address)
# If previous line doesn't throw exception, IP address is being used by someone
print "No"
except socket.herror:
# socket.gethostbyaddr() throws error, so IP is not being used at present
# You can write os.system() and give it ifconfig and route commands as parameter.
print "Yes"
The problem with this code is that method.gethostbyaddr() takes lot of time to throw socket.herror if IP address is not in use on the network.
If you name this script as isIPAvailable.py, then it can be called by:
python isIPAvailable.py 192.168.112.226

Categories