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