Using GPy with IPv6
-
Has anyone prior experience with using GPy over IPv6 NB-IoT networks? Our local MNO supports only IPV6 and I am able to attach to the network using the following code snippet:
from network import LTE lte = LTE() lte.init() lte.send_at_cmd('AT+CFUN=0') lte.send_at_cmd('AT+CGDCONT=1,"IPV6","iot"') lte.send_at_cmd('AT+CFUN?') lte.send_at_cmd('AT+CFUN=1') lte.send_at_cmd('AT+CFUN?') lte.send_at_cmd('AT+CREG?')
However I am not sure how I can establish UDP socket communication. I checked the Sequans modem manual for IPv6 data transmission support. When creating a new socket through the
AT+SQNSD
command the remote IP address should be configured as follows:IPaddr String type. Address of the remote host. Any valid IP address in the format “xxx.xxx.xxx.xxx” or any host name solved with a DNS query.
So this means that only IPv4 addresses are supported?
Is also anyone aware of native IPv6 support for the WLAN/LTE classes of pycom? I guess not?
Thanks!
-
Just an update of the latest changes. The API of the microATsocket has changed to be closer to the typical usocket API. Also a custom version of getaddrinfo info has been implemented, so the code now looks somehting like:
import microATsocket as socket from network import LTE import binascii lte = LTE() # attach to network # ... #message as bytes data = bytearray('{data:"testmessage"}') # create socket instance providing the instance of the LTE modem sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) sock.setModemInstance(lte) # getaddrinfo needs to be called on the instance of socket resolvedIPs = sock.getaddrinfo("google.com", 5683) # send data to specific IP (dummy IP and port used as example) sock.sendto(data, resolvedIPs[0][-1]) # receive data from the previously used IP. # socket is still open from the 'sendto' operation (resp, address) = sock.recvfrom(1024) print("Response: from ip:" + address[0] + ", port: " + str(address[1]) + ", data: " + str(binascii.hexlify(bytearray(resp))))
-
@kjm you are correct, a URL can resolve to multiple IPs and yes, a getaddrinfo lookup is needed.
Since getaddrinfo lookup is a DNS request, I have created an example code on how to do it over the UDP socket.
The example uses https://github.com/insighio/DNS-Client to form and decode the DNS request/response along with the custom MicroATSocket socket.socket = MicroATSocket(lte) url='google.com' dns_server="2001:4860:4860::8888" ipv6_only = True resolvedIPs = dns_query.dns_resolve(socket, url, dns_server, ipv6_only) print("Resolved IP list: " + str(resolvedIPs)) data = bytearray('{data:"testmessage"}') socket.sendto(data, (resolvedIPs[0], 8888)) (resp, address) = socket.recvfrom() print("Response: from ip:" + address[0] + ", port: " + str(address[1]) + ", data: " + str(binascii.hexlify(bytearray(resp)))) socket.close()
Since Google's DNS server IP is fixed, it can be used directly. If DNS resolve is successful, a list of IPs will be returned. Pick any of the returned IPs and you are ready to transfer your data.
Full source code can be found: here
-
@nftylitak thnx heaps for doing that. I seem to be confused re IPV6. I thought is was a scheme that would allow each iot mote to have its own unique address & free us from the tyranny of dns lookups. But when I check the IPv6 address of a random website, say detectportal.firefox.com, I find it has more than one IPv6 address. Which makes me think IPv6 addresses are going to be just as fluid as IPV4, which means some sort of getaddrinfo style lookup will still be required?
nslookup detectportal.firefox.com Non-authoritative answer: Name: a1089.dscd.akamai.net Addresses: 2407:8800:bf00:145::cb57:7a19 2407:8800:bf00:145::cb57:7a2b 23.212.98.59 202.7.177.35 Aliases: detectportal.firefox.com detectportal.prod.mozaws.net detectportal.firefox.com-v2.edgesuite.net
-
@kjm I have added the socket implementation to a separate repo to be easier to use.
You can find the report in GitHub: microATsocket for more examples and special features.
A quick example would be the following:
from microATsocket import MicroATSocket from network import LTE import binascii lte = LTE() # attach to network # ... #message as bytes data = bytearray('{data:"testmessage"}') # create socket instance providing the instance of the LTE modem socket = MicroATSocket(lte) # send data to specific IP (dummy IP and port used as example) socket.sendto(data, ("2001:4860:4860::8888", 8888)) # receive data from the previously used IP. # socket is still open from the 'sendto' operation (resp, address) = socket.recvfrom() print("Response: from ip:" + address[0] + ", port: " + str(address[1]) + ", data: " + str(binascii.hexlify(bytearray(resp)))) # close socket socket.close()
The feedback is always welcomed.
-
@kjm today I will create some examples and get back to you within the day.
-
@nftylitak Are you able to post an example of how to use that wrapper socket?
-
Greetings,
@agotsis your example indeed works for IPv6, so based on your code I have made a wrapper "socket" based on AT commands for GPy. The tricky part was that through AT+SQNSSEND, I could not send bytes, so it needed special care.
The socket can be found through this link in the hope that it will save time to others: https://github.com/insighio/microCoAPy/blob/master/examples/pycom/nbiot/pycom_at_socket.py
-
I'm salivating in anticipation! It would be so nice to ditch that useless, untimeoutable, getaddrinfo dns lookup with a move to IPV6.
-
A small update: It seems that the
AT+SQNSD
is also acceptingIPv6
target addresses. I managed to send a UDP message from GPy to an IPv6 address, using the following snippet:lte.send_at_cmd('AT+SQNSD=1,1,<targetPort>,"XXXX:XXX:XXXX:XX:XXXX:XXX:XXX:XXXX",0,0,1') lte.send_at_cmd('AT+SQNSSEND=1') lte.send_at_cmd('hello\x1A') lte.send_at_cmd('AT+SQNSH=1')
However
usocket
is not able to handle IPv6 (see for example in [1] and [2]), so native support is yet available.