what exactly is passed as "address" in sendto for ipv6
Question: I am trying to send an **icmpv6 ping packet** across running as root (python
2.7 on Linux)

I understand that **sendto** uses two tuple struct in case of ipv4 (and it
works) and know that ipv6 uses a 4 tuple struct. Still i can't get it to work.

It either results in an _"invalid argument"_ or _"socket.gaierror: [Errno -2]
Name or service not known"_

Following is a bare minimum example showing what i am attempting. I am even
fine if i can get it to work with local host in case of ipv6 i.e. ::1

    
    
    import socket
    
    def main(dest_name):
        #dest_addr = socket.gethostbyname(dest_name)
        addrs = socket.getaddrinfo(dest_name, 0, socket.AF_INET6, 0, socket.SOL_IP)
    
        print addrs
        dest = addrs[2]
    
        port = 33434 # just some random number because of icmp
        icmp = socket.getprotobyname('ipv6-icmp')
        #print icmp
    
        send_socket = socket.socket(socket.AF_INET6, socket.SOCK_RAW, icmp)
        print "sent to " + str(dest[4])
        send_socket.sendto('', (str(dest[4]), port))
        send_socket.close()
    
    if __name__ == '__main__':
        main('ipv6.google.com')
    

I actually tried each tuple from the addr list, but the result is same.

**Update:**

Also tried alternates with sendto's params, but it results in invalid
arguments whether i use local host or google ipv6 address

    
    
    send_socket.sendto('', dest[4])
    

**Update 2:**

For reference, working ipv4 code follows (as asked in comments)

    
    
    def main(dest_name):
        dest_addr = socket.gethostbyname(dest_name)
        icmp = socket.getprotobyname('icmp')
    
        send_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
        print "sent to " + dest_name#str(dest[4])
        send_socket.sendto('', (dest_addr, 0))
        send_socket.close()
    
    if __name__ == '__main__':
        main('www.google.com')
    

**Update 3:**

When i run the v6 version with dest[4] as the only parameter (no string, just
the tuple and NO port), following is output on my machine (Mint 15) which
includes printing interfaces

    
    
    sudo python test_v6.py 
    [(10, 1, 6, '', ('::1', 0, 0, 0)), (10, 2, 17, '', ('::1', 0, 0, 0)), (10, 3, 0, '', ('::1', 0, 0, 0))]
    sent to ('::1', 0, 0, 0)
    Traceback (most recent call last):
      File "test_v6.py", line 18, in <module>
        main('::1')
      File "test_v6.py", line 14, in main
        send_socket.sendto('', dest[4])
    socket.error: [Errno 22] Invalid argument
    

I am not sure why it still produces invalid argument


Answer: Your original problem was that bizarre things like a 2-tuple whose first
member is a Python string representation of the 4-tuple address are not even
close to valid ways to specify an address.

You can fix that by just using `dest[4]` itself—that is, the tuple you got
back as the sockaddr part of `getaddrinfo`—as the address. (As Sander
Steffann's answer explains, you're not exactly doing this cleanly. But in your
case, at least for `'::1'` or `'localhost'` with the other values you've
specified, you're going to get back the right values to use.) You should also
probably use `addrs[0]` rather than `addrs[2]`.

Anyway, in your **Update 3** , you appear to have done exactly that, and
you're getting `socket.error: [Errno 22] Invalid argument`. But there are
_two_ arguments to `sendto`, and it's the _other_ one that's invalid: `''` is
not a valid ICMP6 packet because it has no ICMP6 header.

You can test this pretty easily by first `connect`ing to `dest[4]`, which will
succeed, and then doing a plain `send`, which will fail with the same error.

For some reason, on Fedora 10 (ancient linux), the call seems to succeed
anyway. I don't know what goes out over the wire (if anything). But on Ubuntu
13.10 (current linux), it fails with `EINVAL`, exactly as it should. On OS X
10.7.5 and 10.9.0, it fails with `ENOBUFS`, which is bizarre. In all three
cases, if I split the `sendto` into a `connect` and a `send`, it's the `send`
that fails.

`'\x80\0\0\0\0\0\0\0'` is a valid ICMP6 packet (an Echo service request header
with no data). If I use that instead of your empty string, it now works on all
four machines.

(Of course I still get `ENETUNREACH` or `EHOSTUNREACH` when I try to hit
something on the Internet, because I don't have an IPv6-routable connection.)

