The cleanup sequence from nesessionmanager looks quite different for the case where we're stopping the tunnel from the extension:
Disconnect started by framework
Note that we don't see an "entering disposing state" here. When the disconnect is triggered from the management app we see:
11:18:28.084338-0700 nesessionmanager com.example.vpn.app[1854]: disposing
11:18:28.084763-0700 nesessionmanager com.example.vpn.app[1854]: disposed, tearing down agent connection
11:18:38.722862-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:67D0C9ED-FFBC-4FF7-B0CF-9195809EC6FB:(null)] in state NESMVPNSessionStateDisposing: plugin NEVPNTunnelPlugin(com.example.vpn.app[inactive]) dispose complete
11:18:38.722928-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:67D0C9ED-FFBC-4FF7-B0CF-9195809EC6FB:(null)] in state NESMVPNSessionStateDisposing: all plugins have disposed
11:18:38.723301-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:67D0C9ED-FFBC-4FF7-B0CF-9195809EC6FB:(null)]: Leaving state NESMVPNSessionStateDisposing
The network is fine at this point. If we delete the VPN config we see:
11:19:02.495277-0700 configd SCNC: stop, triggered by (114) configd, type com.example.vpn.app, reason Service Disposed
Disconnect started by cancelTunnelWithError
When the VPN shutdown is triggered from the extension we see multiple messages about disposing & teardown, but nothing about leaving the disposing state:
11:14:25.887783-0700 nesessionmanager com.example.vpn.app[1854]: disposing
11:14:25.888103-0700 nesessionmanager com.example.vpn.app[1854]: disposed, tearing down agent connection
11:14:42.306910-0700 nesessionmanager com.example.vpn.app[1854]: disposing
11:14:42.307280-0700 nesessionmanager com.example.vpn.app[1854]: disposed, tearing down agent connection
11:15:47.831509-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)] in state NESMVPNSessionStateStopping: plugin already disconnected, disposing all plugins
11:15:47.831604-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)]: Entering state NESMVPNSessionStateDisposing, timeout 5 seconds
11:15:47.831643-0700 nesessionmanager com.example.vpn.app[1854]: disposing
11:15:47.833142-0700 nesessionmanager com.example.vpn.app[1854]: disposed, tearing down agent connection
at this point the network is dead to DNS. When we delete the VPN configuration entirely we get:
11:16:12.804142-0700 configd SCNC: stop, triggered by (114) configd, type com.example.vpn.app, reason Service Disposed
11:16:12.891252-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)] in state NESMVPNSessionStateStopping: plugin already disconnected, disposing all plugins
11:16:12.891377-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)]: Entering state NESMVPNSessionStateDisposing, timeout 5 seconds
11:16:12.891438-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)] in state NESMVPNSessionStateDisposing: no plugins to dispose
11:16:12.891803-0700 nesessionmanager NESMVPNSession[Primary Tunnel:TestConfig:3CA66354-3DDF-40FF-8C59-473ED2545DFB:(null)]: Leaving state NESMVPNSessionStateDisposing
And name resolution immediately starts working.