====================[ Readings ]==================== -----[ 1. TCP extensions. When setting up communications between your host and VM you likely encountered both Window Scaling and SACK. These features are described in RFC 1323 and RFC 2018. Read these RFCs! Note the style in which the RFCs are written, including the use of MUST and SHOULD. These are specifically defined terms for RFCs; see https://www.ietf.org/rfc/rfc2119.txt for their meanings. Note that my hack of copying the options of the TCP SYN packet as received straight into the constructed SYN+ACK is what's enabling us to see these features in action. Were we to reply with a standard option-less SYN+ACK with the standard TCP header of 20 bytes, the host would not use them in the connection, because it would have no assurance that the peer could handle them. But since we echo these options back in the SYN+ACK, the host assumes it is dealing with a modern stack that knows what to do with these options. More details are in http://www.cs.dartmouth.edu/~sergey/cs60/lab4/testing-sliding-window.txt Note that TCP options are designed in such a way that implementations can skip over the options they don't know how to interpret. Each option (excepting the one-byte NOP, used for padding) starts with the type and a length; if the type is not known, the option can still be skipped by skipping the given length of bytes, reaching the following, hopefully known, options. This piece of code illustrates the point: typedef struct { uint8_t kind; uint8_t size; } tcp_option_t; // Parse the RFC 1323 window scale option out of SYN packet, fill in the value. // According to RFC 1323, this option can only appear on the SYN packet. // Return 1 on success, zero on failure. // (cf. http://stackoverflow.com/questions/16519846/parse-ip-and-tcp-header-especially-common-tcp-header-optionsof-packets-capture) int get_window_scale( pkt_t *pkt, int *window ) { uint8_t *opt = (uint8_t*)pkt->tcp + sizeof(struct tcphdr); int found = 0; while( *opt != 0 ) { tcp_option_t* _opt = (tcp_option_t*)opt; if( _opt->kind == TCPOPT_NOP ) { // see netinet/tcp.h ; it's 1 ++opt; // NOP is one byte, this is a special case. Other options have explicit length. continue; } if( _opt->kind == TCPOPT_WINDOW ) { // it's 3 *window = *(opt + 2); // skip past 1-byte kind and 1-byte length; get 1-byte value found = 1; break; } opt += _opt->size; } return found; } The same principle of being able to skip the unknown applies to IPv6 options in IPv6 extension headers. Which brings us to... -----[ 2. IPv6 Extension Headers and Options Read textbook chapter 5.3. -----[ 3. IPv6 practicalities. Observe a machine connected to our Dartmouth's IPv6 network on eth0. It is known as "test6.dartmouth.edu", with the IPv6 address "2604:5f00:ffff:fe00::1:53". test6:~# ifconfig eth0 eth0 Link encap:Ethernet HWaddr b8:27:eb:5a:af:b7 inet6 addr: 2604:5f00:ffff:fe00::1:53/128 Scope:Global inet6 addr: fe80::ba27:ebff:fe5a:afb7/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:13929 errors:0 dropped:0 overruns:0 frame:0 TX packets:15269 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1522547 (1.4 MiB) TX bytes:1737784 (1.6 MiB) Note that there are _two_ IPv6 addresses here, one automatically derived from the MAC and link-scoped, the other assigned. I can add many more, all on the same interface: test6:~# ip -6 addr add 2604:5f00:ffff:fe00::bad:c0de dev eth0 test6:~# ip -6 addr add 2604:5f00:ffff:fe00::101:ca75 dev eth0 test6:~# ip -6 addr add 2604:5f00:ffff:fe00::1337:c0de dev eth0 (yes, I know, encoding words in IPv6 addresses is a bit lame. Still, enjoy http://royal.pingdom.com/2009/02/06/ipv6-playtime-hiding-sentences-inside-addresses/) All of these addresses will become immediately pingable after the router exchanges Neighbor Solicitation/Neighbor Advertisements ICMPv6 packets with the host. E.g., after I do this from another host: sergey@chinaski:~$ ping6 -c3 2604:5f00:ffff:fe00::bad:c0de PING 2604:5f00:ffff:fe00::bad:c0de(2604:5f00:ffff:fe00::bad:c0de) 56 data bytes 64 bytes from 2604:5f00:ffff:fe00::bad:c0de: icmp_seq=2 ttl=54 time=328 ms 64 bytes from 2604:5f00:ffff:fe00::bad:c0de: icmp_seq=3 ttl=54 time=328 ms I see on eth0: test6:~# tcpdump -i eth0 -n tcpdump: WARNING: eth0: no IPv4 address assigned tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 23:23:59.631115 IP6 2604:5f00:ffff:fe00::1 > ff02::1:ffad:c0de: ICMP6, neighbor solicitation, who has 2604:5f00:ffff:fe00::bad:c0de, length 32 ^^^^^^^^^^^^^^^^^ Note the multicast address "ff02::1:ffad:c0de"! IPv6 eliminates broadcasts, as broadcasting for a /64 subnet would mean broadcasting to 2^64 hosts, which is _enormous_. So the router gets the packet and tries to concoct a narrowly matching multicast address. This is called "Solicited-Node Multicast" and uses the prefix of FF02::1:FFxx:yyzz where xx:yyzz are the last 24 bits of the sought host. Incidentally, the Ethernet address on this Solicited Node Multicast is constructed as 33:33:FF:xx:yy:zz, another IPv6 convention aimed at making the request more specific. The router cannot know what the MAC is, but tries to guess---instead of using FF:FF:FF:FF:FF:FF as in IPv4. Note that 33:... still makes the address Ethernet broadcast (the lowest bit of the first byte is set), but more selective. Now Ethernet cards can filter for these constructed addresses for the broadcast solicitations meant for them, and avoid all-or-nothing FF:FF:FF:FF:FF:FF . And my host replied, with Neighbor Advertisement (NA) for the newly assigned address: 23:23:59.631341 IP6 2604:5f00:ffff:fe00::bad:c0de > 2604:5f00:ffff:fe00::1: ICMP6, neighbor advertisement, tgt is 2604:5f00:ffff:fe00::bad:c0de, length 32 23:24:00.637826 IP6 2001:470:23:a02::2 > 2604:5f00:ffff:fe00::bad:c0de: ICMP6, echo request, seq 2, length 64 23:24:00.638040 IP6 2604:5f00:ffff:fe00::bad:c0de > 2001:470:23:a02::2: ICMP6, echo reply, seq 2, length 64 23:24:01.638880 IP6 2001:470:23:a02::2 > 2604:5f00:ffff:fe00::bad:c0de: ICMP6, echo request, seq 3, length 64 23:24:01.639057 IP6 2604:5f00:ffff:fe00::bad:c0de > 2001:470:23:a02::2: ICMP6, echo reply, seq 3, length 64 Note that in the time in took for neighbor discovery (ND) to complete, the first of the ping requests has expired. So it goes. Let's see another ping, for 2604:5f00:ffff:fe00::101:ca75, this time with Ethernet addresses (to showcase Solicited-Node Multicast in Ethernet): test6:~# tcpdump -e -x -i eth0 -n tcpdump: WARNING: eth0: no IPv4 address assigned tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes NOTE the Ethernet address 33:33:ff:01:ca:75 on the NS! 23:42:23.396075 00:26:98:2a:dc:c1 > 33:33:ff:01:ca:75, ethertype IPv6 (0x86dd), length 86: 2604:5f00:ffff:fe00::1 > ff02::1:ff01:ca75: ICMP6, neighbor solicitation, who has 2604:5f00:ffff:fe00::101:ca75, length 32 0x0000: 6c00 0000 0020 3aff 2604 5f00 ffff fe00 0x0010: 0000 0000 0000 0001 ff02 0000 0000 0000 0x0020: 0000 0001 ff01 ca75 8700 6893 0000 0000 0x0030: 2604 5f00 ffff fe00 0000 0000 0101 ca75 0x0040: 0101 0026 982a dcc1 The NA is unicast: 23:42:23.396298 b8:27:eb:5a:af:b7 > 00:26:98:2a:dc:c1, ethertype IPv6 (0x86dd), length 86: 2604:5f00:ffff:fe00::101:ca75 > 2604:5f00:ffff:fe00::1: ICMP6, neighbor advertisement, tgt is 2604:5f00:ffff:fe00::101:ca75, length 32 0x0000: 6000 0000 0020 3aff 2604 5f00 ffff fe00 0x0010: 0000 0000 0101 ca75 2604 5f00 ffff fe00 0x0020: 0000 0000 0000 0001 8800 a26a 6000 0000 0x0030: 2604 5f00 ffff fe00 0000 0000 0101 ca75 0x0040: 0201 b827 eb5a afb7 And ICMPv6 then flows normally: 23:42:24.402051 00:26:98:2a:dc:c1 > b8:27:eb:5a:af:b7, ethertype IPv6 (0x86dd), length 118: 2001:470:23:a02::2 > 2604:5f00:ffff:fe00::101:ca75: ICMP6, echo request, seq 2, length 64 0x0000: 6000 0000 0040 3a38 2001 0470 0023 0a02 0x0010: 0000 0000 0000 0002 2604 5f00 ffff fe00 0x0020: 0000 0000 0101 ca75 8000 8458 52ce 0002 0x0030: 652c 1559 0000 0000 e5ef 0c00 0000 0000 0x0040: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 0x0050: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 0x0060: 3031 3233 3435 3637 23:42:24.402301 b8:27:eb:5a:af:b7 > 00:26:98:2a:dc:c1, ethertype IPv6 (0x86dd), length 118: 2604:5f00:ffff:fe00::101:ca75 > 2001:470:23:a02::2: ICMP6, echo reply, seq 2, length 64 0x0000: 6000 0000 0040 3a40 2604 5f00 ffff fe00 0x0010: 0000 0000 0101 ca75 2001 0470 0023 0a02 0x0020: 0000 0000 0000 0002 8100 8358 52ce 0002 0x0030: 652c 1559 0000 0000 e5ef 0c00 0000 0000 0x0040: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f 0x0050: 2021 2223 2425 2627 2829 2a2b 2c2d 2e2f 0x0060: 3031 3233 3435 3637 More details: http://www.txv6tf.org/wp-content/uploads/2013/07/Martin-IPv6-Multicast-TM-v3.pdf slide 14 A surprising feature of IPv6 is that you can have your default route to the Internet use the link-local automatically assigned address, and it still works! test6:~# route -6 -n | Kernel IPv6 routing table Destination Next Hop Flag Met Ref Use If ::/0 fe80::226:98ff:fe2a:dcc1 UGDAe 1024 0 0 eth0 <--- default route ::/0 This is the default route, obtained from the RAs that my router is sending periodically (or in response to Router Solicitation, RS). It gives the link-scope address of the router's interface facing me, and that address still works. This is a router advertisement that tells my machine what the network's global prefix is, and who the default router is: 00:20:31.197189 00:26:98:2a:dc:c1 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 118: fe80::226:98ff:fe2a:dcc1 > ff02::1: ICMP6, router advertisement, length 64 0x0000: 6c00 0000 0040 3aff fe80 0000 0000 0000 <--- src address ^^^^^^^^^^^^^^^^^^^ 0x0010: 0226 98ff fe2a dcc1 ff02 0000 0000 0000 <--- multicast ff02::1, "for all nodes" ^^^^^^^^^^^^^^^^^^^ ------------------- 0x0020: 0000 0000 0000 0001 8600 af7a 4000 0708 <--- ICMPv6 header, with 3 options ------------------- 0x0030: 0000 0000 0000 0000 0101 0026 982a dcc1 <--- Router's MAC ("Source Link-Layer Address") .... ^^^^^^^^^^^^^^ 0x0040: 0304 40c0 0027 8d00 0009 3a80 0000 0000 <--- ICMPv6 Prefix Information Option 0x0050: 2604 5f00 ffff fe00 0000 0000 0000 0000 <--- ...global network prefix ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x0060: 0501 0000 0000 05dc <--- MTU is 0x5dc == 1500 (normal Ethernet) (byte-for-byte layout: http://www.tcpipguide.com/free/t_ICMPv6RouterAdvertisementandRouterSolicitationMess-2.htm) http://www.tcpipguide.com/free/t_ICMPv6InformationalMessageOptions-2.htm http://www.tcpipguide.com/free/t_ICMPv6InformationalMessageOptions-4.htm http://www.tcpipguide.com/free/t_ICMPv6InformationalMessageOptions-6.htm (these help you make sense of every byte above) -------------------[ IPv6 DNS ]------------------- IPv6 DNS name records have type "AAAA" (they are 4x the size of the IPv4 "A" record) Here is a capture of an external machine executing "dig aaaa puzzle.test6.dartmouth.edu". That query goes to Google's public nameserver 2001:4860:4860::8888, because /etc/resolv.conf on this machine specifies "nameserver 2001:4860:4860::8888". Eventually, it gets the answer "2604:5f00:ffff:fe00::bad:c0de": sergey@chinaski:~$ dig aaaa puzzle.test6.dartmouth.edu ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> aaaa puzzle.test6.dartmouth.edu ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27909 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;puzzle.test6.dartmouth.edu. IN AAAA ;; ANSWER SECTION: puzzle.test6.dartmouth.edu. 86398 IN AAAA 2604:5f00:ffff:fe00::bad:c0de ;; Query time: 1584 msec ;; SERVER: 2001:4860:4860::8888#53(2001:4860:4860::8888) <-- Google's nameserver ;; WHEN: Fri May 12 00:29:11 2017 ;; MSG SIZE rcvd: 72 Google's nameserver performs a recursive query. We can't see that steps of that query, of course, but in the end a query for *.test6.dartmouth.edu must come to my machine, because my machine is the authoritative nameserver for the domain test6.dartmouth.edu, delegated by Dartmouth's nameservers. To wit (+norecurse is important! We want to get what ns1.dartmouth.edu AKA 129.170.17.4 knows regarding the nameserver for my domain; we don't want it to query further): sergey@chinaski:~$ dig @129.170.17.4 +norecurse ns test6.dartmouth.edu ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @129.170.17.4 +norecurse ns test6.dartmouth.edu ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48701 ;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; QUESTION SECTION: ;test6.dartmouth.edu. IN NS ;; AUTHORITY SECTION: test6.dartmouth.edu. 28800 IN NS test6.dartmouth.edu. ;; ADDITIONAL SECTION: test6.dartmouth.edu. 28800 IN AAAA 2604:5f00:ffff:fe00::1:53 <--- my host! ;; Query time: 0 msec ;; SERVER: 129.170.17.4#53(129.170.17.4) ;; WHEN: Fri May 12 00:36:58 2017 ;; MSG SIZE rcvd: 79 So it's my host that gets the request down the chain that Google's nameserver initiates recursively in response to my query. These are the packets that reach it: test6:~# tcpdump -x -i eth0 -n tcpdump: WARNING: eth0: no IPv4 address assigned tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes Some server (2404:6800:4008:c00::104) involved in the recursive lookup chain reaches out to me (and will send this info to whoever queried, it, eventually getting the result back down that chain to Google's NS): 00:40:48.912942 IP6 2404:6800:4008:c00::104.54309 > 2604:5f00:ffff:fe00::1:53.53: 6967 [1au] AAAA? puzzle.test6.dartmouth.edu. (71) 0x0000: 600c ed24 004f 112d 2404 6800 4008 0c00 0x0010: 0000 0000 0000 0104 2604 5f00 ffff fe00 0x0020: 0000 0000 0001 0053 d425 0035 004f 57d5 0x0030: 1b37 0000 0001 0000 0000 0001 0670 757a 0x0040: 7a6c 6505 7465 7374 3609 6461 7274 6d6f 0x0050: 7574 6803 6564 7500 001c 0001 0000 2910 0x0060: 0000 0080 0000 1000 0800 0c00 0240 0020 0x0070: 0104 7000 230a 02 My server replies: 00:40:48.913593 IP6 2604:5f00:ffff:fe00::1:53.53 > 2404:6800:4008:c00::104.54309: 6967*- 1/1/1 AAAA 2604:5f00:ffff:fe00::bad:c0de (119) 0x0000: 6000 0000 007f 1140 2604 5f00 ffff fe00 0x0010: 0000 0000 0001 0053 2404 6800 4008 0c00 0x0020: 0000 0000 0000 0104 0035 d425 007f bc5e 0x0030: 1b37 8400 0001 0001 0001 0001 0670 757a 0x0040: 7a6c 6505 7465 7374 3609 6461 7274 6d6f 0x0050: 7574 6803 6564 7500 001c 0001 c00c 001c 0x0060: 0001 0001 5180 0010 2604 5f00 ffff fe00 0x0070: 0000 0000 0bad c0de c013 0002 0001 0003 0x0080: f480 0007 0161 026e 73c0 13c0 5400 1c00 0x0090: 0100 0151 8000 1026 045f 00ff fffe 0000 0x00a0: 0000 0000 0100 53 The request is actually duplicated with different options, and the duplicate arrives too: 00:40:49.913373 IP6 2404:6800:4008:c00::104.41204 > 2604:5f00:ffff:fe00::1:53.53: 17407 [1au] AAAA? puzzle.test6.dartmouth.edu. (55) 0x0000: 6002 4ff8 003f 112c 2404 6800 4008 0c00 0x0010: 0000 0000 0000 0104 2604 5f00 ffff fe00 0x0020: 0000 0000 0001 0053 a0f4 0035 003f 1ecd 0x0030: 43ff 0000 0001 0000 0000 0001 0670 757a 0x0040: 7a6c 6505 7465 7374 3609 6461 7274 6d6f 0x0050: 7574 6803 6564 7500 001c 0001 0000 2910 0x0060: 0000 0080 0000 00 ... and is answered the same way as before: 00:40:49.914367 IP6 2604:5f00:ffff:fe00::1:53.53 > 2404:6800:4008:c00::104.41204: 17407*- 1/1/1 AAAA 2604:5f00:ffff:fe00::bad:c0de (119) 0x0000: 6000 0000 007f 1140 2604 5f00 ffff fe00 0x0010: 0000 0000 0001 0053 2404 6800 4008 0c00 0x0020: 0000 0000 0000 0104 0035 a0f4 007f c6c7 0x0030: 43ff 8400 0001 0001 0001 0001 0670 757a 0x0040: 7a6c 6505 7465 7374 3609 6461 7274 6d6f 0x0050: 7574 6803 6564 7500 001c 0001 c00c 001c 0x0060: 0001 0001 5180 0010 2604 5f00 ffff fe00 ^^^^^^^^^^^^^^^^^^^ 0x0070: 0000 0000 0bad c0de c013 0002 0001 0003 ^^^^^^^^^^^^^^^^^^^ 0x0080: f480 0007 0161 026e 73c0 13c0 5400 1c00 0x0090: 0100 0151 8000 1026 045f 00ff fffe 0000 ^^^^^^^^^^^^^^^^^^^^^^ 0x00a0: 0000 0000 0100 53 ^^^^^^^^^^^^^^^^^ Parse these packets to see the structure of the answer! Hint: IPv6 addresses are really easy to spot in packet hex dumps! Finally, who is "2404:6800:4008:c00::104"? We can get a reverse (PTR) query: test6:~$ dig -x 2404:6800:4008:c00::104 ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> -x 2404:6800:4008:c00::104 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 6431 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;4.0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.c.0.8.0.0.4.0.0.8.6.4.0.4.2.ip6.arpa. IN PTR ;; AUTHORITY SECTION: 4.0.0.8.6.4.0.4.2.ip6.arpa. 60 IN SOA ns4.google.com. dns-admin.google.com. 155820102 900 900 1800 60 ;; Query time: 369 msec ;; SERVER: 129.170.212.67#53(129.170.212.67) ;; WHEN: Fri May 12 00:50:24 2017 ;; MSG SIZE rcvd: 150 Notice the insanely long name used in PTR lookup! There are 16 bytes == 32 hex digits in an IPv6 address. So the pseudo-name for the reverse lookup is 32 levels deep, one level for each hex digit! In the end, this ends up being a lowly unnamed server within Google's domain. The reverse lookup fails with NXDOMAIN, and is authoritative for "4.0.0.8.6.4.0.4.2.ip6.arpa." that is 2404:6800:4xxx:... -------------------[ Teredo tunnels ]------------------- Teredo tunneling was Microsoft's project for getting globally routable IPv6 addresses for all Windows machines connected over IPv4, whether or not they were behind a NAT. A Teredo connection would poll a remote server periodically for any incoming traffic, thus making it appear to the NAT that it was an outgoing connection; but it would actually pull in incoming data for the global address in 2001:0000:/32 range that remained viable so long as the machine was connected. Teredo caused quite a scare among network security folks who considered their NATs impenetrable, and their machines behind these NATs to be unreachable to outside hosts unless they reached out to these hosts first. For a sketch of Teredo, see https://en.wikipedia.org/wiki/Teredo_tunneling My log from running a free client for the Teredo protocol, called Miredo, on a Mac is here: http://www.cs.dartmouth.edu/~sergey/cs60/miredo-notes.txt In your Linux VM, it's MUCH simpler. You just get miredo with "apt-get install miredo" and then you are up and running; ping6 of Google's 2001:4860:4860::8888 and of my 2604:5f00:ffff:fe00::1:53 should just work. ifconfig will show you a new interface called "teredo", and the IP address of this interface should be reachable from the outside! root@cs60base:~/lab4# ifconfig teredo Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 inet6 addr: 2001:0:53aa:64c:241f:5d99:b7a0:89d3/32 Scope:Global inet6 addr: fe80::e597:7efd:18ca:911a/64 Scope:Link inet6 addr: fe80::ffff:ffff:ffff/64 Scope:Link UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1280 Metric:1 RX packets:4 errors:0 dropped:0 overruns:0 frame:0 TX packets:7 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:500 RX bytes:416 (416.0 B) TX bytes:560 (560.0 B) With miredo running and the "teredo" virtual interface up, I can ping outside IPv6 addresses: root@cs60base:~# ping6 2604:5f00:ffff:fe00::1:53 PING 2604:5f00:ffff:fe00::1:53(2604:5f00:ffff:fe00::1:53) 56 data bytes 64 bytes from 2604:5f00:ffff:fe00::1:53: icmp_seq=1 ttl=57 time=412 ms 64 bytes from 2604:5f00:ffff:fe00::1:53: icmp_seq=2 ttl=57 time=112 ms ^C --- 2604:5f00:ffff:fe00::1:53 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms rtt min/avg/max/mdev = 112.070/262.297/412.524/150.227 ms But that's easy; pinging from behind a NAT is old hat. But now I can ping back from 2604:5f00:ffff:fe00::1:53, too! test6:~# ping6 2001:0:53aa:64c:241f:5d99:b7a0:89d3 PING 2001:0:53aa:64c:241f:5d99:b7a0:89d3(2001:0:53aa:64c:241f:5d99:b7a0:89d3) 56 data bytes 64 bytes from 2001:0:53aa:64c:241f:5d99:b7a0:89d3: icmp_seq=1 ttl=58 time=237 ms 64 bytes from 2001:0:53aa:64c:241f:5d99:b7a0:89d3: icmp_seq=2 ttl=58 time=116 ms 64 bytes from 2001:0:53aa:64c:241f:5d99:b7a0:89d3: icmp_seq=3 ttl=58 time=218 ms ^C And in my VM I observe: root@cs60base:~/lab4# tcpdump -i eth0 -n tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 01:59:21.868818 IP 216.66.77.226.41148 > 192.168.56.100.36522: UDP, length 104 01:59:22.789576 IP 216.66.77.226.41148 > 192.168.56.100.36522: UDP, length 104 01:59:22.789801 IP 192.168.56.100.36522 > 216.66.77.226.41148: UDP, length 104 01:59:24.019755 IP 216.66.77.226.41148 > 192.168.56.100.36522: UDP, length 104 01:59:24.019917 IP 192.168.56.100.36522 > 216.66.77.226.41148: UDP, length 104 01:59:24.941267 IP 216.66.77.226.41148 > 192.168.56.100.36522: UDP, length 104 01:59:24.941472 IP 192.168.56.100.36522 > 216.66.77.226.41148: UDP, length 104 ^C 9 packets captured 9 packets received by filter 0 packets dropped by kernel These are the Teredo packets coming in and out from the miredo's remote server, 216.66.77.226 . They wrap the IPv6 echo request and echo reply packets. The miredo process unwraps these packets, and makes them appear to the Linux kernel as coming in on the "teredo" virtual interface, as if that interface connected directly to an IPv6 network: root@cs60base:~/lab4# tcpdump -i teredo -n tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on teredo, link-type RAW (Raw IP), capture size 262144 bytes 01:59:40.096176 IP6 2604:5f00:ffff:fe00::1337:c0de > 2001:0:53aa:64c:241f:5d99:b7a0:89d3: ICMP6, echo request, seq 30, length 64 01:59:40.096199 IP6 2001:0:53aa:64c:241f:5d99:b7a0:89d3 > 2604:5f00:ffff:fe00::1337:c0de: ICMP6, echo reply, seq 30, length 64 01:59:41.017806 IP6 2604:5f00:ffff:fe00::1337:c0de > 2001:0:53aa:64c:241f:5d99:b7a0:89d3: ICMP6, echo request, seq 31, length 64 01:59:41.017824 IP6 2001:0:53aa:64c:241f:5d99:b7a0:89d3 > 2604:5f00:ffff:fe00::1337:c0de: ICMP6, echo reply, seq 31, length 64 01:59:42.041215 IP6 2604:5f00:ffff:fe00::1337:c0de > 2001:0:53aa:64c:241f:5d99:b7a0:89d3: ICMP6, echo request, seq 32, length 64 01:59:42.041234 IP6 2001:0:53aa:64c:241f:5d99:b7a0:89d3 > 2604:5f00:ffff:fe00::1337:c0de: ICMP6, echo reply, seq 32, length 64 ^C Note that my external machine chose to use the "2604:5f00:ffff:fe00::1337:c0de" address I added on its eth0 for the outgoing packets' source IPv6 address. Suggestion: install Miredo and ping Google's DNS servers and other IPv6 targets to see that you got real IPv6 connectivity. -------------------[ Virtual interfaces and VPNs ]------------------- Miredo makes use of a virtual network interface called TUN/TAP. On the Mac, it is provided by the MacOS kernel extension ("kext"), known outside of the Apple world as a driver. Such _virtual interfaces_ play a huge role in enterprise VPNs that are getting ever so more common on the Internet. We'll cover them next. I wrote a small demo of what a simple python script behind such an interface can do: https://github.com/sergeybratus/netfluke . More info in http://www.cs.dartmouth.edu/~sergey/netreads/task3.txt