1""" Please make sure you read the README COMPLETELY BEFORE reading anything below. 2 It is very critical that you read coding guidelines in Section E in README file. 3""" 4from xnu import * 5from utils import * 6from string import * 7from socket import * 8from enum import IntEnum 9 10import xnudefines 11from netdefines import * 12from routedefines import * 13 14###################################### 15# Globals 16###################################### 17""" Refer to in bsd/net/ntstat.c 18""" 19NSTAT_PROCDETAILS_MAGIC = 0xfeedc001 20NSTAT_GENERIC_SHADOW_MAGIC = 0xfadef00d 21TU_SHADOW_MAGIC = 0xfeedf00d 22""" Refer to nstat_provider_type_t in bsd/net/ntstat.h 23""" 24class NSTAT_PROVIDER(IntEnum): 25 NONE = 0 26 ROUTE = 1 27 TCP_KERNEL = 2 28 TCP_USERLAND = 3 29 UDP_KERNEL = 4 30 UDP_USERLAND = 5 31 IFNET = 6 32 SYSINFO = 7 33 QUIC_USERLAND = 8 34 CONN_USERLAND = 9 35 UDP_SUBFLOW = 10 36 37###################################### 38# Helper functions 39###################################### 40 41def FieldPtrToStructPtr(field_ptr, field_name, element_type): 42 """ Given a pointer to a field with a structure, return a pointer to the structure itself 43 params: 44 field_ptr - value : pointer to the field 45 field_name - str : string name of the field which holds the list links. 46 element_type - str : type of elements to be linked in the list 47 returns: 48 value : A pointer to the start of the structure 49 """ 50 out_string = "" 51 if (field_ptr) : 52 tmp_element = Cast(field_ptr, element_type) 53 tmp_element_plus_offset = addressof(tmp_element.__getattr__(field_name)) 54 offset = tmp_element_plus_offset - tmp_element 55 original_ptr_as_char_ptr = Cast(field_ptr, 'char *') 56 amended_ptr = original_ptr_as_char_ptr - offset 57 return kern.GetValueFromAddress(unsigned(amended_ptr), element_type) 58 return field_ptr 59 60def ReverseIterateTAILQ_AnonymousHEAD(headval, field_name, element_type): 61 """ reverse iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h 62 params: 63 headval - value : value object representing the head of the list 64 field_name - str : string name of the field which holds the list links. 65 element_type - str : type of elements to be linked in the list 66 returns: 67 A generator does not return. It is used for iterating. 68 value : an object that is of type as headval->tqh_last. Always a pointer object 69 example usage: 70 list_head = kern.GetGlobalVariable('ctl_head') 71 for entry in ReverseIterateTAILQ_AnonymousHEAD(list_head, 'next', 'struct kctl *'): 72 print(entry) 73 """ 74 head_first = headval.__getattr__('tqh_first') 75 if head_first: 76 head_first_addr = FieldPtrToStructPtr(addressof(head_first),field_name, element_type) 77 head_last = headval.__getattr__('tqh_last') 78 iter_val = FieldPtrToStructPtr(head_last, field_name, element_type) 79 80 while (unsigned(iter_val) != unsigned(head_first_addr)) and (unsigned(iter_val) != 0) : 81 yield iter_val 82 element = Cast(iter_val, element_type) 83 tmp = element.__getattr__(field_name).__getattr__('tqe_prev') 84 iter_val = FieldPtrToStructPtr(tmp, field_name, element_type) 85 #end of yield loop 86 87def ShowNstatTUShadow(inshadow): 88 """ Display summary for an nstat_tu_shadow struct 89 params: 90 inshadow : cvalue object which points to 'struct nstat_tu_shadow *' 91 """ 92 shad = Cast(inshadow, 'struct nstat_tu_shadow *') 93 procdetails = shad.shad_procdetails 94 out_string = "" 95 if shad : 96 format_string = "nstat_tu_shadow {0: <#0x}: next={1: <#020x} prev={2: <#020x} context (necp_client *)={3: <#020x} live={4: <d}" 97 out_string += format_string.format(shad, shad.shad_link.tqe_next, shad.shad_link.tqe_prev, shad.shad_provider_context, shad.shad_live) 98 99 magic = unsigned(shad.shad_magic) 100 if (magic != TU_SHADOW_MAGIC) : 101 format_string = " INVALID shad magic {0: <#0x}" 102 out_string += format_string.format(magic) 103 104 if (procdetails) : 105 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 106 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 107 108 procmagic = unsigned(procdetails.pdet_magic) 109 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 110 format_string = " INVALID proc magic {0: <#0x}" 111 out_string += format_string.format(procmagic) 112 113 print(out_string) 114 115def ShowNstatGShadow(inshadow): 116 """ Display summary for an nstat_generic_shadow 117 params: 118 inshadow : cvalue object which points to 'struct nstat_generic_shadow *' 119 """ 120 gshad = Cast(inshadow, 'struct nstat_generic_shadow *') 121 procdetails = gshad.gshad_procdetails 122 out_string = "" 123 if gshad : 124 prov_string = GetNstatProviderString(gshad.gshad_provider) 125 format_string = "nstat_generic_shadow {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} refcnt={4: <d} " 126 out_string += format_string.format(gshad, prov_string, gshad.gshad_link.tqe_next, gshad.gshad_link.tqe_prev, gshad.gshad_refcnt) 127 128 ## context 129 if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) : 130 out_string += "context (necp_client *)={0: <#020x} ".format(gshad.gshad_provider_context) 131 elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) : 132 out_string += "context (soflow_hash_entry *)={0: <#020x} ".format(gshad.gshad_provider_context) 133 134 magic = unsigned(gshad.gshad_magic) 135 if (magic != NSTAT_GENERIC_SHADOW_MAGIC) : 136 format_string = " INVALID gshad magic {0: <#0x}" 137 out_string += format_string.format(magic) 138 139 if (procdetails) : 140 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 141 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 142 143 procmagic = unsigned(procdetails.pdet_magic) 144 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 145 format_string = " INVALID proc magic {0: <#0x}" 146 out_string += format_string.format(procmagic) 147 148 print(out_string) 149 150 for src in IterateTAILQ_HEAD(gshad.gshad_locus.ntl_src_queue, 'nts_locus_link'): 151 ShowNstatSrc(src) 152 else: 153 print(out_string) 154 155def GetNstatProcdetailsBrief(procdetails): 156 """ Display a brief summary for an nstat_procdetails struct 157 params: 158 procdetails : cvalue object which points to 'struct nstat_procdetails *' 159 returns: 160 str : A string describing various information for the nstat_procdetails structure 161 """ 162 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 163 out_string = "" 164 if (procdetails) : 165 format_string = " --> pid={0: <d} name={1: <s} refcnt={2: <d}" 166 out_string += format_string.format(procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 167 168 procmagic = unsigned(procdetails.pdet_magic) 169 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 170 format_string = " INVALID proc magic {0: <#0x}" 171 out_string += format_string.format(procmagic) 172 173 return out_string 174 175def ShowNstatProcdetails(procdetails): 176 """ Display a summary for an nstat_procdetails struct 177 params: 178 procdetails : cvalue object which points to 'struct nstat_procdetails *' 179 """ 180 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 181 out_string = "" 182 if (procdetails) : 183 format_string = "nstat_procdetails: {0: <#020x} next={1: <#020x} prev={2: <#020x} " 184 out_string += format_string.format(procdetails, procdetails.pdet_link.tqe_next, procdetails.pdet_link.tqe_prev) 185 out_string += GetNstatProcdetailsBrief(procdetails) 186 187 print(out_string) 188 189def ShowNstatSockLocus(locus): 190 """ Display a summary for an nstat_sock_locus struct 191 params: 192 locus : cvalue object which points to 'struct nstat_sock_locus *' 193 """ 194 locus = Cast(locus, 'struct nstat_sock_locus *') 195 out_string = "" 196 if (locus) : 197 format_string = "nstat_sock_locus: {0: <#020x} next={1: <#020x} prev={2: <#020x}" 198 out_string += format_string.format(locus, locus.nsl_link.tqe_next, locus.nsl_link.tqe_prev) 199 out_string += GetNstatTULocusBrief(locus); 200 201 print(out_string) 202 iterator = IterateTAILQ_HEAD(locus.nsl_locus.ntl_src_queue, 'nts_locus_link') 203 for src in iterator: 204 ShowNstatSrc(src) 205 206 207def GetNstatTUShadowBrief(shadow): 208 """ Display a summary for an nstat_tu_shadow struct 209 params: 210 shadow : cvalue object which points to 'struct nstat_tu_shadow *' 211 returns: 212 str : A string describing various information for the nstat_tu_shadow structure 213 """ 214 out_string = "" 215 shad = Cast(shadow, 'struct nstat_tu_shadow *') 216 procdetails = shad.shad_procdetails 217 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 218 out_string = "" 219 if shad : 220 format_string = " shadow {0: <#0x}: necp_client={1: <#020x} live={2: <d}" 221 out_string += format_string.format(shad, shad.shad_provider_context, shad.shad_live) 222 magic = unsigned(shad.shad_magic) 223 if (magic != TU_SHADOW_MAGIC) : 224 format_string = " INVALID shad magic {0: <#0x}" 225 out_string += format_string.format(magic) 226 elif (procdetails) : 227 out_string += GetNstatProcdetailsBrief(procdetails) 228 229 return out_string 230 231def GetNstatGenericShadowBrief(shadow): 232 """ Display a summary for an nstat_generic_shadow struct 233 params: 234 shadow : cvalue object which points to 'struct nstat_generic_shadow *' 235 returns: 236 str : A string describing various information for the nstat_tu_shadow structure 237 """ 238 gshad = Cast(shadow, 'struct nstat_generic_shadow *') 239 procdetails = gshad.gshad_procdetails 240 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 241 out_string = "" 242 if gshad : 243 format_string = " gshadow {0: <#0x}:" 244 out_string += format_string.format(gshad) 245 if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) : 246 out_string += "necp_client={0: <#020x} ".format(gshad.gshad_provider_context) 247 elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) : 248 out_string += "soflow_hash_entry={0: <#020x} ".format(gshad.gshad_provider_context) 249 else : 250 out_string += "context {0: <#020x} ".format(gshad.gshad_provider_context) 251 out_string += " refcnt={0: <d} ".format(gshad.gshad_refcnt) 252 253 magic = unsigned(gshad.gshad_magic) 254 if (magic != NSTAT_GENERIC_SHADOW_MAGIC) : 255 format_string = " INVALID gshad magic {0: <#0x}" 256 out_string += format_string.format(magic) 257 elif (procdetails) : 258 out_string += GetNstatProcdetailsBrief(procdetails) 259 260 return out_string 261 262def GetNstatTULocusBrief(cookie): 263 """ Display a summary for an nnstat_sock_locus struct 264 params: 265 cookie : cvalue object which points to 'struct nstat_sock_locus *' 266 returns: 267 str : A string describing various information for the nstat_sock_locus structure 268 """ 269 out_string = "" 270 sol = Cast(cookie, 'struct nstat_sock_locus *') 271 inp = sol.nsl_inp 272 inpcb = Cast(inp, 'struct inpcb *') 273 inp_socket = inpcb.inp_socket 274 sock = Cast(inp_socket, 'struct socket *') 275 pname = sol.nsl_pname 276 format_string = " inpcb={0: <#0x}: socket={1: <#020x} process={2: <s}" 277 out_string += format_string.format(inpcb, sock, pname) 278 return out_string 279 280def GetNstatProviderString(provider): 281 providers = { 282 NSTAT_PROVIDER.NONE: "none", 283 NSTAT_PROVIDER.ROUTE: "route", 284 NSTAT_PROVIDER.TCP_KERNEL: "TCP k", 285 NSTAT_PROVIDER.TCP_USERLAND: "TCP u", 286 NSTAT_PROVIDER.UDP_KERNEL: "UDP k", 287 NSTAT_PROVIDER.UDP_USERLAND: "UDP u", 288 NSTAT_PROVIDER.IFNET: "ifnet", 289 NSTAT_PROVIDER.SYSINFO: "sysinfo", 290 NSTAT_PROVIDER.QUIC_USERLAND: "quic u", 291 NSTAT_PROVIDER.CONN_USERLAND: "conn u", 292 NSTAT_PROVIDER.UDP_SUBFLOW: "subflow", 293 } 294 return providers.get(unsigned(provider), "unknown") 295 296def ShowNstatSrc(insrc): 297 """ Display summary for an nstat_src struct 298 params: 299 insrc : cvalue object which points to 'struct nstat_src *' 300 """ 301 src = Cast(insrc, 'nstat_src *') 302 prov = src.nts_provider 303 prov = Cast(prov, 'nstat_provider *') 304 prov_string = GetNstatProviderString(prov.nstat_provider_id) 305 out_string = "" 306 if src : 307 format_string = " nstat_src {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} srcref={4: <d} seq={5: <d}" 308 out_string += format_string.format(src, prov_string, src.nts_client_link.tqe_next, src.nts_client_link.tqe_prev, src.nts_srcref, src.nts_seq) 309 310 if ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_USERLAND) or 311 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_USERLAND) or 312 (prov.nstat_provider_id == NSTAT_PROVIDER.QUIC_USERLAND)) : 313 out_string += GetNstatTUShadowBrief(src.nts_cookie); 314 elif ((prov.nstat_provider_id == NSTAT_PROVIDER.CONN_USERLAND) or 315 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_SUBFLOW)) : 316 out_string += GetNstatGenericShadowBrief(src.nts_cookie); 317 elif ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_KERNEL) or 318 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_KERNEL)) : 319 out_string += GetNstatTULocusBrief(src.nts_cookie); 320 321 print(out_string) 322 323def ShowNstatClient(inclient, reverse): 324 """ Display an nstat_client struct 325 params: 326 client : value object representing an nstat_client in the kernel 327 """ 328 client = Cast(inclient, 'nstat_client *') 329 out_string = "" 330 if client : 331 format_string = "\nnstat_client {0: <#0x}: next={1: <#020x} src-head={2: <#020x} tail={3: <#020x}" 332 out_string += format_string.format(client, client.ntc_next, client.ntc_src_queue.tqh_first, client.ntc_src_queue.tqh_last) 333 procdetails = client.ntc_procdetails 334 if (procdetails) : 335 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 336 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 337 338 print(out_string) 339 if reverse: 340 print("reverse nstat_src list:") 341 iterator = ReverseIterateTAILQ_AnonymousHEAD(client.ntc_src_queue, 'nts_client_link', 'struct nstat_src *') 342 else: 343 print("nstat_src list:") 344 iterator = IterateTAILQ_HEAD(client.ntc_src_queue, 'nts_client_link') 345 for src in iterator: 346 ShowNstatSrc(src) 347 348###################################### 349# Print functions 350###################################### 351def PrintNstatClientList(reverse): 352 print("nstat_clients list:") 353 client = kern.globals.nstat_clients 354 client = cast(client, 'nstat_client *') 355 while client != 0: 356 ShowNstatClient(client, reverse) 357 client = cast(client.ntc_next, 'nstat_client *') 358 359def PrintNstatProcdetailList(reverse): 360 procdetails_head = kern.globals.nstat_procdetails_head 361 if reverse: 362 print("\nreverse nstat_procdetails list:\n") 363 iterator = ReverseIterateTAILQ_AnonymousHEAD(procdetails_head, 'pdet_link', 'struct nstat_procdetails *') 364 else: 365 print("\nnstat_procdetails list:\n") 366 iterator = IterateTAILQ_HEAD(procdetails_head, 'pdet_link') 367 for procdetails in iterator: 368 ShowNstatProcdetails(procdetails) 369 370def PrintNstatGenericShadowList(reverse): 371 gshadows = kern.globals.nstat_gshad_head 372 if reverse: 373 print("\nreverse nstat_ghsad list:\n") 374 iterator = ReverseIterateTAILQ_AnonymousHEAD(gshadows, 'gshad_link', 'struct nstat_generic_shadow *') 375 else: 376 print("\nnstat_ghsad list:\n") 377 iterator = IterateTAILQ_HEAD(gshadows, 'gshad_link') 378 for gshad in iterator: 379 ShowNstatGShadow(gshad) 380 381def PrintNstatTUShadowList(reverse): 382 shadows = kern.globals.nstat_userprot_shad_head 383 if reverse: 384 print("\nreverse nstat_userprot_shad list:\n") 385 iterator = ReverseIterateTAILQ_AnonymousHEAD(shadows, 'shad_link', 'struct nstat_tu_shadow *') 386 else: 387 print("\nnstat_userprot_shad list:\n") 388 iterator = IterateTAILQ_HEAD(shadows, 'shad_link') 389 for shad in iterator: 390 ShowNstatTUShadow(shad) 391 392def PrintNstatTCPLocusList(reverse): 393 loci = kern.globals.nstat_tcp_sock_locus_head 394 if reverse: 395 print("\nreverse nstat tcp socket locus list:\n") 396 iterator = ReverseIterateTAILQ_AnonymousHEAD(loci, 'nsl_link', 'struct nstat_sock_locus *') 397 else: 398 print("\nnstat tcp socket locus list:\n") 399 iterator = IterateTAILQ_HEAD(loci, 'nsl_link') 400 for locus in iterator: 401 ShowNstatSockLocus(locus) 402 403def PrintNstatUDPLocusList(reverse): 404 loci = kern.globals.nstat_udp_sock_locus_head 405 if reverse: 406 print("\nreverse nstat udp socket locus list:\n") 407 iterator = ReverseIterateTAILQ_AnonymousHEAD(loci, 'nsl_link', 'struct nstat_sock_locus *') 408 else: 409 print("\nnstat udp socket locus list:\n") 410 iterator = IterateTAILQ_HEAD(loci, 'nsl_link') 411 for locus in iterator: 412 ShowNstatSockLocus(locus) 413 414###################################### 415# LLDB commands 416###################################### 417# Macro: showallntstat 418 419@lldb_command('showallntstat', 'R') 420def ShowAllNtstat(cmd_args=None, cmd_options={}) : 421 """ Show the contents of various ntstat (network statistics) data structures 422 423 usage: showallntstat [-R] 424 -R : print ntstat list in reverse 425 """ 426 reverse = '-R' in cmd_options 427 428 PrintNstatClientList(reverse) 429 PrintNstatTUShadowList(reverse) 430 PrintNstatGenericShadowList(reverse) 431 PrintNstatProcdetailList(reverse) 432 PrintNstatTCPLocusList(reverse) 433 PrintNstatUDPLocusList(reverse) 434 435# EndMacro: showallntstat 436