Using python, I'd like to accomplish two things:
Need to split an ipv6 address and port combination in the format [fec2::10]:80 to fec2::10 and 80.
Given an IP address and port combination, I need to determine if the IP is a v4 or v6 address. Eg: 1.2.3.4:80 and [fec2::10]:80
Please suggest a way to do it.
Thanks!
Sample code:
#!/usr/bin/env python
def main():
server = "[fec1::1]:80"
if server.find("[", 0, 2) == -1:
print "IPv4"
ip, port = server.split(':')
else:
print "IPv6"
new_ip, port = server.rsplit(':', 1)
print new_ip
ip = new_ip.strip('[]')
print ip
print port
if __name__ == '__main__':
main()
This works for all cases except when the input is specified without a port. Eg: 10.78.49.50 and [fec2::10]
Any suggestions to address this?
Assuming your_input is like "[fec2::10]:80" or "1.2.3.4:80", it is easy to split the port and find out the ip address:
#!/usr/bin/env python3
from ipaddress import ip_address
ip, separator, port = your_input.rpartition(':')
assert separator # separator (`:`) must be present
port = int(port) # convert to integer
ip = ip_address(ip.strip("[]")) # convert to `IPv4Address` or `IPv6Address`
print(ip.version) # print ip version: `4` or `6`
You can use urlparse (called urllib.parse in 3.x) to separate the URL into each of its components:
>>> from urlparse import urlparse
>>> ipv4address = urlparse("http://1.2.3.4:80")
>>> ipv4address
ParseResult(scheme='http', netloc='1.2.3.4:80', path='', params='', query='', fragment='')
>>> ipv6address = urlparse("http://[fec2::10]:80")
>>> ipv6address
ParseResult(scheme='http', netloc='[fec2::10]:80', path='', params='', query='', fragment='')
Then you can split the port off by finding the index of the last colon using rfind:
>>> ipv4address.netloc.rfind(':')
7
>>> ipv4address.netloc[:7], ipv4address.netloc[8:]
('1.2.3.4', '80')
>>> ipv6address.netloc.rfind(':')
10
>>> ipv6address.netloc[:10], ipv6address.netloc[11:]
('[fec2::10]', '80')
Identifying which type it is should then be as simple as if ':' in that_split_tuple[0], right? (Not 100% sure because it's been a while since I learned about how to write IPv6 addresses in URLs.)
Finally, removing the brackets from your IPv6 address is simple, there are many ways to do it:
>>> ipv6address.netloc[:10].replace('[', '').replace(']', '')
'fec2::10'
>>> ipv6address.netloc[:10].strip('[]')
'fec2::10'
Edit: since you expressed concern about not always having port numbers, you could simplify significantly by using a regular expression:
>>> import re
>>> f = lambda(n): re.split(r"(?<=\]):" if n.startswith('[') else r"(?<=\d):", n)
>>> f(ipv4address.netloc)
['1.2.3.4', '80']
>>> f(ipv6address.netloc)
['[fec2::10]', '80']
>>> f("1.2.3.4")
['1.2.3.4']
>>> f("[fec2::10]")
['[fec2::10]']
(I'm having trouble being more clever with my regular expression, hence the inline ternary.)
This is the code I came up with. It looks lengthy and laborious, but it addresses all possible input scenarios. Any suggestion to condense/better it is most welcome :)
#!/usr/bin/env python
import optparse
def main():
server = "[fec1::1]:80"
if server.find("[", 0, 2) == -1:
print "IPv4"
if server.find(":", 0, len(server)) == -1:
ip = server
port = ""
else:
ip, port = server.split(':')
else:
print "IPv6"
index = server.find("]", 0, len(server))
if index == -1:
print "Something wrong"
new_ip = ""
port = ""
else:
if server.find(":", index, len(server)) == -1:
new_ip = server
port = ""
else:
new_ip, port = server.rsplit(':', 1)
print new_ip
ip = new_ip.strip('[]')
print ip
print port
if __name__ == '__main__':
main()
Related
I want to convert a hexadecimal byte variable that comes in through the network into IP and Port.
For example, the format is :
value = (b'\xd3[\xdf\x94:\x98\xd5\xe6J\x9f\xb2\xfb\xd8\x18\xbdDsa')
# Size is random but multiples of 6 all.
type(value) # bytes
I want to print the variable named value above as follows.
>>> func(value)
"211.91.223.148:15000"
"213.230.74.159:45819"
Even if I searched, I could not find a module that changes bytes to IP and Port.
Any help would be appreciated.
test.py:
import ipaddress
import struct
from itertools import islice
N = 6
def func(value):
it = iter(value)
while chunk := bytes(islice(it, N)):
ip, port = struct.unpack("!IH", chunk)
ip = ipaddress.ip_address(ip)
print(f"{ip}:{port}")
def main():
value = b"\xd3[\xdf\x94:\x98\xd5\xe6J\x9f\xb2\xfb\xd8\x18\xbdDsa"
func(value)
if __name__ == "__main__":
main()
Test:
$ python test.py
211.91.223.148:15000
213.230.74.159:45819
216.24.189.68:29537
I am trying to get the DNS Server IP Addresses using python. To do this in Windows command prompt, I would use
ipconfig -all
As shown below:
I want to do the exact same thing using a python script. Is there any way to extract these values?
I was successful in extracting the IP address of my device, but DNS Server IP is proving to be more challenging.
I recently had to get the IP addresses of the DNS servers that a set of cross platform hosts were using (linux, macOS, windows), this is how I ended up doing it and I hope it's helpful:
#!/usr/bin/env python
import platform
import socket
import subprocess
def is_valid_ipv4_address(address):
try:
socket.inet_pton(socket.AF_INET, address)
except AttributeError: # no inet_pton here, sorry
try:
socket.inet_aton(address)
except socket.error:
return False
return address.count('.') == 3
except socket.error: # not a valid address
return False
return True
def get_unix_dns_ips():
dns_ips = []
with open('/etc/resolv.conf') as fp:
for cnt, line in enumerate(fp):
columns = line.split()
if columns[0] == 'nameserver':
ip = columns[1:][0]
if is_valid_ipv4_address(ip):
dns_ips.append(ip)
return dns_ips
def get_windows_dns_ips():
output = subprocess.check_output(["ipconfig", "-all"])
ipconfig_all_list = output.split('\n')
dns_ips = []
for i in range(0, len(ipconfig_all_list)):
if "DNS Servers" in ipconfig_all_list[i]:
# get the first dns server ip
first_ip = ipconfig_all_list[i].split(":")[1].strip()
if not is_valid_ipv4_address(first_ip):
continue
dns_ips.append(first_ip)
# get all other dns server ips if they exist
k = i+1
while k < len(ipconfig_all_list) and ":" not in ipconfig_all_list[k]:
ip = ipconfig_all_list[k].strip()
if is_valid_ipv4_address(ip):
dns_ips.append(ip)
k += 1
# at this point we're done
break
return dns_ips
def main():
dns_ips = []
if platform.system() == 'Windows':
dns_ips = get_windows_dns_ips()
elif platform.system() == 'Darwin':
dns_ips = get_unix_dns_ips()
elif platform.system() == 'Linux':
dns_ips = get_unix_dns_ips()
else:
print("unsupported platform: {0}".format(platform.system()))
print(dns_ips)
return
if __name__ == "__main__":
main()
Resources I used to make this script:
https://stackoverflow.com/a/1325603
https://stackoverflow.com/a/4017219
Edit: If anyone has a better way of doing this please share :)
DNS Python (dnspython) might be helpful. You can get the DNS server address with:
import dns.resolver
dns_resolver = dns.resolver.Resolver()
dns_resolver.nameservers[0]
i have the following code:
import socket # Import socket module
import sys
s = socket.socket() # Create a socket object
host = '' # Get local machine name
port = 1234 # Reserve a port for your service.
s.connect((host, port))
while 1:
data = s.recv(1024)
print ' data ' , data
d = data.split('?') # parsing values from server
if len(d) < 2:
# if does not contain ?, do nothing
continue
else:
a = d[0]
b = d[1].replace('\n', '')
# check how a compares to b, and send response accordingly
if (a > b):
s.send('1')
elif (a == b):
s.send('2')
else:
s.send('3')
s.close() # Close the socket when done
Without the processing code I have, it works fine if I just send a random value. But with the code above, I can only parse the first set of line, and then it stops. (I assume it closes the socket or something?)
The data coming from the socket looks like '1 ? 23' or '23 ? 1' , etc. it expects a response that determines how the two numbers relate.
In comparison, if I have this code:
import socket # Import socket module
import sys
s = socket.socket() # Create a socket object
host = '' # Get local machine name
port = 1234 # Reserve a port for your service.
s.connect((host, port))
backlog = ''
while 1:
data = s.recv(1024)
sp = data.split('\n')
if len(sp) < 2:
backlog += data
continue
line = backlog + sp[0]
backlog = sp[1]
data = line
print ' data ' , data
if not data:
break
s.send ('2')
s.close() # Close the socket when done
This code will yield a server response of either 'Correct!' or 'Incorrect...try again!' depending on whether it's right or wrong.
You seem to assume that you always get a full line with each read() call. That is wrong.
You should split your input into lines, and only if you have a full line, you proceed.
backlog = ''
while 1:
data = s.recv(1024)
# do we have a line break?
sp = data.split('\n')
if len(sp) < 2:
# no, we haven't...
backlog += data
continue
# yes, we have.
line = backlog + sp[0] # first part is the now complete line.
backlog = sp[1] # 2nd part is the start of the new line.
print ' line ' , line
d = line.split('?') # parsing values from server
if len(d) < 2:
# if does not contain ?, do nothing
continue
else:
a = int(d[0]) # we want to compare numbers, not strings.
b = int(d[1])
# check how a compares to b, and send response accordingly
if (a > b):
s.send('1')
elif (a == b):
s.send('2')
else:
s.send('3')
Try out what happens now.
Another question which occurs to me is what exactly does the server expect? Really only one byte? Or rather '1\n', '2\n', '3\n'?
Q: Write a program that prompts the user for an IP address then converts this to a base 10, binary and hex value. The program then converts the hex value to an RFC3056 IPv6 6to4 address.
I have the base 10 and binary parts working but I can't seem to get my head around the hex part. Can the format string method be used somehow to accomplish the same thing? Or would I need to import the ipaddress module in this case?
#!/usr/bin/python3
ip_address = input("Please enter a dot decimal IP Address: ")
"""This part converts to base 10"""
ListA = ip_address.split(".")
ListA = list(map(int, ListA))
ListA = ListA[0]*(256**3) + ListA[1]*(256**2) + ListA[2]*(256**1) + ListA[3]
print("The IP Address in base 10 is: " , ListA)
"""This part converts to base 2"""
base2 = [format(int(x), '08b') for x in ip_address.split('.')]
print("The IP Address in base 2 is: ", base2)
"""This part converts to hex"""
hexIP = []
[hexIP.append(hex(int(x))[2:].zfill(2)) for x in ip_address.split('.')]
hexIP = "".join(hexIP)
print("The IP Address in hex is: " , hexIP)
EDIT: Managed to convert the IP Address to hex value. Now how do I convert this hex value into IPv6 address?
>>> ip_address = '123.45.67.89'
>>> numbers = list(map(int, ip_address.split('.')))
>>> '2002:{:02x}{:02x}:{:02x}{:02x}::'.format(*numbers)
'2002:7b2d:4359::'
In Python 3.3 you could use ipaddress module to manipulate IPv4, IPv6 addresses:
#!/usr/bin/env python3
import ipaddress
# get ip address
while True:
ip4str = input("Enter IPv4 (e.g., 9.254.253.252):")
try:
ip4 = ipaddress.IPv4Address(ip4str)
except ValueError:
print("invalid ip address. Try, again")
else:
break # got ip address
# convert ip4 to rfc 3056 IPv6 6to4 address
# http://tools.ietf.org/html/rfc3056#section-2
prefix6to4 = int(ipaddress.IPv6Address("2002::"))
ip6 = ipaddress.IPv6Address(prefix6to4 | (int(ip4) << 80))
print(ip6)
assert ip6.sixtofour == ip4
# convert ip4 to a base 10
print(int(ip4))
# convert ip4 to binary (0b)
print(bin(int(ip4)))
# convert ip4 to hex (0x)
print(hex(int(ip4)))
If you just want to use the IPv4 addresses in an IPv6 context (e.g. by passing to socket.connect() created using the socket.AF_INET6 address family), you can just use the syntax described in RFC4291, Section 2.2:
>>> import socket
>>> a = '10.20.30.40'
>>> s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
>>> s.connect(('2002::' + a, 9))
I.e. just prepend ::ffff: to the IPv4 address and you get a valid 6to4 address. If you instead want to convert this address to the more common hexadecimal form, I suggest using the standard library ipaddress module you mentioned:
>>> import ipaddress
>>> a = '10.20.30.40'
>>> print(ipaddress.IPv6Address('2002::' + a).compressed)
'2002::a14:1e28'
Before referring to the solution, have a look at this doc for conversion and convention of ipv6 representation.
def ipconversion4to6(ipv4_address):
hex_number = ["{:02x}".format(int(_)) for _ in address.split(".")]
ipv4 = "".join(hex_number)
ipv6 = "2002:"+ipv4[:4]+":"+ipv4[4:]+"::"
return ipv6
I'm a python newbie and I don't understand why it won't read my IP and ADDR variables in the function dns.zone.query(IP, ADDR)???
import dns.query
import dns.zone
import sys
IP = sys.stdin.readline()
ADDR = sys.stdin.readline()
z = dns.zone.from_xfr(dns.query.xfr(IP , ADDR))
names = z.nodes.keys()
names.sort()
for n in names:
print z[n].to_text(n)
It works when I pass an actual IP and Domain, but not with the variables... I don't get what's wrong?
readline() will include a trailing newline. You can use sys.stdin.readline().strip()
I would try with:
IP = sys.stdin.readline().strip()
ADDR = sys.stdin.readline().strip()
Add some prints after the variables to debug it:
print '_%s_' % IP
print '_%s_' % ADDR
Try sys.stdin.readline().strip(). You need to remove the newlines.