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
Related
I have 2 programs comunicating with each other via ethernet. Sending one is using scapy to encode port, ip and payload before sending it as ethernet frame. My problem is that in payload im sending counter and when reciving that it's sometimes changed to symbol.
\x00\x00\x00\x00\x00\x00\x00\x07
\x00\x00\x00\x00\x00\x00\x00\x08 is fine but next
\x00\x00\x00\x00\x00\x00\x00\t
\x00\x00\x00\x00\x00\x00\x00\n
\x00\x00\x00\x00\x00\x00\x00\x0b its fine again
later they are changed to next asci symbols
My question is how to stop converting bytes to asci?
sender.py
import socket
from scapy.all import *
PADDING_VALUE = b'\xd1'
ETH_P_ALL = 3
DST_IP = "127.0.0.12"
IFACE = "lo"
SRC_IP = "127.0.0.11"
class FpgaMockup:
def __init__(self, setup_iface):
self.setup_sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
self.setup_sock.bind((setup_iface, 0))
self.padding = 16
def send(self, pkt):
self.setup_sock.send(pkt)
if __name__ == "__main__":
testing_fpga = FpgaMockup(IFACE)
for i in range(100):
packet = IP(dst=DST_IP, src=SRC_IP)/UDP(sport=12666, dport=12666)/Raw(load=int(i).to_bytes(8, "big")+PADDING_VALUE*testing_fpga.padding)
pkt = Ether(packet)
testing_fpga.send(raw(pkt))
print("Finished sending.")
reciever.py
import socket
ETH_P_ALL = 3
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(ETH_P_ALL))
s.bind(("lo", 0))
while(True):
pkt = s.recv(4096)
print(pkt)
These are not "changed". \x09 is exactly the same as \t, \x0a is the same as \n. These are just printed differently but nevertheless are the same:
>>> print(b'\x08\x09\x0a\x0b')
b'\x08\t\n\x0b'
>>> b'\x08\x09\x0a\x0b' == b'\x08\t\n\x0b'
True
For more information see the documentation to the syntax of String and Bytes literals.
If you don't want to have this conversation simply enforce writing as a hexadecimal sequence instead of characters:
>>> b'\x08\t\n\x0b'.hex()
'08090a0b'
I'm using Twisted + AMP to communicate between a server and client, both of which are Python, fully under my control. My messages are usually short, but sometimes an argument can be longer than the 64K limit. Is there any way to handle this gracefully?
I see that AMPv2 handles long messages, but I think that the Twisted implementation is for AMPv1.
I suspect chunking will be part of the answer but I'm not sure how to do that. I only have one method that is susceptible to these long messages, so I don't need the most general solution. I am open to a making different amp.Argument subclass if it will help.
You can use the below code
# From lp:~glyph/+junk/amphacks
"""
An argument type for sending medium-sized strings (more than 64k, but small
enough that they still fit into memory and don't require streaming).
"""
from cStringIO import StringIO
from itertools import count
from twisted.protocols.amp import AMP, Argument, Command
CHUNK_MAX = 0xffff
class BigString(Argument):
def fromBox(self, name, strings, objects, proto):
value = StringIO()
value.write(strings.get(name))
for counter in count(2):
chunk = strings.get("%s.%d" % (name, counter))
if chunk is None:
break
value.write(chunk)
objects[name] = value.getvalue()
def toBox(self, name, strings, objects, proto):
value = StringIO(objects[name])
firstChunk = value.read(CHUNK_MAX)
strings[name] = firstChunk
counter = 2
while True:
nextChunk = value.read(CHUNK_MAX)
if not nextChunk:
break
strings["%s.%d" % (name, counter)] = nextChunk
counter += 1
class Send(Command):
arguments = [('big', BigString())]
class Example(AMP):
#Send.responder
def gotBig(self, big):
print 'Got a big input', len(big)
f = file("OUTPUT", "wb")
f.write(big)
f.close()
return {}
def main(argv):
from twisted.internet import reactor
from twisted.internet.protocol import Factory, ClientCreator
if argv[1] == 'client':
filename = argv[2]
def connected(result):
result.callRemote(Send, big=file(filename).read())
ClientCreator(reactor, AMP).connectTCP("localhost", 4321).addCallback(
connected)
reactor.run()
elif argv[1] == 'server':
f = Factory()
f.protocol = Example
reactor.listenTCP(4321, f)
reactor.run()
else:
print "Specify 'client' or 'server'."
if __name__ == '__main__':
from sys import argv as arguments
main(arguments)
PS: The code is taken from https://raw.githubusercontent.com/fusionapp/documint/8fdbaeb3aeb298afff4ba951243d03c98fe8ff99/documint/mediumbox.py
There are 3 codes that need to do the following actions:
A sends a message to B along with the CRC32 code.
B receives this message and CRC32 code.
B follows a 40% probability to change the message.
B sends the message along with the original CRC32 code to C.
C receives the message and CRC32 code and check whether it is correct or not.
For some reason, in part C when I compare the CRC's they are never equal, what am I missing?
Part A:
import socket
import struct
import sys
import binascii
def crc32(v):
r = binascii.crc32(v.encode())
return r
if len(sys.argv) != 3:
print("Useage: python " + sys.argv[0] + " <ip> <liseten port>")
sys.exit(-1)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
print("Input text:")
text = sys.stdin.readline().strip()
ss = struct.pack("!50sL",text.encode(),crc32(text))
s.sendto(ss,(sys.argv[1],int(sys.argv[2])))
if text == "bye":
break
Part B:
import socket
import operator
import sys
import binascii
import struct
import random
def crc32(v):
return binascii.crc32(v.encode())
if len(sys.argv) != 3:
print("Useage: python " + sys.argv[0] + " <liseten port>")
sys.exit(-1)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", int(sys.argv[1])))
print("Waiting...")
while True:
data, addr = s.recvfrom(1024)
str,crc = struct.unpack("!50sL",data)
str = str.decode("utf-8").replace("\0","")
if random.randint(0,100) < 40:
str = str + "x"
print("str:%s\ncrc:%X" % (str,crc & 0xffffffff))
str2 = str.encode("utf-8")
tpack = struct.pack("!50sL", str2, crc)
s.sendto(tpack,("127.0.0.1",int(sys.argv[2])))
if str == "bye":
break
Part C:
import socket
import operator
import sys
import binascii
import struct
def crc32(v):
return binascii.crc32(v.encode())
if len(sys.argv) != 2:
print("Useage: python " + sys.argv[0] + " <liseten port>")
sys.exit(-1)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0", int(sys.argv[1])))
print("Waiting...")
while True:
data, addr = s.recvfrom(1024)
str,crc = struct.unpack("!50sL",data)
str = str.decode("utf-8")
print("str:%s\ncrc:%X" % (str,crc & 0xffffffff))
ncrc = crc32(str)
if ncrc == crc:
print("both messages are the same")
if str == "bye":
break
You forgot to replace the null bytes in Part C. You calculated the CRC in Part A before packing to 50 bytes, and removed them in Part B when displaying the received value.
str = str.decode("utf-8")
should b:
str = str.decode("utf-8").replace('\0','')
Note: str is a builtin function that you lose access to by using it as a variable name.
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()
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