Python - Create list of IPs based off starting IP - python

I spent a few hours researching, and this has stumped me. Before I go down a new path, I'm looking for a best practice.
I ultimately want a list of IPs (just the IPs) when given a starting IP, based off the quantity of items in a list.
I've been using the ipaddress module; here's the nearest I've gotten..
import ipaddress
IP_Start = 192.168.1.1
hostnames = [hostname1, hostname2, hostname3]
list_of_ips = []
my_range = range(len(hostnames))
for ips in my_range:
list_of_ips.append(ipaddress.ip_address(IP_Start) + my_range[ips])
print(list_of_ips)
Output:
list_of_ips = [IPv4Address('192.168.1.1'), IPv4Address('192.168.1.2'), IPv4Address('192.168.1.3')]
For some reason, I cannot strip "IPv4Address(' ')" out of the list of strings; my output may not be a traditional list. When using str.replace, I get weird errors and figure replacing is probably not the best practice.
I feel like if I ditch the ipaddress module, there would be a much simpler way of doing this. What would be a better way of doing this so my output is simply
list_of_ips = [192.168.1.1, 192.168.1.2, 192.168.1.3]

IPv4Address is the data type of the object returned. That is the name of a class; the display function for that class says that it returns the format you see, with the IP address as a string. You need to look up the class to find a method (function) or attribute (data field) to give you the IP address as a string, without the rest of the object tagging along.
The simplest way to do this is to convert to str:
for ips in my_range:
list_of_ips.append(str(ipaddress.ip_address(IP_Start)) ... )

Here is how to do it with builtins only
start with a function to convert an IP address to a long integer, and another function to convert a long integer back into an IP address
import socket,struct
def ip_to_int(ip_address):
return struct.unpack('!I', socket.inet_aton(ip_address))[0]
def int_to_ip(int_value):
return socket.inet_ntoa(struct.pack('!I', int_value))
then all you need to do is iterate over your range
def iter_ip_range(start_address, end_address):
for i in range(ip_to_int(start_address), ip_to_int(end_address) + 1):
yield int_to_ip(i)
and just use it
print(list(iter_ip_range("192.168.11.12","192.168.11.22")))

Related

How to remove/exclude unwanted objects from a list in python

Hi I am trying to get the IP of every interface on my machine using netifaces in python. I am still new to python and working my way through some concepts but it seems like I can query every NIC at once and then put the results into a list the problem is my end goal is to ask the user which network to work on and I want to exclude everything that returns 'No IP addr'.
I have already tried a few different methods including removing strings from the list and that didnt work or only adding IP addresses objects but im pretty sure im not doing it properly since it still errors out. Any help is appreciated.
import os
import socket
from netifaces import interfaces, ifaddresses, AF_INET
def get_self_IP():
for ifaceName in interfaces():
addresses = []
possibilities = [i['addr'] for i in ifaddresses(ifaceName).setdefault(AF_INET, [{'addr':'No IP addr'}] )]
print(' '.join(possibilities))
for i in possibilities:
if isinstance(i, ifaddress.ipaddress): # if i is an IP address
addresses.append(i)
print(addresses)
Also I have two lists now because ive changed it a few times to troubleshoot but if I can keep it as one list and only .append the IPs to it while its gathering IPs rather than have to do an entire separate list with a separate for or if loop it would be ideal but I do not know another way unfortunately.
Not sure if this is what you want, but:
I changed the function to:
def get_self_IP():
addresses = []
for ifaceName in interfaces():
ifaddresses_list = ifaddresses(ifaceName)
possibilities = [i['addr'] for i in ifaddresses_list.setdefault(AF_INET, [{'addr': 'No IP addr'}])]
for i in possibilities:
if ifaddresses_list[2][0]['addr'] != "No IP addr":
addresses.append(i)
print(addresses)
The ifaddresses(ifaceName) returns a dictionary which apparently the key 2 contains the IP address in the index 0 with the key 'addr', which in case the IP doesn't exist the value is No IP addr. In that the if checks if that is not the case and then adds the IP address to the addresses list.
If I didn't understand what you want clearly, please answer with more details :)

How to check an IP address is within a predefined list in python

Providing that I have this list which contains a number IP addresses:
IpAddresses = ["192.168.0.1","192.168.0.2","192.168.0.3","192.168.0.4"]
Then after receiving a packet I want to check if its source address is included in the predefined list IpAddresses
data, address = rxsocket.recvfrom(4096)
I have tried two alternatives, but both didn't work:
First:
if (address in IpAddresses):
do something
Then, I tried to convert address into string before making the comparison:
str_address = str(address)
if (str_address in IpAddresses):
do something
I am not familiar with python syntax, so please could you show me how to do this.
if address[0] in IpAddresses:
since the address object appears as a tuple only the 0th index appears in your list so you should check for its existence (also you can usually skip the parenthesis on an if statement unless it makes the if statement less readable)

How do you slice part of an input statement in Python 3?

I have a question which asks me to get a user's email address and then return the URL it is associated with. So, for example: 'abc123#address.com' --> 'http:://www.address.com'
I did get this:
def main():
email_address = input('Enter your email address (eg. abc123#address.com): ').strip()
strip_username = email_address.split('#', 1)[-1]
the_url(strip_username)
def the_url(url_ending):
print('Your associated URL is: http://www.' + str(url_ending))
main()
which does what I want, but this code: split('#'...) is something I haven't learned yet. I just found it online. I need to use indexing and splicing for this program, but how can I use splicing if I don't know the length of the user's email? I need to get rid of everything before and including the '#' symbol so that it can leave me with just 'address.com' but I don't know what address it will be. It could be hotmail, gmail, etc. Thanks, and I'm really new to Python so I'm trying to only use what I've learned in class so far.
The split method just splits up the string based on the character to you give it, so:
"Hello#cat".split("#")
Will give you
["Hello", "cat"]
Then you can just take the 1st index of that array to give you whatever's after the first # symbol.
If you don't want to use str.split then by indexing and slicing,
you can do something like this.
>>> str = 'abc123#address.com'
>>> 'http://www.' + str[str.index('#')+1:]
'http://www.address.com'

Referencing range of IP addresses

I am trying to specify a range of addresses that will be set every time an API is called. For the example below, when api is referenced, I would like it to hosts in the range to a list, and not just one as it currently does.
api = xmlrpclib.ServerProxy("http://user:pass#192.168.0.1:8442/")
Generating the addresses seems straightforward enough, but I am unsure how to store it so that when api is reference, it's sends to every host, e.g. 192.168.0.1 - 192.168.0.100 and not just one.
for i in range(100):
ip = "192.168.0.%d" % (i)
print ip
I would also like to be able to specify the range, e.g. 192.168.0.5 - 192.168.0.50 rather then incrementing from zero.
Update: The API does not handle a list very well so the solution need to be able to parse the list. Might this simply require a second for statement?
If you want a different range:
for i in range(5,51):
ip = "192.168.0.%d" % (i)
print ip
Not sure what you mean by setting multiple. That for loop is doing that for you. If you're talking about saving references of your api, you can also throw those into a list.
api = []
for i in xrange(5,51):
ip = "192.168.0.%d" % (i)
api.append(xmlrpclib.ServerProxy("http://user:pass#" + ip))

Pack array of namedtuples in PYTHON

I need to send an array of namedtuples by a socket.
To create the array of namedtuples I use de following:
listaPeers=[]
for i in range(200):
ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')
ipPuerto.ip="121.231.334.22"
ipPuerto.puerto="8988"
listaPeers.append(ipPuerto)
Now that is filled, i need to pack "listaPeers[200]"
How can i do it?
Something like?:
packedData = struct.pack('XXXX',listaPeers)
First of all you are using namedtuple incorrectly. It should look something like this:
# ipPuerto is a type
ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')
# theTuple is a tuple object
theTuple = ipPuerto("121.231.334.22", "8988")
As for packing, it depends what you want to use on the other end. If the data will be read by Python, you can just use Pickle module.
import cPickle as Pickle
pickledTuple = Pickle.dumps(theTuple)
You can pickle whole array of them at once.
It is not that simple - yes, for integers and simple numbers, it s possible to pack straight from named tuples to data provided by the struct package.
However, you are holding your data as strings, not as numbers - it is a simple thing to convert to int in the case of the port - as it is a simple integer, but requires some juggling when it comes to the IP.
def ipv4_from_str(ip_str):
parts = ip_str.split(".")
result = 0
for part in parts:
result <<= 8
result += int(part)
return result
def ip_puerto_gen(list_of_ips):
for ip_puerto in list_of_ips:
yield(ipv4_from_str(ip_puerto.ip))
yield(int(ip_puerto.puerto))
def pack(list_of_ips):
return struct.pack(">" + "II" * len(list_of_ips),
*ip_puerto_gen(list_of_ips)
)
And you then use the "pack" function from here to pack your structure as you seem to want.
But first, attempt to the fact that you are creating your "listaPiers" incorrectly (your example code simply will fail with an IndexError) - use an empty list, and the append method on it to insert new named tuples with ip/port pairs as each element:
listaPiers = []
ipPuerto=collections.namedtuple('ipPuerto', 'ip, puerto')
for x in range(200):
new_element = ipPuerto("123.123.123.123", "8192")
listaPiers.append(new_element)
data = pack(listaPiers)
ISTR that pickle is considered insecure in server processes, if the server process is receiving pickled data from untrusted clients.
You might want to come up with some sort of separator character(s) for the records and fields (perhaps \0 and \001 or \376 and \377). Then putting together a message is kind of like a text file broken up into records and fields separated by spaces and newlines. Or for that matter, you could use spaces and newlines, if your normal data doesn't include these.
I find this module very valuable for framing data in socket-based protocols:
http://stromberg.dnsalias.org/~strombrg/bufsock.html
It lets you do things like "read up until the next null byte" or "read the next 10 characters" - without needing to worry about the complexities of IP aggregating or splitting packets.

Categories