Search code examples
python-2.7sslpyopenssl

Connecting to an ipv6 ssl server using pyopenssl


I need to connect to ipv6 server using pyopenssl .Is that even possible?For ipv4 i don't have any problem.This is what i'v tried for ipv6:

ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_verify(SSL.VERIFY_NONE, verify_cb)
ctx.use_privatekey_file (os.path.join(dir, 'client.pkey'))
ctx.use_certificate_file(os.path.join(dir, 'client.cert'))
ctx.load_verify_locations(os.path.join(dir, 'CA.cert'))
#Set up client
sock = SSL.Connection(ctx, socket.socket(socket.AF_INET6, socket.SOCK_STREAM))
sock.connect(('fe80::3a63:bbff:fe31:3013%ens32',443,0,0))

But i'm getting the following error:

sock.connect(('fe80::3a63:bbff:fe31:3013%ens32',443,0,0))
  File "/root/Desktop/PY/ilodos2/venv/lib/python2.7/site-packages/OpenSSL/SSL.py", line 1455, in connect
    return self._socket.connect(addr)
  File "/usr/lib64/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
error: [Errno 22] Invalid argument

The documentation of pyopenssl does not talk about ipv6 at all. If pyopenssl cant be used for ipv6, are there any other modules using which i can do ssl renegotiation?


Solution

  • The problem itself isn't really related to PyOpenSSL, when you're using scoped (link local) ipv6 addresses you neeed to pass the correct scopeid as the fourth item of the address tuple:

    ...
    For AF_INET6 address family, a four-tuple (host, port, flowinfo, scopeid) is used, where flowinfo and scopeid represent the sin6_flowinfo and sin6_scope_id members in struct sockaddr_in6 in C. For socket module methods, flowinfo and scopeid can be omitted just for backward compatibility. Note, however, omission of scopeid can cause problems in manipulating scoped IPv6 addresses.

    Consult ip addr to show the correct numerical scope id, e.g. with scopeid 2 for ens32 the following should work:

    sock.connect(('fe80::3a63:bbff:fe31:3013%ens32', 443, 0, 2))
    

    Or use getaddrinfo() to get the correct address:

    ainfo = socket.getaddrinfo('fe80::3a63:bbff:fe31:3013%ens32', 443, socket.AF_INET6, socket.SOCK_STREAM)
    address = ainfo[0][4]