Converting IPv4 Address to a Hex IPv6 Address in Python - python

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

Related

getting remote ip from local ip

given a local side IP address(ip): u'1.1.1.1/32' #unicode format
how to get the remote side ip? (which will be 1.1.1.2)
logic:
if local ip is even, remote ip will be local ip + 1
else, local ip - 1
i was trying something like this:
ip_temp = int(ip.replace('/32','').split('.')[-1])
if ip_temp % 2 == 0:
remote = ip + 1
else:
remote = ip - 1
remote_ip = <replace last octet with remote>
I looked into ipaddress module but couldnt find anything useful
Most Python socket utilities require that the Remote IP Be a tuple with a string and port number (integer). For example:
import socket
address = ('127.0.0.1', 10000)
sock.connect(address)
For your case, you have most of the logic required. However you need to determine what to do with the cases of X.X.X.0 and X.X.X.255.
The full code to do what you want is:
ip = '1.1.1.1/32'
# Note Drop the cidr notation as it is not necessary for addressing in python
ip_temp = ip.split('/')[0]
ip_temp = ip_temp.split('.')
# Note this does not handle the edge conditions and only modifies the last octet
if int(ip_temp[-1]) % 2 == 0:
remote = int(ip_temp[-1]) + 1
else:
remote = int(ip_temp[-1]) -1
remote_ip = ".".join(ip_temp[:3]) + "." + str(remote)

The raw sockets can't create an ARP request packet with source (MAC and IP )taken as some other machine .. Any suggestions?

I'm using the below script for injecting an ARP packet request. When I keep the source (MAC and IP) as my machine, I can happily see the packets in the wire and receive ARP replies however on changing the source to a different machine in the LAN, the ARP requests don't get back the ARP replies.
I am dicey if the RAW sockets can only frame up an ARP request for the base machine or am I going wrong somewhere ?
Below is the code ...
#!/usr/bin/python
import sys
import socket
import binascii
import struct
from itertools import chain
try:
iFace = raw_input("Enter the interface using which the Injection needs to be done ...\n")
rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW,socket.htons(0x0800))
rawSocket.bind((iFace, socket.htons(0x0800)))
print "Raw Socket got created .... with the Ethernet Protocol Id : 0x0806 at interface %s"%str(iFace)
except:
print "Something unexpected happened during the Program execution."
else:
def checkMac(mac):
if len(mac.split(":")) != 6:
print "The MAC is in correct. It should be in Hexadecimal Format with each byte separated with colon...\n"
sys.exit(0)
else:
macList = mac.split(":")
macLen = len(macList)
return tuple ([int(macList[index],16) for index in range(macLen)])
def checkIp(ip):
ipList = ip.split(".")
ipLen = len(ipList)
return int( "".join( [ "{:02X}".format(int(ele)) for ele in ipList ] ), 16 )
dMac = raw_input("Enter the Destination MAC .. hexadecimal charaters separated with ':' \n")
# dMac = "0X:XX:XX:XX:XX:4X"
dMacTup = checkMac(dMac)
# sMac = raw_input("Enter the Source MAC .. hexadecimal charaters separated with ':' \n")
sMac = "XX:XX:XX:XX:XX:XX"
sMacTup = checkMac(sMac)
type = 0x0806
# Creating an Ethernet Packet .... using dMac, sMac, type
etherPack = struct.pack ("!6B6BH",*tuple(chain(dMacTup,sMacTup,[type])))
# Creating an ARP Packet .... now
hardwareType = 0x0001
protocolType = 0x0800
hln = 0x06
pln = 0x04
op = 0x0001
# srcIp = raw_input("Enter the Source IP ':' \n")
srcIp = "10.0.2.216"
intSrcIp = checkIp(srcIp)
destIp = raw_input("Enter the Destination IP .. \n")
# destIp = "10.0.2.1"
intDestIp = checkIp(destIp)
arpPack = struct.pack("!HHBBH6BI6BI", *tuple(chain( [hardwareType,protocolType,hln,pln,op], sMacTup,[intSrcIp], dMacTup,[intDestIp] )))
# Framing the final Packet
finalPack = etherPack + arpPack
for i in range(50):
rawSocket.send(finalPack + "Hacker in the wires ...")
print "Sending Packet %d"%i
finally:
print "Closing the created Raw Socket ..."
rawSocket.close()

Python TypeError: an integer is required while working with Sockets

Research:
Getting a "TypeError: an integer is required" in my script
https://github.com/faucamp/python-gsmmodem/issues/39
https://docs.python.org/2/howto/sockets.html
Here is my complete error output:
Traceback (most recent call last):
File "/home/promitheas/Desktop/virus/socket1/socket1.py", line 20, in <module>
createSocket()
File "/home/promitheas/Desktop/virus/socket1/socket1.py", line 15, in createSocket
ServerSock.bind((socket.gethostname(), servPort))
File "/usr/lib/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
TypeError: an integer is required
Code:
import socket
# Acquiring the local public IP address
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 0))
# Defining some variables
servIpAddr = s.getsockname()[0]
servPort = ''
while ((len(servPort) < 4)): # and (len(servPort) > 65535)
servPort = raw_input("Enter server port. Must be at least 4 digits.\n> ")
# Creating a socket to wait for a connection
def createSocket():
ServerSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ServerSock.bind((socket.gethostname(), servPort)) # This is where the error occurs
ServerSock.listen(5)
(clientsocket, address) = ServerSock.accept()
if __name__ == "__main__":
createSocket()
I'm not sure if there are any other errors, but I'm really stumped on this one. Please ask if you need any other info, and thanks in advance!
It looks like the second element of the address tuple needs to be an integer. From the documentation:
A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in Internet domain notation like 'daring.cwi.nl' or an IPv4 address like '100.50.200.5', and port is an integer.
Try converting servPort to an integer before using it in bind.
servPort = ''
while ((len(servPort) < 4)): # and (len(servPort) > 65535)
servPort = raw_input("Enter server port. Must be at least 4 digits.\n> ")
servPort = int(servPort)
servPort must be an integer. You currently have it set to a string the user enters. Try casting the raw_input to an int using int(servPort).

Parsing IP address and port in python

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()

I want to match a newline character followed by a string using regular expression in python

Device ID: xyz
Entry address(es):
IP address: 10.3.10.46
Platform: WS-x, Capabilities: Switch IGMP
Interface: GigabitEthernet9/33, Port ID (outgoing port): GigabitEthernet0/2
Holdtime : 177 sec
Management address(es):
IP address: 10.3.10.46
above is a snipet from a file.From among the above i want to collect the ip address by matching only the 2 lines below.
Entry address(es):
IP address: 10.3.10.46
or
Management address(es):
IP address: 10.3.10.46
The regular expression i have written is as follows which does not work and i am not able to resolve how i can show the new line after "address(es):" in my regular expression.
f = open(fileName)
for line in f:
matchObj1 = re.match(r'Entry address\(es\):\s+IP address: ([0-9.]+)', line)
if matchObj1:
print "IP Address = ", matchObj1.group(1)
matchObj2 = re.match(r'Entry address\(es\):\s+IP address: ([0-9.]+)', line)
if matchObj2:
print "IP Address = ", matchObj2.group(1)
Please Help. Thank you.
You need to use re.search instead of re.match, re.match is used for matching from the start of string:
>>> s = 'Device ID: xyz\nEntry address(es): \n IP address: 10.3.10.46\n Platform: WS-x, Capabilities: Switch IGMP \n Interface: GigabitEthernet9/33, Port ID (outgoing port): GigabitEthernet0/2\n Holdtime : 177 sec'
>>> re.search(r'Entry address\(es\):\s+IP address: ([0-9.]+)', s).group(1)
'10.3.10.46'
search() vs. match():
re.match() checks for a match only at the beginning of the string,
while re.search() checks for a match anywhere in the string.
You don't need to use regular expressions for this. Your input looks like the output of a configuration file or a program, and easy to parse.
def get_addresses(fname):
addresses = {}
with open(fname) as f:
lines = [l.strip().lower() for l in f]
for i, line in enumerate(lines):
if line.startswith("ip address"):
ip = line.split(": ")[1]
address_type = lines[i-1]
if address_type == "entry address(es):":
addresses["entry"] = ip
elif address_type == "management address(es):":
addresses["management"] = ip
# Add additional address type handling here
return addresses

Categories

Resources