Chapter 9 What is the IPv6 address of the DNS server used by 192.168.1.26?

9.1 Objects in memory/packages loaded from preceding chapters

Objects available:

  • read_zeek_log() — helper function to read Zeek log files (Chapter 3)
  • packets — data frame of PCAP packet data (Chapter 4)
  • conn — Zeek conn.log data (Chapter 5)
  • hoststshark host/IP file (Chapter 8)

Packages:

  • {tidyverse}

9.2 Question Setup

Our maze is getting even twistier now as we seek out the IPv6 address of the DNS server used by 192.168.1.26? If we don’t read the question thoroughly it is possible to arrive at a wrong answer by forgetting it asked about the DNS server the client is using and not the client itself.

This quest also underscores a critical fact about modern computing environments: IPv6 adoption is increasing and many (if not most) hosts — at least on internal networks — use both IPv4 and IPv6 addresses at the same time. Knowing the various addresses a given host (idenfitied via MAC address) has/had is crucial to tracing activity. Forgetting that IPv6 can be in play could be a costly mistake IRL.

9.3 Solving the quest with R and Zeek conn.log

Again, while we could do a few tshark standalone command line machinations to solve this quest, it doesn’t make much sense to since we have to deal with multiple calls, already have the data we need, and would have to use other command line tools to truly “solve” it well with “just” tshark.

We first need to find (in conn) the DNS traffic for our target host, then take the MAC address of the IP address it is talking to and then re-look for that in conn:

conn %>% 
  filter(
    id.orig_h == "192.168.1.26", 
    service == "dns"
  ) %>% 
  select(orig_l2_addr = resp_l2_addr) %>% 
  left_join(conn) %>% 
  filter(!is.na(id.orig_h)) %>% 
  distinct(id.orig_h)
## Joining, by = "orig_l2_addr"
## # A tibble: 1 x 1
##   id.orig_h                
##   <chr>                    
## 1 fe80::c80b:adff:feaa:1db7

Base R is, again, similar:

conn %>% 
  subset(
    id.orig_h == "192.168.1.26" & service == "dns",
    select = resp_l2_addr
  ) |>
  merge(
    conn,
    by.x = "resp_l2_addr",
    by.y = "orig_l2_addr"
  ) |>
  subset(
    !is.na(id.orig_h),
    select = id.orig_h,
    drop = TRUE
  ) %>% 
  unique()
## [1] "fe80::c80b:adff:feaa:1db7"