Recording a Packet Trace

I want to track down which part of an app contacts a given domain listed in its App Privacy Report.

Following the instructions given here I am able to capture a packet trace, but traffic to the domain in question is encrypted using QUIC.

Is there a way to insert e.g. mitmproxy into the capture process in order to get hold of the SSLKEYLOGFILE so that I can decrypt the traffic?

Answered by DTS Engineer in 879819022

I was able to get this working today:

  1. On my Mac, running macOS 26.2, I downloaded the Mac version (mitmproxy-12.2.1-macos-arm64.tar.gz).

  2. I unpacked it.

  3. I moved it to the Applications folder.

  4. And launched it (which opens a Terminal window).

  5. It creates its CA (certificate authority) certificates in ~/.mitmproxy . I check that was all present:

    % ls -l ~/.mitmproxy 
    total 48
    -rw-r--r--@ 1 quinn  staff  1172 13 Mar 12:05 mitmproxy-ca-cert.cer
    -rw-r--r--@ 1 quinn  staff  1035 13 Mar 12:05 mitmproxy-ca-cert.p12
    -rw-r--r--@ 1 quinn  staff  1172 13 Mar 12:05 mitmproxy-ca-cert.pem
    -rw-------@ 1 quinn  staff  2384 13 Mar 12:05 mitmproxy-ca.p12
    -rw-------@ 1 quinn  staff  2847 13 Mar 12:05 mitmproxy-ca.pem
    -rw-r--r--@ 1 quinn  staff   770 13 Mar 12:05 mitmproxy-dhparam.pem
    
  6. On a victim device running 26.2…

    IMPORTANT This process involves changing system-wide trust settings. Given that, it’s not appropriate for a device you actually care about.

  7. I launched Safari and open a private browsing tab (this helps with subsequent steps).

  8. In Settings > Wi-Fi > My Network > Configure Proxy, I selected Manual, and entered my Mac’s IP address and port 8080.

  9. Back in Safari, I went to http://mitm.it.

  10. I tapped iOS > Get “mitmproxy-ca-cert.pem” and agreed to the download.

  11. In Settings > General > VPN & Device Management > mitmproxy, I ran through the install sequence.

  12. In Settings > About > Certificate Trust Settings, I enabled the “mitmproxy” CA.

  13. Back in Safari, I created a new tab and entered https://mitmproxy.org.

  14. In Terminal on my Mac, I saw those requests being proxied.

    Note If you press z, you can clear the list of requests which makes it easier to see the new ones.

  15. Back in Safari, I hit the refresh button and watched the requests continue to be proxied.

Neat-o!


I hit one really weird gotcha during this exercise. In step 13 I originally tested with https://example.com. That failed with a 502 Bad Gateway error. I suspect this is some special case within mitmproxy, because it only seems to affect that site.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

What platform are you on?

Oh, and are you using QUIC via HTTP/3? Or explicitly?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

What platform are you on?

iOS unfortunately

Oh, and are you using QUIC via HTTP/3? Or explicitly?

I'm not sure; let me check

It seems to be QUIC explicitly. And it's not us using it but some dependency we include - and yes, I am aware of https://developer.apple.com/documentation/Xcode/verifying-the-origin-of-your-xcframeworks :)

I also have been perusing the logs, but to no avail (Bundle Name and ID redacted):

default	2026-03-06 08:10:29.582324 +0100	mDNSResponder	dnssd_server	[R421] getaddrinfo start -- flags: 0xC000D000, ifindex: 0, protocols: 0, hostname: google.com, options: 0x8 {use-failover}, client pid: 545 (com.apple.WebKi), delegator pid: 463 (<CFBundleName>)
default	2026-03-06 08:10:29.583518 +0100	mDNSResponder	resolver	[Q65194] Received acceptable 44-byte response from 192.168.179.1 over UDP via en0/13 -- id: 0x533C (21308), flags: 0x8180 (R/Query, RD, RA, NoError), counts: 1/1/0/0, google.com. IN A?, 285 IN A 172.217.17.206
default	2026-03-06 08:19:53.020864 +0100	com.apple.WebKit.Networking	connection	[C1 83F90D07-2D61-4158-A073-C82071955008 google.com:443 quic-connection, bundle id: <CFBundleIdentifier>, url: https://google.com/, definite, attribution: developer, context: com.apple.CFNetwork.NSURLSession.{FC11B685-7D67-4806-80B1-6E2559DC8AA4}{(null)}{Y}{3}{0x20e0344a0} (sensitive), proc: 1F873F6E-9E6F-3D35-A95D-C72E62C50C26, effective proc: 888D3A38-707B-33BC-944C-0143FC68835D, delegated upid: 0, pid: 814, attribution context: google.com] start
info	2026-03-06 08:19:53.024946 +0100	com.apple.WebKit.Networking	connection	nw_endpoint_resolver_handle_alternative [C1.1.1 google.com:443 in_progress resolver (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good)] Discovered alternative google.com:443 using tcp
info	2026-03-06 08:19:53.024960 +0100	com.apple.WebKit.Networking	connection	nw_endpoint_resolver_handle_alternative [C1.1.1 google.com:443 in_progress resolver (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good)] Discovered alternative google.com:443 using quic
info	2026-03-06 08:19:53.024986 +0100	com.apple.WebKit.Networking	connection	nw_endpoint_transform_receive_report_block_invoke [C1.1 google.com:443 in_progress transform (satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, LQM: good)] updated endpoint alternatives allow quic, restarting
default	2026-03-06 08:19:53.029119 +0100	com.apple.WebKit.Networking	quic	quic_conn_initialize_inner [C1.1.2.1:2] [-987721dfe9544d2a] created QUIC connection (spin bit enabled)
info	2026-03-06 08:19:53.100833 +0100	com.apple.WebKit.Networking	quic	quic_conn_process_inbound [C1.1.2.1:2] [-f87721dfe9544d2a] unable to parse packet (decryption keys may not be ready)

If it’s a QUIC connection and the logs has a com.apple.WebKit.Networking subsystem, it’s almost certainly HTTP/3. Have you tried the HTTP Traffic instrument? See Analyzing HTTP traffic with Instruments.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I have, but the HTTP Traffic Instrument does not seem to record anything, I just get Network Connections:

the HTTP Traffic Instrument does not seem to record anything

Indeed. I had just assumed that it’d work for requests generated by a web view, but I tried that here today and it doesn’t seem to be the case )-:

Still, that’s more evidence that this QUIC traffic is coming from a web view, which is very likely to be HTTP/3. And you should be able to intercept that with a debugging HTTP proxy. Have you tried that already?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, that's the first thing I tried after tcpdump when I saw there were encrypted QUIC packets in the trace file. I could not get my device to connect to mitmproxy running on my Mac though, and running Proxyman directly on the device did not capture anything interesting.

OK. Lemme explain how I’d tackle this and then you can either try it yourself or, if you’ve tried it already, share your experience.

I typically test this stuff with a small test project. I set it up to run a request via URLSession and also load a page via a web view. I then run my debugging infrastructure against that test app. If things work there, I can run the same setup against my real app with some confidence that my debugging setup is working. OTOH, if I can’t get the results I expect with my test app, I know that there’s something wrong with my debugging setup.

I haven’t tried mitmproxy recently, but the last time I did it worked a treat.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I haven’t tried mitmproxy recently, but the last time I did it worked a treat.

I don't know what I'm doing wrong honestly, but if I configure a manual HTTP proxy I always end up with "No Internet Connection"

I was able to get this working today:

  1. On my Mac, running macOS 26.2, I downloaded the Mac version (mitmproxy-12.2.1-macos-arm64.tar.gz).

  2. I unpacked it.

  3. I moved it to the Applications folder.

  4. And launched it (which opens a Terminal window).

  5. It creates its CA (certificate authority) certificates in ~/.mitmproxy . I check that was all present:

    % ls -l ~/.mitmproxy 
    total 48
    -rw-r--r--@ 1 quinn  staff  1172 13 Mar 12:05 mitmproxy-ca-cert.cer
    -rw-r--r--@ 1 quinn  staff  1035 13 Mar 12:05 mitmproxy-ca-cert.p12
    -rw-r--r--@ 1 quinn  staff  1172 13 Mar 12:05 mitmproxy-ca-cert.pem
    -rw-------@ 1 quinn  staff  2384 13 Mar 12:05 mitmproxy-ca.p12
    -rw-------@ 1 quinn  staff  2847 13 Mar 12:05 mitmproxy-ca.pem
    -rw-r--r--@ 1 quinn  staff   770 13 Mar 12:05 mitmproxy-dhparam.pem
    
  6. On a victim device running 26.2…

    IMPORTANT This process involves changing system-wide trust settings. Given that, it’s not appropriate for a device you actually care about.

  7. I launched Safari and open a private browsing tab (this helps with subsequent steps).

  8. In Settings > Wi-Fi > My Network > Configure Proxy, I selected Manual, and entered my Mac’s IP address and port 8080.

  9. Back in Safari, I went to http://mitm.it.

  10. I tapped iOS > Get “mitmproxy-ca-cert.pem” and agreed to the download.

  11. In Settings > General > VPN & Device Management > mitmproxy, I ran through the install sequence.

  12. In Settings > About > Certificate Trust Settings, I enabled the “mitmproxy” CA.

  13. Back in Safari, I created a new tab and entered https://mitmproxy.org.

  14. In Terminal on my Mac, I saw those requests being proxied.

    Note If you press z, you can clear the list of requests which makes it easier to see the new ones.

  15. Back in Safari, I hit the refresh button and watched the requests continue to be proxied.

Neat-o!


I hit one really weird gotcha during this exercise. In step 13 I originally tested with https://example.com. That failed with a 502 Bad Gateway error. I suspect this is some special case within mitmproxy, because it only seems to affect that site.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thank you for the detailed instructions, I still cannot get it to work though. My Mac is running macOS 15.7.4 and my iPhone is on iOS 26.3.1, but step 9 invariably fails. I even tried messing with the system firewall settings, allowing all incoming connections to mitmproxy and disabling the firewall altogether, but still no luck.

Do you work in a managed environment?

I sometimes see reports like by folks who work in high-security industries, like health or finance. Their network, Mac, or device is locked down in some way that breaks this tooling. It’s hard to offer specific advice in that case, because these setups are very site specific, but I do have a few general hints:

  • If you have a Mac laptop, you can relocate it to a different network. For example, you might run this test at home.
  • Rather than running the proxy on your main work Mac, run it on a ‘victim’ Mac. For example, I often have great success using Mac-on-Mac virtualisation.
  • Test with a victim ‘device’ that’s unmanaged. Or if you test device is managed, try a different device, like your own personal iPhone.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

This is slightly embarrassing, but it turns out that I was using a wi-fi that basically blocks everything except ports 80 and 443. After I changed networks it worked as you described.

Regarding the suspicious traffic however I am none the wiser since apparently the connection is secured using some sort of pinning; running mitmdump reveals:

client connect
server connect google.com:443 (142.251.39.238:443)
Client TLS handshake failed. The client disconnected during the handshake. If this happens consistently for google.com, this may indicate that the client does not trust the proxy's certificate.
client disconnect
server disconnect google.com:443 (142.251.39.238:443)
I was using a wi-fi that basically blocks everything

Hey hey!

And, yeah, I see stuff like that all the time (-:

apparently the connection is secured using some sort of pinning

Interesting.

The weird part about this is your suspicion that the traffic is coming from within the web view, but it’s not obvious code running in the web view — so JavaScript, basically — could implement pinning.

So, I think it’d be worthwhile double checking the origin of this network connection. With mitmproxy you should be able to get the source IP and port number of the request. And you can then use RVI to track the originating process. RVI puts this in packet metadata, which you can display by running tcpdump with the -k option. See the tcpdump man page for details.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The weird part about this is your suspicion that the traffic is coming from within the web view, but it’s not obvious code running in the web view — so JavaScript, basically — could implement pinning.

No, it's not a WebView where I suspect the traffic comes from, but a (mostly) native app that includes a (small) number of 3rd party dependencies in both source and binary form.

I suspect the traffic comes from one of the binary dependencies, but I am having a hard time pinning down which one. I only have circumstantial evidence (framework name redacted):

$ strings Frameworks/<CFBundleName>.framework/<CFBundleName> | grep google.com
mail.google.com
www.google.com
*.google.com 

With mitmproxy you should be able to get the source IP and port number of the request. And you can then use RVI to track the originating process. RVI puts this in packet metadata, which you can display by running tcpdump with the -k option. See the tcpdump man page for details.

How would I go about setting that up?

it's not a WebView where I suspect the traffic comes from

Ah, OK, thanks for setting my straight.

How would I go about setting that up?

Which bit?

To get the source information from mitmproxy, view the request, switch to the Detail tab, and look at the Client Connection section.

Getting process information from the packet trace is a small extension of the RVI process described in Recording a Packet Trace:

  1. Set up RVI per the Set Up iOS Packet Tracing section.
  2. When you get to the tcpdump command, add the -k option to cause it to dump each packet’s metadata.

And tcpdump naturally logs the port numbers in each packet, so you can look for outgoing packets whose source port matches the port number you get from the proxy.

Having said that, this won’t help given your clarification that the connection is not coming from a web view but from within your own process.


I suspect that your third-party library is using BSD Sockets with its own TLS stack. If that’s the case then it’s going to be hard for you to get at the plaintext. A debugging HTTP proxy is the only general-purpose approach. Given that that isn’t working, your options are:

  • Dig into the library at the assembly level, either with the debugger or with a reverse engineering tool.
  • Talk to the library’s vendor to see if they have anything to offer here. For example, there might be an environment variable that causes the library to log its traffic, or TLS keys, or something along those lines.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Which bit?

I was unaware that I could simply run both mitmproxy as well as rvictl and tcpdump at the same time. However I did just that; inspecting the trace file (in Wireshark) revealed the following (bundle name redacted):

[Process Information: com.apple.WebKit(1114) [<CFBundleName>(1111)]]
    [Id: 1114]
    [Name: com.apple.WebKit]

But I guess you are right in that this does not tell me anything I did not already know.

Furthermore I do not see any TLS handshake messages after the server sent its certificate along with the "Finished" message which confirms that there might be some sort of pinning going on.

My quick_conn_process_inbound unable to parse packet messages are generally preceded with

udp_validate_cksum_internal [C63.1.1.1:3] udp incorrect IPv4-UDP offload checksum 0x3b00 ulen 1026
nw_protocol_udp_get_input_frames [C63.1.1.1:3] Dropped inbound packets, checking for more
sec_framer_open_aesgcm failed to open for AESGCM: -4308

It's a similar environment where we're inside a protected network, with some internal DNS dispatch to a host that overwrites a global DNS setting (highjacked domain). And we're also using firebase for our iOS app.

Recording a Packet Trace
 
 
Q