congratulations! you may already be an ipv6 network ... · why is your home network secure? •...
TRANSCRIPT
Congratulations! You may already be an
IPv6 Network Operator or Developer!
Darrell [email protected]
https://networkmom.net
RFC: “Request for comments”
• Internet standards documents from the Internet Engineering Task Force
• https://ietf.org/standards/rfcs/
• Could be “standards track”, “best current practice”, “informational”, “experimental”, or “historic”
Jon Postel 1943-1998: RFC Editor during the
Internet’s development
Why is your home network secure?
• Your IPv4 network uses NAT
• Internal network uses RFC1918 address space
• Not possible to directly connect from Internet to 192.168.0.22 port 22
• Netgear does not know where to forward ingress connections unless you configure “port forwarding”
Internet
192.168.0.22/24 192.168.0.32
24.130.70.242/21
192.168.0.1/24
I have news!
• Most home networks have IPv6 connectivity (DOCSIS* 3.0+ cable modem required)
• They use internet-routable IPv6 space!
• What prevents inbound SSH connections?
Internet
2001:db8:4802:1620:c71:2af2:75d7:2add
2001:db8:6045:a0:31bd:f2f9:3c3f:c0e8
2001:db8:4802:1620:b27f:b9ff:fe5d:8ed2
* Data Over Cable Service Interface Specification
Netgear C7000-100NAS enables IPv6 stateful firewall by default
Special IPv4 addresses10.0.0.0 - 10.255.255.255
172.16.0.0 - 172.31.255.255 192.168.0.0 - 192.168.255.255
Private address space RFC1918
127.0.0.0 - 127.255.255.255(usually 127.0.0.1) Loopback Addresses RFC5735
169.254.0.0 - 169.254.255.255 Link Local RFC5735
192.0.2.0 - 192.0.2.255 Documentation RFC5735
224.0.0.0 - 239.255.255.255 Multicast RFC3171
255.255.255.255 Limited broadcast RFC919/922
Reminder: IPv4 address is just 32 bits
192.168.47.131
11000000.10101000.00101111.10000011
11000000101010000010111110000011
C0.A8.2F.83
IPv6 address is 128 bits2001:db8:4802:1620:c71:2af2:75d7:2add
00100000000000010000110110111000010010000000001000010110001000000000110001110001001010101111001001110101110101110010101011011101
Eight hextets, each consisting of 16 bits or 4 nibbles
But why do some hextets above have only 3 characters?
IPv6 address shortening rules (RFC4291)
1. Remove leading zeros in each hextet, but leave at least one numeral in each hextet
2. Replace consecutive :0: hextets with :: but only once per IPv6 address
2001:0db8:0032:0000:0000:5bf0:0000:8f8a2001:db8:32:0:0:5bf0:0:8f8a
2001:db8:32::5bf0:0:8f8a
IPv6 address lengthening rules
1. Prepend zeros in each hextet until each hextet has 4 digits
2. Expand :: into sufficient :0000: hextets resulting in a total of eight hextets
2001:db8:32::5bf0:0:8f8a2001:0db8:0032::5bf0:0000:8f8a
2001:0db8:0032:0000:0000:5bf0:0000:8f8a
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/16 /32 /48 /64 /128 (easy)/8 /44 /52 /60 (medium)
/43 /45 /50 /62 /63 (hard)
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/64
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/64
2345:6789:abcd:ef01::/64Includes IPv6 addresses in this range:2345:6789:abcd:ef01:0000:0000:0000:00002345:6789:abcd:ef01:ffff:ffff:ffff:ffff
1 Subnet
2345:6789:abcd:ef01:0000:0000:0000:0000/64
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/48
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/48
2345:6789:abcd::/48Includes IPv6 addresses in this range:2345:6789:abcd:0000:0000:0000:0000:00002345:6789:abcd:ffff:ffff:ffff:ffff:ffff
65536 subnets
2345:6789:abcd:0000:0000:0000:0000:0000/48
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/8
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/8
23::/8 is wrong! That would mean 0023::/82300::/8 is correct
Includes IPv6 addresses in this range:2300:0000:0000:0000:0000:0000:0000:000023ff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
2300:0000:0000:0000:0000:0000:0000:0000/8
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/31
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/31Last hex digit of 2nd hextet is 0x9
Binary equivalent is 1001Slicing off last bit is 1000 = 0x8
2345:6788::/31Includes IPv6 addresses in this range:2345:6788:0000:0000:0000:0000:0000:00002345:6789:ffff:ffff:ffff:ffff:ffff:ffff
2345:6788:0000:0000:0000:0000:0000:0000/31
Many more address prefix drills in appendix
The presentation will be at the meetup forums for Bay LISA
IPv6 address types (www.iana.org)
2000::/3 (binary starts with 001)(first digit 2 or 3)
Assignable global Unicast
fc00::/7(most use starts with fd**:)
Unique local unicast
fe80:0:0:0::/64*(fe80::/10 reserved)
Link local unicast
ff00::/8 (starts ff**:) multicast
::1 Loopback
2001:0db8::/32 Documentation
IPv6 prefix sizes/32 65536 sites each with
/48
/48 65536 subnets each of size /64
/64 One subnet with 16 billion billion hosts
/127 Used by network engineers for p2p links
/128 Single addressRouter loopback interface
2001:0db8:SITE:SUBNET:HOST:HOST:HOST:HOST
Last 4 hextets / 64 bits are often called “interface identifier”
IPv6 prefixes 2001:0db8:0032:48c3:4f21:5bfe:3f2d:8f8a
2001:0db8::/32Typical small ISP allocation
or large enterprise allocation
2001:0db8:0032::/48 Typical allocation for small enterprise or building
2001:0db8:0032:48c3::/64 Typical subnet
Unique Local Addresses (RFC4193)
• First two nibbles (8 bits) are FD. (FC00::/8 also unique-local)
• Pick the next 40 bits randomly
• This gives you a “likely to be unique” /48 for your site to use.
• Randomly generated example: fdf3:ec00:6668::/48
• https://www.ultratools.com/tools/rangeGenerator
• This is an advantage over RFC1918 IPv4 addresses: when two companies merge, their RFC1918 addresses commonly overlap.
• IPv6 NAT-capable network equipment is rare!If you need occasional Internet use routable addresses!
Home network revisited• Not unique local (prefix not fc00::/8
or fd00::/8
• Not link-local (prefix not fe80:0:0:0:)
• Inside 2000::/3 “assignable global unicast” address range
• I am using the “2001:0db8::/32” documentation prefix.
Internet
2001:db8:4802:1620:c71:2af2:75d7:2add
2001:db8:6045:a0:31bd:f2f9:3c3f:c0e8
2001:db8:4802:1620:b27f:b9ff:fe5d:8ed2
MacOS: System Preferences -> Network -> (select interface) -> Advanced -> TCP/IP
Does not include link-local!
iOS: Settings -> Wi-Fi -> click ℹ ⃝ -> scroll down
Does not include link-local!
% ifconfig en0en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=50b<RXCSUM,TXCSUM,VLAN_HWTAGGING,AV,CHANNEL_IO>ether 68:5b:35:89:0a:04 inet6 fe80::8f0:afb2:bdf0:7bde%en0 prefixlen 64 secured scopeid 0x5 inet 192.168.0.10 netmask 0xffffff00 broadcast 192.168.0.255inet6 2001:db8:4802:1620:c4:a57:8f22:1d81 prefixlen 64 autoconf secured inet6 2001:db8:4802:1620:1914:17b5:aaf1:4e5a prefixlen 64 deprecated autoconf temporary inet6 2001:db8:4802:1620:2c09:a14c:6890:19d0 prefixlen 64 autoconf temporary nd6 options=201<PERFORMNUD,DAD>media: autoselect (1000baseT <full-duplex,flow-control,energy-efficient-ethernet>)status: active
% ifconfig en0
inet6 fe80::8f0:afb2:bdf0:7bde%en0 prefixlen 64 secured scopeid 0x5
inet6 2001:db8:4802:1620:c4:a57:8f22:1d81 prefixlen 64 autoconf secured
inet6 2001:db8:4802:1620:1914:17b5:aaf1:4e5a prefixlen 64 deprecated autoconf temporary inet6 2001:db8:4802:1620:2c09:a14c:6890:19d0 prefixlen 64 autoconf temporary
TCP/IP Stack Review
source: http://www.softpanorama.org/Net/Images/tcp_ip_layers.gif
Ethernet frame format
source: http://cs.uccs.edu/~cs522/msgformat/hw1_ht1.gif
Ethernet frame type 0x0800=IPv4Ethernet frame type 0x86DD=IPv6
RFC793
IPv4 vs IPv6 header format:20-60 bytes versus 40 bytes
(source: h3c.com)
No variable header lengths! No L3 checksums! No hop-by-hop checksum updates! No hop-by-hop fragmentation!
IPv6 extension headers (source www.cisco.com)
Warning: RFC7872 reports 10%-50% of Internet destinations drop packets with some types of extension headers.
DNS Basics• A-record maps a domain-name to an IPv4 address
• AAAA-record maps a domain-name to an IPv6 address
• CNAME maps a “domain name” to another “domain name” (alias)
% host www.cnn.com www.cnn.com is an alias for turner-tls.map.fastly.net. turner-tls.map.fastly.net has address 151.101.189.67 turner-tls.map.fastly.net has IPv6 address 2a04:4e42:2d::323
IPv6 APIs
• MacOS Swift/Objective-C URLSession
• MacOS Swift/Objective-C Network
• MacOS Swift/Objective-C CFSocket
• (Oracle) Java URL API (on MacOS)
• (Oracle) Java Socket API (on MacOS)
• (Oracle) Java Server-socket API (on MacOS)
• Homework
More complete source code in appendix
Paul Hudson: www.hackingwithswift.com “100 days of Swift / SwiftUI”
URLSession API (also available in Objective-C)
let url = URL(string: “https://www.hackingwithswift.com/samples/friendface.json”)!
URLSession.shared.dataTask(with: URLRequest(url: url)) { data, response, error in if let data = data { if let decodedResponse = try? JSONDecoder().decode([User].self, from: data){ DispatchQueue.main.async { self.users = decodedResponse } return } } }.resume()
~ % host www.hackingwithswift.com www.hackingwithswift.com has address 178.79.182.10 www.hackingwithswift.com has IPv6 address 2a01:7e00::f03c:91ff:fe2e:1654
Part 1: DNS requests, responses, TCP-SYN
% sudo tcpdump host 178.79.182.10 or 2a01:7e00::f03c:91ff:fe2e:1654
14:17:36.948063 IP6 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49821 > 2001:558:feed::1.53: 13644+ AAAA? www.hackingwithswift.com.
14:17:36.948136 IP6 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.65468 > 2001:558:feed::1.53: 63139+ A? www.hackingwithswift.com.
14:17:36.966276 IP6 2001:558:feed::1.53 > 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49821: 13644 1/0/0 AAAA 2a01:7e00::f03c:91ff:fe2e:1654
14:17:36.980634 IP6 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49589 > 2a01:7e00::f03c:91ff:fe2e:1654.443: Flags [S], seq 2968916496, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 1458429152 ecr 0,sackOK,eol], length 0
14:17:37.019043 IP6 2001:558:feed::1.53 > 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.65468: 63139 1/0/0 A 178.79.182.10
14:17:37.085123 IP 192.168.0.22.49590 > 178.79.182.10.443: Flags [S], seq 1030969591, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1458429256 ecr 0,sackOK,eol], length 0
Part 2: TCP SYN complete, data flow over IPv6, IPv4 socket reset
14:17:37.124348 IP6 2a01:7e00::f03c:91ff:fe2e:1654.443 > 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49589: Flags [S.], seq 743955647, ack 2968916497, win 28560, options [mss 1440,sackOK,TS val 3277029686 ecr 1458429152,nop,wscale 7], length 0
14:17:37.124398 IP6 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49589 > 2a01:7e00::f03c:91ff:fe2e:1654.443: Flags [.], ack 1, win 2052, options [nop,nop,TS val 1458429295 ecr 3277029686], length 0
14:17:37.127902 IP6 2001:db8:4802:1620:d97b:d0a7:bf39:6d2.49589 > 2a01:7e00::f03c:91ff:fe2e:1654.443: Flags [P.], seq 1:518, ack 1, win 2052, options [nop,nop,TS val 1458429298 ecr 3277029686], length 517
14:17:37.234613 IP 178.79.182.10.443 > 192.168.0.22.49590: Flags [S.], seq 20673728, ack 1030969592, win 28960, options [mss 1460,sackOK,TS val 1850566449 ecr 1458429256,nop,wscale 7], length 0
14:17:37.234651 IP 192.168.0.22.49590 > 178.79.182.10.443: Flags [R], seq 1030969592, win 0, length 0
let serverEndpoint = NWEndpoint.Host("swiftbysundell.net") let portEndpoint = NWEndpoint.Port(rawValue: 80)! connection = NWConnection(host: serverEndpoint, port: portEndpoint, using: .tcp)
connection.start(queue: self.queue) connection.send(content: sendData, completion: .contentProcessed({ (error) in
connection.receive(minimumIncompleteLength: 1, maximumLength: 8192) { (content, context, isComplete, error) in
Swift/Objective-C Network framework (selected) Also accessible from Objective-C
% sudo tcpdump port 80
2001:db8:4802:1620:c194:8573:68fe:835e.52327 > 2606:4700:20::681a:f74.http: Flags [S], seq 4198741866, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 1476531926 ecr 0,sackOK,eol], length 0 2606:4700:20::681a:f74.http > 2001:db8:4802:1620:c194:8573:68fe:835e.52327: Flags [S.], seq 3581324650, ack 4198741867, win 27200, options [mss 1360,nop,nop,sackOK,nop,wscale 10], length 0 2001:db8:4802:1620:c194:8573:68fe:835e.52327 > 2606:4700:20::681a:f74.http: Flags [.], ack 1, win 4096, length 0
2001:db8:4802:1620:c194:8573:68fe:835e.52327 > 2606:4700:20::681a:f74.http: Flags [P.], seq 1:42, ack 1, win 4096, length 41: HTTP: GET / HTTP/1.0 2606:4700:20::681a:f74.http > 2001:db8:4802:1620:c194:8573:68fe:835e.52327: Flags [.], ack 42, win 27, length 0 2606:4700:20::681a:f74.http > 2001:db8:4802:1620:c194:8573:68fe:835e.52327: Flags [.], ack 42, win 27, length 0 2606:4700:20::681a:f74.http > 2001:db8:4802:1620:c194:8573:68fe:835e.52327: Flags [P.], seq 1:248, ack 42, win 27, length 247: HTTP: HTTP/1.1 301 Moved Permanently
Swift Network framework tcpdump output (socket over IPv6)
let port = 80 let inAddr = inet_addr(“104.26.3.236”) //should have DNS->IP resolution code
let socket = CFSocketCreate(kCFAllocatorDefault, AF_INET, //could be AF_INET6 SOCK_STREAM, IPPROTO_TCP, CFSocketCallBackType.readCallBack.rawValue, { (socket, callBackType, address, data, info) in debugPrint("got socket") }, nil)
var sin = sockaddr_in() // sin.sin_len = __uint8_t(MemoryLayout.size(ofValue: sin)) sin.sin_family = sa_family_t(AF_INET) sin.sin_port = UInt16(port).bigEndian sin.sin_addr.s_addr = inAddr
let addressDataCF = NSData(bytes: &sin, length: MemoryLayout.size(ofValue: sin)) as CFData
let socketErr = CFSocketConnectToAddress(socket, addressDataCF, CFTimeInterval(timeout))
Swift/Objective-C CFSocket API, similar to old BSD Socket API IPv4 or IPv6 is explicitly configured in the Socket call
Programmer has to implement dual-stack!
source code modified from Learn Java 12 Programming by Nick Samoylov
private static void getFromUrl(){ System.setProperty("java.net.preferIPv6Addresses" , "true"); try { URL url = new URL("http://java.com/"); URLConnection conn = url.openConnection(); conn.setRequestProperty("Accept", "text/html"); conn.setRequestProperty("Connection", "close"); conn.setRequestProperty("Accept-Language", "en-US"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); try(InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is))){ String line; while ((line = br.readLine()) != null){ System.out.println(line); } } …
Java URL API prefers IPv4 by default but IPv6 works
% sudo tcpdump -n port 80 or port 53
2001:db8:4802:1620:c194:8573:68fe:835e.59915 > 2001:558:feed::1.53: 15952+ A? java.com. (26) 2001:db8:4802:1620:c194:8573:68fe:835e.63346 > 2001:558:feed::1.53: 2104+ AAAA? java.com. (26) 2001:558:feed::1.53 > 2001:db8:4802:1620:c194:8573:68fe:835e.59915: 15952 1/0/0 A 104.68.99.141 (42) 2001:558:feed::1.53 > 2001:db8:4802:1620:c194:8573:68fe:835e.63346: 2104 2/0/0 AAAA 2600:1406:1400:69a::196, AAAA 2600:1406:1400:69e::196 (82)
2001:db8:4802:1620:c194:8573:68fe:835e.57284 > 2600:1406:1400:69a::196.80: Flags [S], seq 2787410941, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 1499299361 ecr 0,sackOK,eol], length 0
2600:1406:1400:69a::196.80 > 2001:db8:4802:1620:c194:8573:68fe:835e.57284: Flags [S.], seq 1495637400, ack 2787410942, win 28560, options [mss 1440,sackOK,TS val 3681207985 ecr 1499299361,nop,wscale 7], length 0
2001:db8:4802:1620:c194:8573:68fe:835e.57284 > 2600:1406:1400:69a::196.80: Flags [.], ack 1, win 2052, options [nop,nop,TS val 1499299374 ecr 3681207985], length 0
URL connection to java.com with IPv6 manually set to preferred
source code modified from Learn Java 12 Programming by Nick Samoylov
System.setProperty("java.net.preferIPv6Addresses" , "true"); try(Socket s = new Socket("whatismyv6.com",3333); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dout = new DataOutputStream(s.getOutputStream()); BufferedReader console = new BufferedReader(new InputStreamReader(System.in))){ String prompt = "Say something: "; System.out.print(prompt); String msg; while ((msg = console.readLine()) != null) { dout.writeUTF( msg); dout.flush(); if (msg.equalsIgnoreCase("end")) { break; } msg = dis.readUTF(); System.out.println("Server said: " +msg); if (msg.equalsIgnoreCase("end")) { break; } System.out.print(prompt); } …
Java Socket API
% sudo tcpdump -n port 3333
// With default preference
192.168.0.22.57360 > 169.45.201.128.3333: Flags [S], seq 2384788794, win 65535, options [mss 1460,nop,wscale 6,nop,nop,TS val 1500031987 ecr 0,sackOK,eol], length 0 169.45.201.128.3333 > 192.168.0.22.57360: Flags [R.], seq 0, ack 2384788795, win 0, length 0
// With IPv6 preference
2001:db8:4802:1620:c194:8573:68fe:835e.57370 > 2607:f0d0:3802:84::128.3333: Flags [S], seq 1582363866, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 1500098402 ecr 0,sackOK,eol], length 0 2607:f0d0:3802:84::128.3333 > 2001:db8:4802:1620:c194:8573:68fe:835e.57370: Flags [R.], seq 0, ack 1582363867, win 0, length 0
Java Socket API output
Before and after setting java.net.preferIPv6Addresses
https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/net/doc-files/net-properties.html
Wireshark
Capture of Java connection to java.com before and after setting System.setProperty("java.net.preferIPv6Addresses" , “true");
Java server-socket
% sudo tcpdump -n port 3333 18:06:17.871794 IP6 2001:db8:4802:1620:358b:d3d:b39d:4b0f.62154 > 2001:db8:4802:1620:c71:2af2:75d7:2add.3333: Flags [S], seq 724297298, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 2969264067 ecr 0,sackOK,eol], length 0
18:06:17.871995 IP6 2001:db8:4802:1620:c71:2af2:75d7:2add.3333 > 2001:db8:4802:1620:358b:d3d:b39d:4b0f.62154: Flags [S.], seq 3606864735, ack 724297299, win 65535, options [mss 1440,nop,wscale 6,nop,nop,TS val 1573806934 ecr 2969264067,sackOK,eol], length 0
try(Socket s = new ServerSocket(3333).accept(); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dout = new DataOutputStream(s.getOutputStream());
Visiting a webpage by IPv6 address for testing before
adding AAAA-record to DNS
Prepend https:// Enclose IPv6 address in square brackets You may get a “certificate impersonation” warning
May not work for some types of web hosting where multiple domains are behind one IP address
Dualcomm network tap for access-points
IPv6 API review• MacOS Swift/Objective-C URLSession (prefers IPv6)
• MacOS Swift/Objective-C Network (prefers IPv6)
• MacOS Swift/Objective-C CFSocket (you hardcode IP version)
• (Oracle) Java URL API (on MacOS) (prefers IPv4)
• (Oracle) Java Socket API (on MacOS) (prefers IPv4)
• (Oracle) Java Server-socket API (on MacOS) (listens to IPv4 and IPv6)
Homework: Pick another OS / API, test, and report
results in the meeting comments
• Kotlin on Android (my one test seemed to indicate IPv4 preference using the Retrofit library)
• Java on Android?
• Microsoft
State of the IPv6 Internet
Source for graphs 3-5: https://blog.apnic.net/2020/01/14/bgp-in-2019-the-bgp-table/
https://www.google.com/intl/en/ipv6/statistics.html
https://www.akamai.com/us/en/resources/our-thinking/state-of-the-
internet-report/state-of-the-internet-ipv6-adoption-visualization.jsp#networks
Akamai IPv6 user traffic data
IPv4 address space depleted
IPv4 Internet route table size: 814k Growing by 150 routes per day
IPv6 route table size: 80k Growing at 50 routes/day
How to get IPv6 address space
1. Get it from your ISP
• Advantages: Easy, cheap, does not add to Internet routing table size
• Disadvantages: Locks you into ISP, if you switch ISPs you must switch addresses.
2. Get it from American Registry for Internet Number (ARIN) (or AFRNIC, APNIC, RIPTE, or LACNIC) as an ISP
3. Get it from American Registry for Internet Number (ARIN) (or other registry) as an End User (enterprise)
How much address space do end users
get under ARIN policy?
Sites Assignment
1 /48
2-12 /44
13-192 /40
193-3072 /36
3073-49152 /32
Number Resource Policy Manual https://www.arin.net/participate/policy/nrpm/
Appendix 1Deeper into IPv6
% sudo tcpdump -n -i en0 icmp6:: > ff02::1:ff62:313: ICMP6, neighbor solicitation, who has fe80::c7d:a37c:c362:313fe80::c7d:a37c:c362:313 > ff02::2: ICMP6, router solicitationfe80::b27f:b9ff:fe5d:8ed2 > ff02::1: ICMP6, router advertisement:: > ff02::1:ffd7:2add: ICMP6, neighbor solicitation, who has 2001:db8:4802:1620:c71:2af2:75d7:2add:: > ff02::1:ff39:6d2: ICMP6, neighbor solicitation, who has 2001:db8:4802:1620:d97b:d0a7:bf39:6d2fe80::b27f:b9ff:fe5d:8ed2 > ff02::1:ffd7:2add: ICMP6, neighbor solicitation, who has 2001:db8:4802:1620:c71:2af2:75d7:2addfe80::b27f:b9ff:fe5d:8ed2 > ff02::1:ff39:6d2: ICMP6, neighbor solicitation, who has 2001:db8:4802:1620:d97b:d0a7:bf39:6d2fe80::c7d:a37c:c362:313 > fe80::b27f:b9ff:fe5d:8ed2: ICMP6, neighbor advertisement, tgt is 2001:db8:4802:1620:c71:2af2:75d7:2addfe80::c7d:a37c:c362:313 > fe80::b27f:b9ff:fe5d:8ed2: ICMP6, neighbor advertisement, tgt is 2001:db8:4802:1620:d97b:d0a7:bf39:6d2fe80::c7d:a37c:c362:313 > fe80::b27f:b9ff:fe5d:8ed2: ICMP6, neighbor solicitation, who has fe80::b27f:b9ff:fe5d:8ed2fe80::b27f:b9ff:fe5d:8ed2 > fe80::c7d:a37c:c362:313: ICMP6, neighbor advertisement, tgt is fe80::b27f:b9ff:fe5d:8ed2
(add option -e to tcpdump command for ethernet header)
b0:7f:b9:5d:8e:d2 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd),length 174: (hlim 255, next-header ICMPv6 (58) payload length: 120) fe80::b27f:b9ff:fe5d:8ed2 > ff02::1: [icmp6 sum ok] ICMP6,router advertisement, length 120
Procedure: turn off WiFi, enable tcpdump, turn on WiFi
Third frame / packet:
How did I find out my prefix? How did I find out my default route?
IPv6 L3 multicast addresses (source: edge.networkworld.com)
11
IPv6 L3 well-known multicast addresses
• ff02::1 all hosts on local subnet
• ff02::2 all routers on local subnet
• ff02::5, ff02::6 OSPFv3
• ff02::9 RIPng
• ff02::fb Bonjour/multicast DNS
IPv6 L3 multicast address -> L2 ethernet multicast address mapping
Prepend “33-33” to last 32 bits of IPv6 L3 address
(src: technet.microsoft.com)
IPv6 router advertisement% sudo tcpdump -e -vv -n icmp6
15:04:17.492672 b0:7f:b9:5d:8e:d2 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 174: (hlim 255, next-header ICMPv6 (58) payload length: 120) fe80::b27f:b9ff:fe5d:8ed2 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 120
hop limit 64, Flags [other stateful], pref medium, router lifetime 1800s, reachable time 0ms, retrans timer 0ms
source link-address option (1), length 8 (1): b0:7f:b9:5d:8e:d2
prefix info option (3), length 32 (4): 2001:db8:4802:1620::/64, Flags [onlink, auto], valid time 345600s, pref. time 345600s
route info option (24), length 24 (3): 2001:db8:4802:1620::/60, pref=medium, lifetime=173859s
rdnss option (25), length 40 (5): lifetime 60s, addr: 2001:558:feed::1 addr: 2001:558:feed::2
% netstat -f inet6 -rn Routing tables
Internet6: Destination Gateway Flags Netif default fe80::b27f:b9ff:fe5d:8ed2%en0 UGc en0
% ping6 fe80::b27f:b9ff:fe5d:8ed2 PING6(56=40+8+8 bytes) fe80::c7d:a37c:c362:313%en0 --> fe80::b27f:b9ff:fe5d:8ed2 ping6: sendmsg: No route to host
% ping6 -I en0 fe80::b27f:b9ff:fe5d:8ed2 PING6(56=40+8+8 bytes) fe80::c7d:a37c:c362:313%en0 --> fe80::b27f:b9ff:fe5d:8ed2 16 bytes from fe80::b27f:b9ff:fe5d:8ed2%en0, icmp_seq=0 hlim=64 time=10.274 ms
15:04:17.492672 b0:7f:b9:5d:8e:d2 > 33:33:00:00:00:01, ethertype IPv6 (0x86dd), length 174: (hlim 255, next-header ICMPv6 (58) payload length: 120) fe80::b27f:b9ff:fe5d:8ed2 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 120
% nslookup > server Default server: 2001:558:feed::1 Address: 2001:558:feed::1#53 Default server: 2001:558:feed::2 Address: 2001:558:feed::2#53 Default server: 75.75.75.75 Address: 75.75.75.75#53
rdnss option (25), length 40 (5): lifetime 60s, addr: 2001:558:feed::1 addr: 2001:558:feed::2
DHCPv6 exists if IPv6 router advertisements do not meet your needs
But who wants to maintain a DHCPv6 server?
% ping6 ff02::1 PING6(56=40+8+8 bytes) fe80::c7d:a37c:c362:313%en0 --> ff02::1 ping6: sendmsg: No route to host ping6: wrote ff02::1 16 chars, ret=-1
% ping6 -I en0 ff02::1 PING6(56=40+8+8 bytes) fe80::c7d:a37c:c362:313%en0 --> ff02::1 16 bytes from fe80::c7d:a37c:c362:313%en0, icmp_seq=0 hlim=64 time=0.093 ms 16 bytes from fe80::185a:ebb6:f06c:d324%en0, icmp_seq=0 hlim=64 time=196.187 ms 16 bytes from fe80::86b:63fb:9d7f:535b%en0, icmp_seq=0 hlim=64 time=196.551 ms 16 bytes from fe80::1c62:ac22:c600:e121%en0, icmp_seq=0 hlim=64 time=197.240 ms
No Layer-3 IPv6 broadcast!
IPv6 “all nodes” multicast address meets the need
Can also “ping -I en0 ff02::2” to ping “all routers”
(but my Netgear does not respond, violating an RFC)
IPv6 Neighbor Solicitation: Input: IPv6 address on attached net. Goal: MAC address
Step 1: Convert target IPv6 unicast address to “solicited node IPv6 multicast address”
Prepend “ff02:0:0:0:0:1:ff” to the last 24 bits (6 hex digits) of the target IPv6 unicast address
Result: ff02:0:0:0:0:1:ffd7:2add ff02::1:ffd7:2add
Step 2: Calculate L2/ethernet multicast address
Prepend “33:33:” to the last 32 bits (8 hex digits) of the target IPv6 address
Result: 33:33:ff:d7:2a:dd
Step 3: Send “ICMPv6 neighbor solicitation” to that destination
b0:7f:b9:5d:8e:d2 > 33:33:ff:d7:2a:dd ethertype IPv6 (0x86dd) fe80::b27f:b9ff:fe5d:8ed2 > ff02::1:ffd7:2add: ICMP6, neighbor solicitation, who has 2001:db8:4802:1620:c71:2af2:75d7:2add
Step 4: Destination responds with “ICMPv6 neighbor advertisement”
f8:ff:c2:10:10:1c > b0:7f:b9:5d:8e:d2, ethertype IPv6 (0x86dd) fe80::c7d:a37c:c362:313 > fe80::b27f:b9ff:fe5d:8ed2: ICMP6, neighbor advertisement, tgt is 2001:db8:4802:1620:c71:2af2:75d7:2add
Target IPv6 unicast address: 2001:db8:4802:1620:c71:2af2:75d7:2add ARP
% netstat -rn -f inet6 2601:647:4802:1620:c71:2af2:75d7:2add f8:ff:c2:10:10:1c UHLWI en0
An IPv6 node must recognize the following addresses: (RFC4291)
1. Link-local address on each interface 2. All additional unicast (and anycast) addresses 3. Loopback address (::1) 4. All nodes multicast address ff02::1, ff01::1 5. Solicited-node multicast address for each unicast address (ff02::1:feXX:XXXX) 6. Any other subscribed multicast groups 7. An IPv6 router must also recognize the all-routers multicast address ff02::2*
* ff01::2, ff05::2 are also required
% netstat -g…IPv6 Multicast Group MembershipsGroup Link-layer Address Netifff02::fb%en0 33:33:0:0:0:fb en0ff02::1:ff39:6d2%en0 33:33:ff:39:6:d2 en0ff02::1:ffd7:2add%en0 33:33:ff:d7:2a:dd en0ff01::1%en0 33:33:0:0:0:1 en0ff02::1%en0 33:33:0:0:0:1 en0ff02::1:ff62:313%en0 33:33:ff:62:3:13 en0ff02::2:ff47:1aef%en0 33:33:ff:47:1a:ef en0 (node info RFC4620)
Cool MacOS command of the day: nettop
nettop -m tcp -J rtt_min,rtt_var,bytes_in,bytes_out -p 40893 bytes_in bytes_out rtt_min rtt_var com.apple.WebKi.40893 99 KiB 209 KiB tcp4 192.168.0.10:49492<->lb-192-30-253-124-iad.github.com:443 3628 B 1009 B 72.56 ms 16.12 ms tcp4 192.168.0.10:49479<->104.244.42.66:443 5091 B 1648 B 17.72 ms 7.69 ms tcp4 192.168.0.10:49467<->lb-140-82-114-25-iad.github.com:443 3783 B 1184 B 81.22 ms 6.75 ms tcp4 192.168.0.10:49448<->stackoverflow.com:443 3951 B 1035 B 83.03 ms 22.56 ms tcp4 192.168.0.10:49441<->151.101.129.69:443 64 KiB 50 KiB 9.94 ms 0.62 ms tcp4 192.168.0.10:49269<->ec2-34-192-92-205.compute-1.amazonaws.com:443 13 KiB 151 KiB 77.75 ms 7.94 ms tcp4 192.168.0.10:49245<->lb-140-82-113-25-iad.github.com:443 4651 B 2196 B 79.12 ms 0.62 ms
Appendix 2Address prefix drills
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/16
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/16
2345:0000:0000:0000:0000:0000:0000:0000/16 2345::/16
Includes IPv6 addresses in this range:2345:0000:0000:0000:0000:0000:0000:00002345:ffff:ffff:ffff:ffff:ffff:ffff:ffff
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/32
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/32
2345:6789::/32
Includes IPv6 addresses in this range:2345:6789:0000:0000:0000:0000:0000:00002345:6789:ffff:ffff:ffff:ffff:ffff:ffff
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/128
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/128
2345:6789:abcd:ef01:2345:6789:abcd:ef01::/128
Includes this IPv6 address:2345:6789:abcd:ef01:2345:6789:abcd:ef01
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/60
address prefix drill2345:6789:abcd:ef01:2345:6789:abcd:ef01
/60
2345:6789:abcd:ef00::/60
Includes IPv6 addresses in this range:2345:6789:abcd:ef00:0000:0000:0000:00002345:6789:abcd:ef0f:ffff:ffff:ffff:ffff
Appendix 3Expanded source code for network samples
Paul Hudson: www.hackingwithswift.com “100 days of Swift / SwiftUI”
URLSession API (also available in Objective-C)
func loadData() { guard let url = URL(string: "https://www.hackingwithswift.com/samples/friendface.json") else { debugPrint("Invalid URL") return } let request = URLRequest(url: url) URLSession.shared.dataTask(with: request) { data, response, error in if let data = data { if let decodedResponse = try? JSONDecoder().decode([User].self, from: data) { DispatchQueue.main.async { self.users = decodedResponse } return } } debugPrint("fetch failed: \(error?.localizedDescription ?? "Unknown error")") }.resume() }
import Foundation import Network class TcpPrint { let queue: DispatchQueue let connection: NWConnection static let sendString = """ GET / HTTP/1.0 Host: swiftbysundell.net
""".utf8 let sendData = Data(sendString) init?() { queue = DispatchQueue(label: "queueName", attributes: .concurrent) let serverEndpoint = NWEndpoint.Host("swiftbysundell.net") let portEndpoint = NWEndpoint.Port(rawValue: 80)! connection = NWConnection(host: serverEndpoint, port: portEndpoint, using: .tcp) connection.stateUpdateHandler = { [weak self] (newState) in switch newState { case .ready: debugPrint("TcpReader.ready to send") self?.receive() case .failed(let error): debugPrint("TcpReader.client failed with error \(error)") exit(-1) case .setup, .waiting, .preparing: debugPrint("TcpReader state \(newState)") case .cancelled: debugPrint("TcpReader.cancelled") exit(0) } } connection.start(queue: self.queue) connection.send(content: sendData, completion: .contentProcessed({ (error) in print("send completed") if let error = error { print("send error: \(error)") } })) } func receive() { connection.receive(minimumIncompleteLength: 1, maximumLength: 8192) { (content, context, isComplete, error) in debugPrint("\(Date()) TcpReader: got a message \(String(describing: content?.count)) bytes") if let content = content { let str = String(decoding: content, as: UTF8.self) debugPrint(str) } if self.connection.state == .ready && isComplete == false { self.receive() } } } }
Swift/Objective-C Network framework Also accessible from Objective-C
package com.packt.learnjava.ch11_network; // source code modified from Learn Java 12 Programming by Nick Samoylov import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.URL; import java.net.URLConnection; public class UrlClient { public static void main(String[] args) { getFromUrl(); } private static void getFromUrl(){ System.setProperty("java.net.preferIPv6Addresses" , "true"); try { URL url = new URL("http://java.com/"); URLConnection conn = url.openConnection(); conn.setRequestProperty("Accept", "text/html"); conn.setRequestProperty("Connection", "close"); conn.setRequestProperty("Accept-Language", "en-US"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); try(InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is))){ String line; while ((line = br.readLine()) != null){ System.out.println(line); } } } catch (Exception e) { e.printStackTrace(); } } }
Java URL API
Recent Java versions prefer IPv4 by default
(at least on my system)
package com.packt.learnjava.ch11_network; // source code modified from Learn Java 12 Programming by Nick Samoylov import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.net.Socket; public class TcpClient { public static void main(String[] args) { System.setProperty("java.net.preferIPv6Addresses" , "true"); try(Socket s = new Socket("whatismyv6.com",3333); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dout = new DataOutputStream(s.getOutputStream()); BufferedReader console = new BufferedReader(new InputStreamReader(System.in))){ String prompt = "Say something: "; System.out.print(prompt); String msg; while ((msg = console.readLine()) != null) { dout.writeUTF( msg); dout.flush(); if (msg.equalsIgnoreCase("end")) { break; }
msg = dis.readUTF(); System.out.println("Server said: " +msg); if (msg.equalsIgnoreCase("end")) { break; } System.out.print(prompt); } } catch(Exception ex){ ex.printStackTrace(); } } }
Java Socket API