1

I've search Google and this site and have found several non-R alternatives to do this.. and unfortunately the iptools package can't do it either. I need to do this to merge two datasets together. Any ideas?

Somethink like this, but for bulk IPs: https://isc.sans.edu/tools/ipv6.html#form

No reproducible example because you can use any IP address to demonstrate this..

kng229
  • 473
  • 5
  • 13
  • See this answer: https://stackoverflow.com/a/1555659/2341679 – Scott Ritchie Apr 20 '18 at 20:08
  • Hi, I specifically asked how to do this using R. I don't know Java. – kng229 Apr 20 '18 at 20:12
  • 2
    Hi, the answers there are language agnostic - they suggest that there is no way to convert between IPV4 and IPV6 - R or otherwise – Scott Ritchie Apr 20 '18 at 20:13
  • 1
    You could try looking up the hostname of each IP address, and merging on that instead, eg through `ip_to_hostname()` in the `iptools` package. – Scott Ritchie Apr 20 '18 at 20:15
  • Thanks, I didn't want to resort to that because it is very slow. What about the third answer in your "see this answer" link? It makes it seem possible.. – kng229 Apr 20 '18 at 20:23

1 Answers1

1

You haven't provided sample data.

You haven't told us whether you really know you have the "right kind" of IPv6 addresses to translate to IPv4.

But, we can use base R to implement the basic algorithms:

ipv4_to_ipv6 <- function(x) {
  sapply(x, function(res) {
    res <- strsplit(res, ".", fixed=TRUE)[[1]]
    res <- as.numeric(res)
    res <- sprintf("%02x", res)
    res <- toupper(sprintf("%s%s:%s%s", res[1], res[2], res[3], res[4]))
    sprintf("2002:%s::%s", res, res)
  }, USE.NAMES = FALSE)
}

ipv6_to_ipv4 <- function(x) {
  sapply(x, function(res) {
    res <- iptools::expand_ipv6(res) # NOTE: github version
    res <- strsplit(res, ":", fixed=TRUE)[[1]]
    res <- tail(res, 2)
    res <- c( substr(res[1], 1, 2), substr(res[1], 3, 4), substr(res[2], 1, 2), substr(res[2], 3, 4))
    res <- as.integer(as.raw(sprintf("0x%s", res)))
    res <- paste0(res, collapse=".")
  }, USE.NAMES = FALSE)
}

Now I'll cheat and use a method from dplyr to make the example/test code a bit less cumbersome:

set.seed(0)

dplyr::data_frame(
  rip4_in = iptools::ip_random(10),
  rip6 = ipv4_to_ipv6(rip4_in),
  rip4_out = ipv6_to_ipv4(rip6)
)
## # A tibble: 10 x 3
##    rip4_in         rip6                      rip4_out       
##    <chr>           <chr>                     <chr>          
##  1 113.251.221.104 2002:71FB:DD68::71FB:DD68 113.251.221.104
##  2 34.116.63.87    2002:2274:3F57::2274:3F57 34.116.63.87   
##  3 47.227.58.127   2002:2FE3:3A7F::2FE3:3A7F 47.227.58.127  
##  4 73.45.245.68    2002:492D:F544::492D:F544 73.45.245.68   
##  5 115.111.38.132  2002:736F:2684::736F:2684 115.111.38.132 
##  6 26.105.115.206  2002:1A69:73CE::1A69:73CE 26.105.115.206 
##  7 114.50.117.41   2002:7232:7529::7232:7529 114.50.117.41  
##  8 120.7.114.8     2002:7807:7208::7807:7208 120.7.114.8    
##  9 84.66.177.142   2002:5442:B18E::5442:B18E 84.66.177.142  
## 10 80.68.179.220   2002:5044:B3DC::5044:B3DC 80.68.179.220

NOTE: The above is missing tons of validation checks for proper input.

ALSO: They've been added to the inet package.

Read — https://www.rfc-editor.org/rfc/rfc3056#section-2 — to brush up on some of this.

If you have real, "internet" IPv4 and IPv6 addresses and are trying to match up hosts that host the same service on the same system to both IPv4 and IPv6 clients the above will not work. The only way to accomplish that is to try to get to the FQDN in front of the A or AAAA you have and then lookup either the A or AAAA you don't have.

That operation is going to take alot of time for a large list of addresses so I highly suggest you make a local cache (SQLite is likely fine depending on the volume) so you can then wrap that lookup dance with a cache check.

Community
  • 1
  • 1
hrbrmstr
  • 77,368
  • 11
  • 139
  • 205