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###################################### 40def ReverseIterateTAILQ_AnonymousHEAD(headval, field_name, element_type): 41 """ reverse iterate over a TAILQ_HEAD in kernel. refer to bsd/sys/queue.h 42 params: 43 headval - value : value object representing the head of the list 44 field_name - str : string name of the field which holds the list links. 45 element_type - str : type of elements to be linked in the list 46 returns: 47 A generator does not return. It is used for iterating. 48 value : an object that is of type as headval->tqh_last. Always a pointer object 49 example usage: 50 list_head = kern.GetGlobalVariable('ctl_head') 51 for entry in ReverseIterateTAILQ_AnonymousHEAD(list_head, 'next', 'struct kctl *'): 52 print(entry) 53 """ 54 head_first = headval.__getattr__('tqh_first') 55 head_first_addr = addressof(head_first) 56 iter_val = headval.__getattr__('tqh_last') 57 while (unsigned(iter_val) != unsigned(head_first_addr)) and (unsigned(iter_val) != 0) : 58 yield iter_val 59 element = Cast(iter_val, element_type) 60 iter_val = element.__getattr__(field_name).__getattr__('tqe_prev') 61 #end of yield loop 62 63def ShowNstatTUShadow(inshadow): 64 """ Display summary for an nstat_tu_shadow struct 65 params: 66 inshadow : cvalue object which points to 'struct nstat_tu_shadow *' 67 """ 68 shad = Cast(inshadow, 'struct nstat_tu_shadow *') 69 procdetails = shad.shad_procdetails 70 out_string = "" 71 if shad : 72 format_string = "nstat_tu_shadow {0: <#0x}: next={1: <#020x} prev={2: <#020x} context (necp_client *)={3: <#020x} live={4: <d}" 73 out_string += format_string.format(shad, shad.shad_link.tqe_next, shad.shad_link.tqe_prev, shad.shad_provider_context, shad.shad_live) 74 75 magic = unsigned(shad.shad_magic) 76 if (magic != TU_SHADOW_MAGIC) : 77 format_string = " INVALID shad magic {0: <#0x}" 78 out_string += format_string.format(magic) 79 80 if (procdetails) : 81 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 82 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 83 84 procmagic = unsigned(procdetails.pdet_magic) 85 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 86 format_string = " INVALID proc magic {0: <#0x}" 87 out_string += format_string.format(procmagic) 88 89 print(out_string) 90 91def ShowNstatGShadow(inshadow): 92 """ Display summary for an nstat_generic_shadow 93 params: 94 inshadow : cvalue object which points to 'struct nstat_generic_shadow *' 95 """ 96 gshad = Cast(inshadow, 'struct nstat_generic_shadow *') 97 procdetails = gshad.gshad_procdetails 98 out_string = "" 99 if gshad : 100 prov_string = GetNstatProviderString(gshad.gshad_provider) 101 format_string = "nstat_generic_shadow {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} refcnt={4: <d} " 102 out_string += format_string.format(gshad, prov_string, gshad.gshad_link.tqe_next, gshad.gshad_link.tqe_prev, gshad.gshad_refcnt) 103 104 ## context 105 if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) : 106 out_string += "context (necp_client *)={0: <#020x} ".format(gshad.gshad_provider_context) 107 elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) : 108 out_string += "context (soflow_hash_entry *)={0: <#020x} ".format(gshad.gshad_provider_context) 109 110 magic = unsigned(gshad.gshad_magic) 111 if (magic != NSTAT_GENERIC_SHADOW_MAGIC) : 112 format_string = " INVALID gshad magic {0: <#0x}" 113 out_string += format_string.format(magic) 114 115 if (procdetails) : 116 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 117 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 118 119 procmagic = unsigned(procdetails.pdet_magic) 120 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 121 format_string = " INVALID proc magic {0: <#0x}" 122 out_string += format_string.format(procmagic) 123 124 print(out_string) 125 126def GetNstatProcdetailsBrief(procdetails): 127 """ Display a brief summary for an nstat_procdetails struct 128 params: 129 procdetails : cvalue object which points to 'struct nstat_procdetails *' 130 returns: 131 str : A string describing various information for the nstat_procdetails structure 132 """ 133 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 134 out_string = "" 135 if (procdetails) : 136 format_string = " --> pid={0: <d} name={1: <s} refcnt={2: <d}" 137 out_string += format_string.format(procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 138 139 procmagic = unsigned(procdetails.pdet_magic) 140 if (procmagic != NSTAT_PROCDETAILS_MAGIC) : 141 format_string = " INVALID proc magic {0: <#0x}" 142 out_string += format_string.format(procmagic) 143 144 return out_string 145 146def ShowNstatProcdetails(procdetails): 147 """ Display a summary for an nstat_procdetails struct 148 params: 149 procdetails : cvalue object which points to 'struct nstat_procdetails *' 150 """ 151 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 152 out_string = "" 153 if (procdetails) : 154 format_string = "nstat_procdetails: {0: <#020x} next={1: <#020x} prev={2: <#020x} " 155 out_string += format_string.format(procdetails, procdetails.pdet_link.tqe_next, procdetails.pdet_link.tqe_prev) 156 out_string += GetNstatProcdetailsBrief(procdetails) 157 158 print(out_string) 159 160def GetNstatTUShadowBrief(shadow): 161 """ Display a summary for an nstat_tu_shadow struct 162 params: 163 shadow : cvalue object which points to 'struct nstat_tu_shadow *' 164 returns: 165 str : A string describing various information for the nstat_tu_shadow structure 166 """ 167 out_string = "" 168 shad = Cast(shadow, 'struct nstat_tu_shadow *') 169 procdetails = shad.shad_procdetails 170 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 171 out_string = "" 172 if shad : 173 format_string = " shadow {0: <#0x}: necp_client={1: <#020x} live={2: <d}" 174 out_string += format_string.format(shad, shad.shad_provider_context, shad.shad_live) 175 magic = unsigned(shad.shad_magic) 176 if (magic != TU_SHADOW_MAGIC) : 177 format_string = " INVALID shad magic {0: <#0x}" 178 out_string += format_string.format(magic) 179 elif (procdetails) : 180 out_string += GetNstatProcdetailsBrief(procdetails) 181 182 return out_string 183 184def GetNstatGenericShadowBrief(shadow): 185 """ Display a summary for an nstat_generic_shadow struct 186 params: 187 shadow : cvalue object which points to 'struct nstat_generic_shadow *' 188 returns: 189 str : A string describing various information for the nstat_tu_shadow structure 190 """ 191 gshad = Cast(shadow, 'struct nstat_generic_shadow *') 192 procdetails = gshad.gshad_procdetails 193 procdetails = Cast(procdetails, 'struct nstat_procdetails *') 194 out_string = "" 195 if gshad : 196 format_string = " gshadow {0: <#0x}:" 197 out_string += format_string.format(gshad) 198 if (gshad.gshad_provider == NSTAT_PROVIDER.CONN_USERLAND) : 199 out_string += "necp_client={0: <#020x} ".format(gshad.gshad_provider_context) 200 elif (gshad.gshad_provider == NSTAT_PROVIDER.UDP_SUBFLOW) : 201 out_string += "soflow_hash_entry={0: <#020x} ".format(gshad.gshad_provider_context) 202 else : 203 out_string += "context {0: <#020x} ".format(gshad.gshad_provider_context) 204 out_string += " refcnt={0: <d} ".format(gshad.gshad_refcnt) 205 206 magic = unsigned(gshad.gshad_magic) 207 if (magic != NSTAT_GENERIC_SHADOW_MAGIC) : 208 format_string = " INVALID gshad magic {0: <#0x}" 209 out_string += format_string.format(magic) 210 elif (procdetails) : 211 out_string += GetNstatProcdetailsBrief(procdetails) 212 213 return out_string 214 215def GetNstatTUCookieBrief(cookie): 216 """ Display a summary for an nstat_tucookie struct 217 params: 218 shadow : cvalue object which points to 'struct nstat_tucookie *' 219 returns: 220 str : A string describing various information for the nstat_tucookie structure 221 """ 222 out_string = "" 223 tucookie = Cast(cookie, 'struct nstat_tucookie *') 224 inp = tucookie.inp 225 pname = tucookie.pname 226 inpcb = Cast(inp, 'struct inpcb *') 227 inp_socket = inpcb.inp_socket 228 sock = Cast(inp_socket, 'struct socket *') 229 format_string = " inpcb={0: <#0x}: socket={1: <#020x} process={2: <s}" 230 out_string += format_string.format(inpcb, sock, pname) 231 return out_string 232 233def GetNstatProviderString(provider): 234 providers = { 235 NSTAT_PROVIDER.NONE: "none", 236 NSTAT_PROVIDER.ROUTE: "route", 237 NSTAT_PROVIDER.TCP_KERNEL: "TCP k", 238 NSTAT_PROVIDER.TCP_USERLAND: "TCP u", 239 NSTAT_PROVIDER.UDP_KERNEL: "UDP k", 240 NSTAT_PROVIDER.UDP_USERLAND: "UDP u", 241 NSTAT_PROVIDER.IFNET: "ifnet", 242 NSTAT_PROVIDER.SYSINFO: "sysinfo", 243 NSTAT_PROVIDER.QUIC_USERLAND: "quic u", 244 NSTAT_PROVIDER.CONN_USERLAND: "conn u", 245 NSTAT_PROVIDER.UDP_SUBFLOW: "subflow", 246 } 247 return providers.get(unsigned(provider), "unknown") 248 249def ShowNstatSrc(insrc): 250 """ Display summary for an nstat_src struct 251 params: 252 insrc : cvalue object which points to 'struct nstat_src *' 253 """ 254 src = Cast(insrc, 'nstat_src *') 255 prov = src.nts_provider 256 prov = Cast(prov, 'nstat_provider *') 257 prov_string = GetNstatProviderString(prov.nstat_provider_id) 258 out_string = "" 259 if src : 260 format_string = " nstat_src {0: <#0x}: prov={1: <8s} next={2: <#020x} prev={3: <#020x} srcref={4: <d} seq={5: <d}" 261 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) 262 263 if ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_USERLAND) or 264 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_USERLAND) or 265 (prov.nstat_provider_id == NSTAT_PROVIDER.QUIC_USERLAND)) : 266 out_string += GetNstatTUShadowBrief(src.nts_cookie); 267 elif ((prov.nstat_provider_id == NSTAT_PROVIDER.CONN_USERLAND) or 268 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_SUBFLOW)) : 269 out_string += GetNstatGenericShadowBrief(src.nts_cookie); 270 elif ((prov.nstat_provider_id == NSTAT_PROVIDER.TCP_KERNEL) or 271 (prov.nstat_provider_id == NSTAT_PROVIDER.UDP_KERNEL)) : 272 out_string += GetNstatTUCookieBrief(src.nts_cookie); 273 274 print(out_string) 275 276def ShowNstatClient(inclient, reverse): 277 """ Display an nstat_client struct 278 params: 279 client : value object representing an nstat_client in the kernel 280 """ 281 client = Cast(inclient, 'nstat_client *') 282 out_string = "" 283 if client : 284 format_string = "nstat_client {0: <#0x}: next={1: <#020x} src-head={2: <#020x} tail={3: <#020x}" 285 out_string += format_string.format(client, client.ntc_next, client.ntc_src_queue.tqh_first, client.ntc_src_queue.tqh_last) 286 procdetails = client.ntc_procdetails 287 if (procdetails) : 288 format_string = " --> procdetails {0: <#0x}: pid={1: <d} name={2: <s} refcnt={3: <d}" 289 out_string += format_string.format(procdetails, procdetails.pdet_pid, procdetails.pdet_procname, procdetails.pdet_refcnt) 290 291 print(out_string) 292 if reverse: 293 print("\nreverse nstat_src list:\n") 294 iterator = ReverseIterateTAILQ_AnonymousHEAD(client.ntc_src_queue, 'nts_client_link', 'struct nstat_src *') 295 else: 296 print("\nreverse nstat_src list:\n") 297 iterator = IterateTAILQ_HEAD(client.ntc_src_queue, 'nts_client_link') 298 for src in iterator: 299 ShowNstatSrc(src) 300 301###################################### 302# Print functions 303###################################### 304def PrintNstatClientList(reverse): 305 print("nstat_clients list:\n") 306 client = kern.globals.nstat_clients 307 client = cast(client, 'nstat_client *') 308 while client != 0: 309 ShowNstatClient(client, reverse) 310 client = cast(client.ntc_next, 'nstat_client *') 311 312def PrintNstatProcdetailList(reverse): 313 procdetails_head = kern.globals.nstat_procdetails_head 314 if reverse: 315 print("\nreverse nstat_procdetails list:\n") 316 iterator = ReverseIterateTAILQ_AnonymousHEAD(procdetails_head, 'pdet_link', 'struct nstat_procdetails *') 317 else: 318 print("\nnstat_procdetails list:\n") 319 iterator = IterateTAILQ_HEAD(procdetails_head, 'pdet_link') 320 for procdetails in iterator: 321 ShowNstatProcdetails(procdetails) 322 323def PrintNstatGenericShadowList(reverse): 324 gshadows = kern.globals.nstat_gshad_head 325 if reverse: 326 print("\nreverse nstat_ghsad list:\n") 327 iterator = ReverseIterateTAILQ_AnonymousHEAD(gshadows, 'gshad_link', 'struct nstat_generic_shadow *') 328 else: 329 print("\nnstat_ghsad list:\n") 330 iterator = IterateTAILQ_HEAD(gshadows, 'gshad_link') 331 for gshad in iterator: 332 ShowNstatGShadow(gshad) 333 334def PrintNstatTUShadowList(reverse): 335 shadows = kern.globals.nstat_userprot_shad_head 336 if reverse: 337 print("\nreverse nstat_userprot_shad list:\n") 338 iterator = ReverseIterateTAILQ_AnonymousHEAD(shadows, 'shad_link', 'struct nstat_tu_shadow *') 339 else: 340 print("\nnstat_userprot_shad list:\n") 341 iterator = IterateTAILQ_HEAD(shadows, 'shad_link') 342 for shad in iterator: 343 ShowNstatTUShadow(shad) 344 345###################################### 346# LLDB commands 347###################################### 348# Macro: showallntstat 349 350@lldb_command('showallntstat', 'R') 351def ShowAllNtstat(cmd_args=None, cmd_options={}) : 352 """ Show the contents of various ntstat (network statistics) data structures 353 354 usage: showallntstat [-R] 355 -R : print ntstat list in reverse 356 """ 357 reverse = '-R' in cmd_options 358 359 PrintNstatClientList(reverse) 360 PrintNstatTUShadowList(reverse) 361 PrintNstatGenericShadowList(reverse) 362 PrintNstatProcdetailList(reverse) 363 364# EndMacro: showallntstat 365