Finding AFD Endpoints

AFD.sys maintains a list of endpoint structures in the global variable afd!AfdEndpointListHead, each one of which represents a socket. This document describes how to walk this list to obtain all the AFD endpoints on the system.
0: kd> dt nt!_LIST_ENTRY @@masm(afd!AfdEndpointListHead)
 [ 0xfffffa80`05b95900 - 0xfffffa80`04c0f770 ]
   +0x000 Flink            : 0xfffffa80`05b95900 _LIST_ENTRY [ 0xfffffa80`0377f8d0 - 0xfffff880`0310fd30 ]
   +0x008 Blink            : 0xfffffa80`04c0f770 _LIST_ENTRY [ 0xfffff880`0310fd30 - 0xfffffa80`04d11d30 ]
To find the offset of the link field in the AFD endpoint structure, disassemble the function afd!AfdIsAddressInUse() and look for an instruction that uses a negative offset which would represent the macro CONTAINING_RECORD.
0: kd> uf afd!AfdIsAddressInUse
afd!AfdIsAddressInUse:
fffff880`03120ab0 48895c2408      mov     qword ptr [rsp+8],rbx
fffff880`03120ab5 48896c2410      mov     qword ptr [rsp+10h],rbp
fffff880`03120aba 4889742418      mov     qword ptr [rsp+18h],rsi
fffff880`03120abf 57              push    rdi
fffff880`03120ac0 4883ec30        sub     rsp,30h
fffff880`03120ac4 488bf1          mov     rsi,rcx
fffff880`03120ac7 488b0d7af2feff  mov     rcx,qword ptr [afd!AfdGlobalData (fffff880`0310fd48)]
fffff880`03120ace 33db            xor     ebx,ebx
fffff880`03120ad0 ff158ae5fdff    call    qword ptr [afd!_imp_ExEnterCriticalRegionAndAcquireResourceShared (fffff880`030ff060)]
fffff880`03120ad6 488b3d53f2feff  mov     rdi,qword ptr [afd!AfdEndpointListHead (fffff880`0310fd30)]
fffff880`03120add 488d2d4cf2feff  lea     rbp,[afd!AfdEndpointListHead (fffff880`0310fd30)]
fffff880`03120ae4 eb7f            jmp     afd!AfdIsAddressInUse+0xb5 (fffff880`03120b65)

afd!AfdIsAddressInUse+0x36:
fffff880`03120ae6 488d97f0feffff  lea     rdx,[rdi-110h] ; Offset of the LIST_ENTRY field
fffff880`03120aed 483bd6          cmp     rdx,rsi
fffff880`03120af0 7470            je      afd!AfdIsAddressInUse+0xb2 (fffff880`03120b62)
.
.
.
To display the entries in the list use the following command :
0: kd> r $t0 =  0xfffffa80`05b95900; .for( r $t1 = poi(@$t0) ;  (@$t1 != @$t0) ; r $t1 = poi(@$t1) ) { dw @$t1-110 L1}
fffffa80`0377f7c0  afd0
fffffa80`05aa7340  afd0
fffffa80`039023a0  afd0
fffffa80`03a3e770  afd0
fffffa80`0541e330  afd0
fffffa80`039cec40  afd0
fffffa80`048621f0  afd0
fffffa80`038f62f0  afd0
fffffa80`062b8e50  afd0
fffffa80`04f753f0  afd0
fffffa80`04e82530  afd0
fffffa80`038e85d0  afd0
fffffa80`03a48740  afd0
fffffa80`05ef3010  afd0
fffffa80`05657e50  afd2
fffffa80`059f2300  afd2
.
.
.
The numbers displayed in the second column in the above output indicate the type of endpoint.
The number 0xafd1 indicates an endpoint representing a datagram socket.
The numbers 0xafd0, 0xafd2, 0xafd4, 0xafd6 indicate endpoints representing TCP sockets in various states.

All AFD endpoints have the pool tag AfdE, this can be used to find/verify AFD endpoints.
0: kd> !pool 0xfffffa80`05b95900 2
Pool page fffffa8005b95900 region is Nonpaged pool
*fffffa8005b957e0 size:  1c0 previous size:   90  (Allocated) *AfdE (Protected)
		Pooltag AfdE : Afd endpoint structure, Binary : afd.sys