inet_aton similar function for IPv6 - python

I am using inet_aton to convert IPv4 IP(216.12.207.142) to a string 3624718222. I use the following code for that:
ip_dec = unpack('>L', inet_aton(ip))[0]
Now I need to convert IPv6 ip 2001:23::207:142 to a similar string. It gives me error as it is not IPv4 address. How can I do this?

This is the code I've uses for the purpose before. Note that it returns a 128 bit integer rather than a string (an integer is more useful in general)
from socket import inet_pton, AF_INET6
from struct import unpack
def ip6_to_integer(ip6):
ip6 = inet_pton(AF_INET6, ip6)
a, b = unpack(">QQ", ip6)
return (a << 64) | b
And testing it
>>> ip6_to_integer("2001:23::207:142")
42540490934961530759802172199372521794L
Or as a string if you must!
>>> str(ip6_to_integer("2001:23::207:142"))
'42540490934961530759802172199372521794'

Related

How to send unsigned values to dBus from Python

I'm trying to use PyQt5's DBus module to interact with the KDE PowerManagerAgent. When calling the AddInhibition method I need to send the first paramter as an uint32 (Unsigned int), but the code sends the value as a singed int.
The code is written using Python 3
self.dBus = QtDBus.QDBusConnection.sessionBus()
msg = QtDBus.QDBusMessage.createMethodCall(self.dBusService, self.dBusPath,self.dBusInterface,'AddInhibition')
msg << 1 << who << reason
reply = QtDBus.QDBusReply(self.dBus.call(msg))
Looking at the output from dbus-monitor I can tell that the code does indeed contact the powermonitor but fails to find the correct AddInhibition method due to the first parameter being type as int32
Output from dbus-monitor when trying to call AddInhibition
Call
method call time=1549706946.073218 sender=:1.172 -> destination=org.kde.Solid.PowerManagement.PolicyAgent serial=5 path=/org/kde/Solid/PowerManagement/PolicyAgent; interface=org.kde.Solid.PowerManagement.PolicyAgent; member=AddInhibition
int32 1
string "This"
string "fails"
Reply
error time=1549706946.073536 sender=:1.29 -> destination=:1.172 error_name=org.freedesktop.DBus.Error.UnknownMethod reply_serial=5
string "No such method 'AddInhibition' in interface 'org.kde.Solid.PowerManagement.PolicyAgent' at object path '/org/kde/Solid/PowerManagement/PolicyAgent' (signature 'iss')"
Output from dbus-monitor when using QDBusViewer application
Call
method call time=1549723045.320128 sender=:1.82 -> destination=org.kde.Solid.PowerManagement.PolicyAgent serial=177 path=/org/kde/Solid/PowerManagement/PolicyAgent; interface=org.kde.Solid.PowerManagement.PolicyAgent; member=AddInhibition
uint32 1
string "This"
string "Works"
Reply
method return time=1549723045.320888 sender=:1.29 -> destination=:1.82 serial=1370 reply_serial=177
uint32 30
Since Python is not strongly typed how do I specify the the parameter must be typed as an unsigned int?
You can use the DBusArgument class to do this by specifying the QMetaType of the argument.
For example, say you want to use the RequestName method from org.freedesktop.DBus (see the spec). The flags argument is an unsigned int, so you'll run into this problem:
>>> from PyQt5.QtDBus import QDBusConnection, QDBusInterface
>>> sessionbus = QDBusConnection.sessionBus()
>>> iface = QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", sessionbus)
>>> c = iface.call('RequestName', 'com.mydomain.myapp', 4)
>>> c.arguments()
['Call to RequestName has wrong args (si, expected su)\n']
So, it's saying it got a string and an integer (si), but it wanted a string and an unsigned integer (su). So, we'll use the QDBusArgument class and specify QMetaType.UInt:
>>> from PyQt5.QtCore import QMetaType
>>> from PyQt5.QtDBus import QDBusConnection, QDBusInterface, QDBusArgument
>>> sessionbus = QDBusConnection.sessionBus()
>>> iface = QDBusInterface("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", sessionbus)
>>> a1 = QDBusArgument()
>>> a1.add('com.mydomain.myapp', QMetaType.QString)
>>> a2 = QDBusArgument(4, QMetaType.UInt)
>>> c = iface.call('RequestName', a1, a2)
>>> c.arguments()
[1]
Since the string was fine, that didn't have to be a QDBusArgument. I just wanted to show the two ways of constructing it (with the .add() method and just using the constructor).

Not able to convert to string

I might be using wrong python terminology.
I have an array of 3 integer elements: month, date and year.
However, I am not able to print each individual element when concatenating strings.
import ssl
import OpenSSL
import time
import sys
def get_SSL_Expiry_Date(host, port):
cert = ssl.get_server_certificate((host, 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
raw_date = x509.get_notAfter()
decoded_date = raw_date.decode("utf-8")
dexpires = time.strptime(decoded_date, "%Y%m%d%H%M%Sz")
bes = dexpires.tm_mon,dexpires.tm_mday,dexpires.tm_year
print (bes)
#print(bes[0]+"/"+bes[1]+"/"+bes[2])
domain = sys.argv[1]
port = 443
get_SSL_Expiry_Date(domain, port)
If I uncomment line 14, I get an error:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
I am trying to get the date in this format (all strings): Month/Date/Year.
What am I doing wrong?
You can use Python's format() method to handle it (much cleaner also):
print("{0}/{1}/{2}".format(bes[0],bes[1],bes[2]))
...or further simplified (thanks Anton)
print("{0}/{1}/{2}".format(*bes))
↳ Python String Formatting
Simply use:
print(time.strftime("%m/%d/%y",dexpires))
See also https://docs.python.org/3/library/time.html
In general python modules usually contain all kinds of reformatting functions you don't have to reinvent them.
Example:
>>> dexpires=time.strptime('20180823131455z','%Y%m%d%H%M%Sz')
>>> dexpires
time.struct_time(tm_year=2018, tm_mon=8, tm_mday=23, tm_hour=13, tm_min=14, tm_sec=55, tm_wday=3, tm_yday=235, tm_isdst=-1)
>>> time.strftime('%m/%d/%y',dexpires)
'08/23/18'
>>>
First you have to convert int values to string than only you are able to concave them.
You can use str() inbuilt method
print(str(bes[0])+"/"+ str(bes[1])+"/"+ str(bes[2])) #convert int to str first.

Python hexidecimal address packing from string

This works correctly:
packed = struct.pack('<L',0x7c023a4f)
This does not:
address = '0x7c023a4f'
packed = struct.pack('<L',address)
How do i make this work?
I tried a lot of methods from the binascii library but i cannot seem to figure it out.
You can use literal_eval to evaluate the string as hex number before packing it:
from ast import literal_eval
address = '0x7c023a4f'
packed = struct.pack('<L', literal_eval(address))
packed
# 'O:\x02|'
Convert it to an integer:
address = '0x7c023a4f'
packed = struct.pack('<L', int(address, 16))

Compare bytes in Python

I get data over TCP and try to compare it with a known value (0xAD):
b, addr = sock.recvfrom(1)
h = "".join(hex(ord(i)) for i in b)
print h
if h == str(0xad):
print "Work"
data = bytearray()
data.append(observer.OBSERVER_VALIDATION_BYTE)
sock.sendto(data, 0, addr)
I tried to compare them like strings as it shown above and tried to compare them like bytes in two ways:
b[0] == 0xAD
or
b2 = bytearray()
b2.append(0xAD)
b2[0] == b[0]
And all of the comparisons failed, though. print h gives me 0xad.
I have a set of bytes defined like BYTE = 0xAD.
I need to send them over TCP and compare the read result.
If I define them like strings (BYTE = '0xAD'), it provides an ability to compare, but I can't put them in the bytearray to send because bytearr.append(BYTE) reasonably returns an error. So I can't redefine them as strings. So what is the way to compare bytes got from sock.recvfrom and value declared in the way I have?
If your problem is casting, you can cast variable BYTES to a bytearray this way:
>>> BYTE = '0xAD'
>>> ba = bytearray([int(BYTE, 16)])
Then compare bytearrays using ==.

Convert an IPv4 range (start and end) to slash notation in Python?

Is there a script available to convert a starting and ending IP address to a slash notation?
Example:
>>> ip_long = '10.182.71.0-10.182.75.255'
>>> convert_to_slash(ip_long)
10.182.71.0/24, 10.182.72.0/22
Use summarize_address_range() from ipaddress, which is part of the Python 3 standard library (and backported to Python 2).
>>> import ipaddress
>>> first = ipaddress.IPv4Address('10.182.71.0')
>>> last = ipaddress.IPv4Address('10.182.75.255')
>>> summary = ipaddress.summarize_address_range(first, last)
>>> list(summary)
[IPv4Network('10.182.71.0/24'), IPv4Network('10.182.72.0/22')]
Google's ipaddr-py library has a method called summarize_address_range(first, last).
summarize_address_range(first, last):
"""Summarize a network range given the first and last IP addresses.
Example:
>>> summarize_address_range(IPv4Address('1.1.1.0'),
IPv4Address('1.1.1.130'))
[IPv4Network('1.1.1.0/25'), IPv4Network('1.1.1.128/31'),
IPv4Network('1.1.1.130/32')]
Args:
first: the first IPv4Address or IPv6Address in the range.
last: the last IPv4Address or IPv6Address in the range.
Returns:
The address range collapsed to a list of IPv4Network's or
IPv6Network's.
Raise:
TypeError:
If the first and last objects are not IP addresses.
If the first and last objects are not the same version.
ValueError:
If the last object is not greater than the first.
If the version is not 4 or 6.
"""
Another solution:
from ipaddress import IPv4Address, summarize_address_range
a=" ".join(map(str, summarize_address_range(IPv4Address('8.8.8.8'), IPv4Address('8.8.9.1'))))
print(a)

Categories

Resources