2018-05-15 23:48:33 +01:00
/ * *
* @ author n1474335 [ n1474335 @ gmail . com ]
2021-12-30 22:51:30 +00:00
* @ author Michael Rowley [ michaellrowley @ protonmail . com ]
2018-05-15 23:48:33 +01:00
* @ copyright Crown Copyright 2016
* @ license Apache - 2.0
* /
2019-07-09 12:23:59 +01:00
import Operation from "../Operation.mjs" ;
import Utils from "../Utils.mjs" ;
import OperationError from "../errors/OperationError.mjs" ;
import { strToIpv6 , ipv6ToStr , ipv4ToStr , IPV6 _REGEX } from "../lib/IP.mjs" ;
2018-12-25 23:58:00 +00:00
import BigNumber from "bignumber.js" ;
2018-05-15 23:48:33 +01:00
/ * *
* Parse IPv6 address operation
* /
class ParseIPv6Address extends Operation {
/ * *
* ParseIPv6Address constructor
* /
constructor ( ) {
super ( ) ;
this . name = "Parse IPv6 address" ;
2018-12-25 23:58:00 +00:00
this . module = "Default" ;
2018-05-15 23:48:33 +01:00
this . description = "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4." ;
2018-08-21 19:07:13 +01:00
this . infoURL = "https://wikipedia.org/wiki/IPv6_address" ;
2018-05-15 23:48:33 +01:00
this . inputType = "string" ;
this . outputType = "string" ;
this . args = [ ] ;
}
/ * *
* @ param { string } input
* @ param { Object [ ] } args
* @ returns { string }
* /
run ( input , args ) {
let match ,
output = "" ;
2021-12-30 14:25:12 +00:00
if ( ! ( match = IPV6 _REGEX . exec ( input ) ) ) {
throw new OperationError ( "Invalid IPv6 address." ) ;
}
const ipv6 = strToIpv6 ( match [ 1 ] ) ,
longhand = ipv6ToStr ( ipv6 ) ,
shorthand = ipv6ToStr ( ipv6 , true ) ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "Longhand: " + longhand + "\nShorthand: " + shorthand + "\n" ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
// Detect reserved addresses
if ( shorthand === "::" ) {
// Unspecified address
output += "\nUnspecified address corresponding to 0.0.0.0/32 in IPv4." ;
output += "\nUnspecified address range: ::/128" ;
} else if ( shorthand === "::1" ) {
// Loopback address
output += "\nLoopback address to the local host corresponding to 127.0.0.1/8 in IPv4." ;
output += "\nLoopback addresses range: ::1/128" ;
} else if ( ipv6 [ 0 ] === 0 && ipv6 [ 1 ] === 0 && ipv6 [ 2 ] === 0 &&
ipv6 [ 3 ] === 0 && ipv6 [ 4 ] === 0 && ipv6 [ 5 ] === 0xffff ) {
// IPv4-mapped IPv6 address
output += "\nIPv4-mapped IPv6 address detected. IPv6 clients will be handled natively by default, and IPv4 clients appear as IPv6 clients at their IPv4-mapped IPv6 address." ;
output += "\nMapped IPv4 address: " + ipv4ToStr ( ( ipv6 [ 6 ] << 16 ) + ipv6 [ 7 ] ) ;
output += "\nIPv4-mapped IPv6 addresses range: ::ffff:0:0/96" ;
} else if ( ipv6 [ 0 ] === 0 && ipv6 [ 1 ] === 0 && ipv6 [ 2 ] === 0 &&
ipv6 [ 3 ] === 0 && ipv6 [ 4 ] === 0xffff && ipv6 [ 5 ] === 0 ) {
// IPv4-translated address
output += "\nIPv4-translated address detected. Used by Stateless IP/ICMP Translation (SIIT). See RFCs 6145 and 6052 for more details." ;
output += "\nTranslated IPv4 address: " + ipv4ToStr ( ( ipv6 [ 6 ] << 16 ) + ipv6 [ 7 ] ) ;
output += "\nIPv4-translated addresses range: ::ffff:0:0:0/96" ;
} else if ( ipv6 [ 0 ] === 0x100 ) {
// Discard prefix per RFC 6666
output += "\nDiscard prefix detected. This is used when forwarding traffic to a sinkhole router to mitigate the effects of a denial-of-service attack. See RFC 6666 for more details." ;
output += "\nDiscard range: 100::/64" ;
} else if ( ipv6 [ 0 ] === 0x64 && ipv6 [ 1 ] === 0xff9b && ipv6 [ 2 ] === 0 &&
ipv6 [ 3 ] === 0 && ipv6 [ 4 ] === 0 && ipv6 [ 5 ] === 0 ) {
// IPv4/IPv6 translation per RFC 6052
output += "\n'Well-Known' prefix for IPv4/IPv6 translation detected. See RFC 6052 for more details." ;
output += "\nTranslated IPv4 address: " + ipv4ToStr ( ( ipv6 [ 6 ] << 16 ) + ipv6 [ 7 ] ) ;
output += "\n'Well-Known' prefix range: 64:ff9b::/96" ;
} else if ( ipv6 [ 0 ] === 0x2001 && ipv6 [ 1 ] === 0 ) {
// Teredo tunneling
output += "\nTeredo tunneling IPv6 address detected\n" ;
const serverIpv4 = ( ipv6 [ 2 ] << 16 ) + ipv6 [ 3 ] ,
udpPort = ( ~ ipv6 [ 5 ] ) & 0xffff ,
clientIpv4 = ~ ( ( ipv6 [ 6 ] << 16 ) + ipv6 [ 7 ] ) ,
flagCone = ( ipv6 [ 4 ] >>> 15 ) & 1 ,
flagR = ( ipv6 [ 4 ] >>> 14 ) & 1 ,
flagRandom1 = ( ipv6 [ 4 ] >>> 10 ) & 15 ,
flagUg = ( ipv6 [ 4 ] >>> 8 ) & 3 ,
flagRandom2 = ipv6 [ 4 ] & 255 ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "\nServer IPv4 address: " + ipv4ToStr ( serverIpv4 ) +
"\nClient IPv4 address: " + ipv4ToStr ( clientIpv4 ) +
"\nClient UDP port: " + udpPort +
"\nFlags:" +
"\n\tCone: " + flagCone ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
if ( flagCone ) {
output += " (Client is behind a cone NAT)" ;
} else {
output += " (Client is not behind a cone NAT)" ;
}
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "\n\tR: " + flagR ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
if ( flagR ) {
output += " Error: This flag should be set to 0. See RFC 5991 and RFC 4380." ;
}
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "\n\tRandom1: " + Utils . bin ( flagRandom1 , 4 ) +
"\n\tUG: " + Utils . bin ( flagUg , 2 ) ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
if ( flagUg ) {
output += " Error: This flag should be set to 00. See RFC 4380." ;
}
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "\n\tRandom2: " + Utils . bin ( flagRandom2 , 8 ) ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
if ( ! flagR && ! flagUg && flagRandom1 && flagRandom2 ) {
output += "\n\nThis is a valid Teredo address which complies with RFC 4380 and RFC 5991." ;
} else if ( ! flagR && ! flagUg ) {
output += "\n\nThis is a valid Teredo address which complies with RFC 4380, however it does not comply with RFC 5991 (Teredo Security Updates) as there are no randomised bits in the flag field." ;
} else {
output += "\n\nThis is an invalid Teredo address." ;
}
output += "\n\nTeredo prefix range: 2001::/32" ;
} else if ( ipv6 [ 0 ] === 0x2001 && ipv6 [ 1 ] === 0x2 && ipv6 [ 2 ] === 0 ) {
// Benchmarking
output += "\nAssigned to the Benchmarking Methodology Working Group (BMWG) for benchmarking IPv6. Corresponds to 198.18.0.0/15 for benchmarking IPv4. See RFC 5180 for more details." ;
output += "\nBMWG range: 2001:2::/48" ;
} else if ( ipv6 [ 0 ] === 0x2001 && ipv6 [ 1 ] >= 0x10 && ipv6 [ 1 ] <= 0x1f ) {
// ORCHIDv1
output += "\nDeprecated, previously ORCHIDv1 (Overlay Routable Cryptographic Hash Identifiers).\nORCHIDv1 range: 2001:10::/28\nORCHIDv2 now uses 2001:20::/28." ;
} else if ( ipv6 [ 0 ] === 0x2001 && ipv6 [ 1 ] >= 0x20 && ipv6 [ 1 ] <= 0x2f ) {
// ORCHIDv2
output += "\nORCHIDv2 (Overlay Routable Cryptographic Hash Identifiers).\nThese are non-routed IPv6 addresses used for Cryptographic Hash Identifiers." ;
output += "\nORCHIDv2 range: 2001:20::/28" ;
} else if ( ipv6 [ 0 ] === 0x2001 && ipv6 [ 1 ] === 0xdb8 ) {
// Documentation
output += "\nThis is a documentation IPv6 address. This range should be used whenever an example IPv6 address is given or to model networking scenarios. Corresponds to 192.0.2.0/24, 198.51.100.0/24, and 203.0.113.0/24 in IPv4." ;
output += "\nDocumentation range: 2001:db8::/32" ;
} else if ( ipv6 [ 0 ] === 0x2002 ) {
// 6to4
output += "\n6to4 transition IPv6 address detected. See RFC 3056 for more details." +
"\n6to4 prefix range: 2002::/16" ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
const v4Addr = ipv4ToStr ( ( ipv6 [ 1 ] << 16 ) + ipv6 [ 2 ] ) ,
slaId = ipv6 [ 3 ] ,
interfaceIdStr = ipv6 [ 4 ] . toString ( 16 ) + ipv6 [ 5 ] . toString ( 16 ) + ipv6 [ 6 ] . toString ( 16 ) + ipv6 [ 7 ] . toString ( 16 ) ,
interfaceId = new BigNumber ( interfaceIdStr , 16 ) ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
output += "\n\nEncapsulated IPv4 address: " + v4Addr +
"\nSLA ID: " + slaId +
"\nInterface ID (base 16): " + interfaceIdStr +
"\nInterface ID (base 10): " + interfaceId . toString ( ) ;
} else if ( ipv6 [ 0 ] >= 0xfc00 && ipv6 [ 0 ] <= 0xfdff ) {
// Unique local address
output += "\nThis is a unique local address comparable to the IPv4 private addresses 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16. See RFC 4193 for more details." ;
output += "\nUnique local addresses range: fc00::/7" ;
} else if ( ipv6 [ 0 ] >= 0xfe80 && ipv6 [ 0 ] <= 0xfebf ) {
// Link-local address
output += "\nThis is a link-local address comparable to the auto-configuration addresses 169.254.0.0/16 in IPv4." ;
output += "\nLink-local addresses range: fe80::/10" ;
} else if ( ipv6 [ 0 ] >= 0xff00 ) {
// Multicast
output += "\nThis is a reserved multicast address." ;
output += "\nMulticast addresses range: ff00::/8" ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
switch ( ipv6 [ 0 ] ) {
case 0xff01 :
output += "\n\nReserved Multicast Block for Interface Local Scope" ;
break ;
case 0xff02 :
output += "\n\nReserved Multicast Block for Link Local Scope" ;
break ;
case 0xff03 :
output += "\n\nReserved Multicast Block for Realm Local Scope" ;
break ;
case 0xff04 :
output += "\n\nReserved Multicast Block for Admin Local Scope" ;
break ;
case 0xff05 :
output += "\n\nReserved Multicast Block for Site Local Scope" ;
break ;
case 0xff08 :
output += "\n\nReserved Multicast Block for Organisation Local Scope" ;
break ;
case 0xff0e :
output += "\n\nReserved Multicast Block for Global Scope" ;
break ;
}
2021-02-23 15:11:16 +00:00
2021-12-30 14:25:12 +00:00
if ( ipv6 [ 6 ] === 1 ) {
if ( ipv6 [ 7 ] === 2 ) {
output += "\nReserved Multicast Address for 'All DHCP Servers and Relay Agents (defined in RFC3315)'" ;
} else if ( ipv6 [ 7 ] === 3 ) {
output += "\nReserved Multicast Address for 'All LLMNR Hosts (defined in RFC4795)'" ;
}
} else {
switch ( ipv6 [ 7 ] ) {
case 1 :
output += "\nReserved Multicast Address for 'All nodes'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 2 :
output += "\nReserved Multicast Address for 'All routers'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 5 :
output += "\nReserved Multicast Address for 'OSPFv3 - All OSPF routers'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 6 :
output += "\nReserved Multicast Address for 'OSPFv3 - All Designated Routers'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 8 :
output += "\nReserved Multicast Address for 'IS-IS for IPv6 Routers'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 9 :
output += "\nReserved Multicast Address for 'RIP Routers'" ;
2021-02-23 15:11:16 +00:00
break ;
2021-12-30 14:25:12 +00:00
case 0xa :
output += "\nReserved Multicast Address for 'EIGRP Routers'" ;
break ;
case 0xc :
output += "\nReserved Multicast Address for 'Simple Service Discovery Protocol'" ;
break ;
case 0xd :
output += "\nReserved Multicast Address for 'PIM Routers'" ;
break ;
case 0x16 :
output += "\nReserved Multicast Address for 'MLDv2 Reports (defined in RFC3810)'" ;
break ;
case 0x6b :
output += "\nReserved Multicast Address for 'Precision Time Protocol v2 Peer Delay Measurement Messages'" ;
break ;
case 0xfb :
output += "\nReserved Multicast Address for 'Multicast DNS'" ;
break ;
case 0x101 :
output += "\nReserved Multicast Address for 'Network Time Protocol'" ;
break ;
case 0x108 :
output += "\nReserved Multicast Address for 'Network Information Service'" ;
break ;
case 0x114 :
output += "\nReserved Multicast Address for 'Experiments'" ;
break ;
case 0x181 :
output += "\nReserved Multicast Address for 'Precision Time Protocol v2 Messages (exc. Peer Delay)'" ;
2021-02-23 15:11:16 +00:00
break ;
}
2018-05-15 23:48:33 +01:00
}
2021-12-30 14:25:12 +00:00
}
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
// Detect possible EUI-64 addresses
if ( ( ( ipv6 [ 5 ] & 0xff ) === 0xff ) && ( ipv6 [ 6 ] >>> 8 === 0xfe ) ) {
output += "\n\nThis IPv6 address contains a modified EUI-64 address, identified by the presence of FF:FE in the 12th and 13th octets." ;
2018-05-15 23:48:33 +01:00
2021-12-30 14:25:12 +00:00
const intIdent = Utils . hex ( ipv6 [ 4 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 4 ] & 0xff ) + ":" +
Utils . hex ( ipv6 [ 5 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 5 ] & 0xff ) + ":" +
Utils . hex ( ipv6 [ 6 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 6 ] & 0xff ) + ":" +
Utils . hex ( ipv6 [ 7 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 7 ] & 0xff ) ,
mac = Utils . hex ( ( ipv6 [ 4 ] >>> 8 ) ^ 2 ) + ":" + Utils . hex ( ipv6 [ 4 ] & 0xff ) + ":" +
Utils . hex ( ipv6 [ 5 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 6 ] & 0xff ) + ":" +
Utils . hex ( ipv6 [ 7 ] >>> 8 ) + ":" + Utils . hex ( ipv6 [ 7 ] & 0xff ) ;
output += "\nInterface identifier: " + intIdent +
"\nMAC address: " + mac ;
2018-05-15 23:48:33 +01:00
}
return output ;
}
}
export default ParseIPv6Address ;