Telcoladder

io.github.gollumw由 GitHub 帳號 gollumw 發布v0.4.0更新於 Oct 24, 2026

Turn a signalling pcap into per-subscriber call flows: 5G, 4G and IMS, every failure explained

概覽

AI 產生的概覽

一個本機 MCP 伺服器,把 5G、4G 與 IMS 信令擷取檔轉換成依用戶劃分的通話流程,並提供經核實的失敗原因說明。

可以做什麼
分析 pcap 或 pcapng 擷取檔,把單一用戶在 NGAP、NAS、SBI、PFCP、GTP、S1AP、Diameter 與 SIP 上的流量關聯成一條通話流程,與命令列工具和瀏覽器檢視使用同一套確定性事實。依人工核實的成因表解釋失敗,給出規範名稱、白話含義與欄位層級根因,表中沒有的原因則如實標為未收錄。把用戶流量拆分為註冊、attach、PDU 工作階段、換手、去註冊與 IMS 通話等情境,附上結果、原因、首個失敗與時長。判定 UE 內容釋放由 RAN 發起或由核心網路下令,並標出與 NAS 計時器預設值相符的間隔。明確列出無法讀取的內容,例如加密 NAS、受保護的 SUPI 與 SBI 上的 TLS。
適用情境
適用於核心網路 SRE、RAN 與核心網路互通測試及三線故障排除:當你本身熟悉信令,希望助理跨介面關聯單一用戶,並依經核實的成因表解釋失敗,而不是只給出一個原因編號。
執行需求
以 PyPI 套件 telcoladder 在本機透過 stdio 執行,需要 Python 3.11+ 以及 Wireshark 4.0 或更新版本中的 tshark;tshark 會從標準安裝目錄尋找,也可透過 TELCOLADDER_TSHARK 環境變數指定。不需帳號、API 金鑰或網路存取。
安裝前請注意
擷取檔包含用戶身分、位址與金鑰;此工具設計為完全本機執行、無遙測、無模型,但仍應將擷取檔視為敏感資料。anonymize 命令只能證明 tshark 能辨識的值已被替換,加密 NAS、SBI 上的 TLS 與加密 ESP 無法讀取,只會被計數而不會解碼。分析對擷取檔為唯讀。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Telcoladder,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

TelcoLadder

Deterministic 5G / 4G / IMS signalling analyzer and call-flow correlator. The correlation and root-cause layer on top of tshark: one subscriber across every interface, every failure explained from a verified cause table, and nothing generated.

[CI] [PyPI] [Python] [Causes] [Oracle] [Offline] [License]

For core-network SRE and R&D, RAN/core interoperability test, and third-line troubleshooting at vendors and operators. It assumes you already read signalling for a living.

bash
pip install telcoladdertelcoladder check                             # verifies tshark and its dissectorstelcoladder summarize failed_attach.pcapng    # one page of facts, every failure cited

[Drop a capture, get each subscriber's correlated ladder — failures explained with their specification reference and the most common field causes]

What you get

Two outputs from one analysis. Mermaid you can paste into a ticket:

mermaid
sequenceDiagram    autonumber    participant gNB    participant AMF    Note over gNB,AMF: SUPI 001011234567895    gNB->>AMF: #35;7 InitialUEMessage ▸ Registration request    AMF->>gNB: #35;8 DownlinkNASTransport ▸ Authentication request    rect rgb(255, 226, 226)    gNB->>AMF: #35;9 UplinkNASTransport ▸ Authentication failure    Note over AMF: Synch failure (#35;21) — 3GPP TS 24.501 §9.11.3.2    end    rect rgb(255, 226, 226)    AMF->>gNB: #35;10 DownlinkNASTransport ▸ Registration reject    Note over gNB: Protocol error, unspecified (#35;111) — 3GPP TS 24.501 §9.11.3.2    end

That is real output from tests/fixtures/ki-mismatch, not an illustration: a UE provisioned with the wrong key, captured on a local Open5GS testbed. It is not the MAC failure you would expect — a UE whose K does not match computes an AUTS the network cannot resynchronise from, so you get #21 and then a bare #111. The cause table says so because we ran it, not because it sounded right.

And the same capture in the browser: a packet list driven by real tshark display filters, per-frame decode tree and bytes, the ladder with the initiator and the cause on every failing event, and a per-PDU-session matrix where every cell cites the frame it came from.

[TelcoLadder browser interface]

What it reads

GenerationProtocolsCause explanations
5G coreNGAP, NAS-5GS, HTTP/2 SBI, PFCP, GTP-U206
4G / EPCS1AP, NAS-EPS, GTPv2-C (S11, S5/S8, N26), SGsAP (SGs)236
IMSSIP (calls, KPIs), Diameter, H.248/MEGACO333

Every cause code is resolved through a hand-verified table to the specification it comes from, what it means in plain language, and the root causes that actually produce it in the field — 775 of them, every name taken verbatim from tshark and re-checked against it by a test. Nothing is generated: a cause the table does not carry is reported as not catalogued, and a clause number is printed only where a person transcribed it. Every network function is named rather than shown as an IP, with the evidence for that name on hover.

The pain, and what replaces it

TodayWith TelcoLadder
Copying UE IDs by hand between windows to follow one subscriberOne subscriber's whole lifetime in one flow: SUPI, 5G-S-TMSI, NGAP and S1AP UE IDs, TEIDs, Call-ID — with keys that are recycled treated as recycled
N2 and SBI in separate captures that never line upN2, SBI and N4 stitched on one timeline; N4 joins through the GTP-U tunnel endpoint the UPF allocated and NGAP relayed
An N26 handover spread across NGAP, N26, S11 and S1APOne segment across all four, joined through the S1-U SGW F-TEID the MME copies from Create Session Response into HandoverRequest
A bare cause number and a trip to the spec775 causes with the specification named, plain language and field root causes; clauses where a person checked them
RAN and core blaming each other for a dropped contextEvery UE context release marked requested by the RAN or ordered by the core — a wire fact, not an opinion
A procedure that stalls for no visible reasonThe gap named when it matches a NAS timer's default (T3560, T3460 …), and failures counted by TAC, cell, DNN and core element
VoLTE Gm signalling hidden inside IPsec ESPNULL-encrypted ESP is detected and decoded, so the SIP and SDP inside join the subscriber's ladder. ESP that is really encrypted stays unreadable and is counted, not guessed
A B2BUA (an AS, or an SBC that keeps the charging ID) changes the Call-ID, so one call shows up as unrelated dialogsLegs that share a charging ID (ICID) and overlap in time are one call, end to end — H.248, HSS, charging and ENUM attached only where evidence ties them to that call
Customer captures that must never leave the buildingA command on your machine: no network listener beyond 127.0.0.1, no telemetry, no cloud, no model

Quickstart: five ways in

Windows without Python? Skip pip and jump to 4. Windows, no install — the only prerequisite is Wireshark.

bash
# 1. CLI — one page of deterministic facts, Markdown or JSONtelcoladder summarize capture.pcapngtelcoladder analyze capture.pcapng -o flow.mmd      # Mermaid, byte-for-byte reproducible
# 2. Browser — drop a capture, or paste a path for anything largetelcoladder serve                                   # http://127.0.0.1:3005
# 3. AI agent — the same facts as MCP tools over stdioclaude mcp add telcoladder -- telcoladder mcp

4. Windows, no install. A standalone executable in a portable zip, built by CI from the tagged source. Nothing is installed and no registry key is written; it needs Wireshark 4.0 or newer on the machine, nothing else.

  1. Download and unzip. Get TelcoLadder-Windows-x64.zip (about 10 MB) from the Releases page.
  2. Double-click check-environment.cmd. It finds tshark.exe in Wireshark's default install location under Program Files — or wherever TELCOLADDER_TSHARK points — and checks the dissectors.
  3. Run it from that folder.
    bat
    telcoladder.exe summarize capture.pcapngtelcoladder.exe serve
    serve listens on http://127.0.0.1:3005: open it in your browser, drop a capture (up to 1 GB), or paste a path for anything larger.

5. Hand a capture to someone else. telcoladder anonymize in.pcap out.pcap rewrites subscriber identities, addresses, hostnames, PLMN and cell identifiers into keyed pseudonyms of the same length — TBCD, ASCII, JSON and HPACK-Huffman alike — recomputes every checksum, then re-reads its own output and refuses to keep it if any original value is still visible. The output walks the same pipeline to the same procedures, roles and failures; only the names differ. Same key, same pseudonyms across captures; the key is printed once and never written down. Compressed HTTP/2 bodies cannot be rewritten in place and are refused unless --blank-opaque-bodies.

Requires Python 3.11+ and tshark (Wireshark 4.0 or newer) for the pip route. Neither the macOS nor the Windows installer puts tshark on your PATH; TelcoLadder looks in the standard install directories and finds it anyway, or takes TELCOLADDER_TSHARK. The venv-by-venv Windows walkthrough is in the user guide.

Five things it does that a decoder does not

Cross-interface correlation. A subscriber is a union of identity keys, each with the right scope: NGAP and S1AP UE IDs are unique only within one association, TEIDs and TMSIs are reallocated and treated as episodes, and the GTP-U tunnel endpoint is one definition shared by NGAP, PFCP, GTP-U and now S1AP. The failure mode of a wrong key is two people in one flow with a ladder that still renders, so the key shapes are tested against captures built to provoke exactly that.

775 verified causes. Names from tshark -G values, re-checked by tests on every CI platform; two Diameter number spaces kept apart; NGAP and S1AP cause groups looked up in the group the message selected. Ordered-sequence rules written by people — #21 followed by #111 is a key mismatch, not a sequence problem — are matched and reported with the frames.

Fault attribution. UEContextReleaseRequest is only ever sent by the RAN and the release Command only by the core; the ladder, the procedure list and the xDR say which one started it. The reason still comes from the cause table; there is no second verdict string.

Timer match and blast radius. An unanswered network request followed by a release or reject a timer's default later is reported as consistent with that timer — never as a proven timeout, because the capture shows timing and not the AMF's state. With several subscribers, failures are counted by TAC, cell, DNN and core-side element; an unknown location is a null row, not a dropped one.

Air-gapped by construction. serve binds 127.0.0.1 and checks the Host header; the MCP server is stdio only; the browser bundle ships in the package and loads nothing from the network; there is no telemetry and no model. What the tool could not read — ciphered NAS, ECIES-protected SUCIs, TLS on SBI, frames no dissector claimed — is counted and stated before any conclusion.

Three scenarios from the test captures

Each of these is a fixture in tests/fixtures/ you can run yourself.

  1. A key mismatch that does not look like one — ki-mismatch. Synch failure (#21) then a bare protocol error (#111). The sequence rule in the cause table names the real cause and says what does not fix it: resetting the SQN. telcoladder summarize tests/fixtures/ki-mismatch/capture.pcap
  2. A context released 6.000 s after an unanswered Authentication request — 5gc-context-release. The release is marked as ordered by the core, and the gap is reported as consistent with T3560's default. The second subscriber in the same file is released at the gNB's request after the radio link was lost, and is marked as such.
  3. A 5GS → EPS handover the target eNB refuses — n26-handover. Five elements on one ladder; the failure appears three times on the wire (S1AP HandoverFailure, the N26 Forward Relocation Response, the NGAP HandoverPreparationFailure) and is explained once, from the S1AP table, with the specification named and no clause invented.

What it does today

  • Reads all three generations from one pcap / pcapng via tshark.
  • Names the network functions and shows the IP when the evidence is ambiguous rather than guessing. Relays — a 5G SCP, a Diameter DRA, a SIP proxy — keep their own lane and are never credited with the services behind them.
  • Correlates one subscriber across identifiers and across protocols, with the scopes described above. On a production trace with TLS on SBI and ECIES-protected SUCIs the N2 side still forms its own per-UE flow; what could not be read is counted and reported, not silently dropped.
  • Splits a subscriber's traffic into scenarios — registration, attach, PDU session, service request (UE- or network-triggered), dedicated bearer setup, modification and release, deregistration, handover (including one that was cancelled, which is not a failure), idle mobility, IMS registration and call — each with outcome, cause, first failure, duration, and where applicable the initiator, the matched timer, or the handover preparation and execution times. The axis is what the subscriber was doing, not which protocol carried it: the S6a exchange inside an attach is part of that attach, the context release that ends a scenario is part of that scenario (its initiator and cause travel with it, and the xDR still lists the release as a row of its own), and an HSS answer of "unknown user" is that attach's failure. A Diameter exchange that belongs to no scenario stands on its own as an HSS-initiated one — under 4G for S6a/Gx and under IMS for Cx/Sh, which the Application-Id decides.
  • Reads Diameter through the DRA: S6a/S6d, Cx/Dx, Sh, Rx, Gx, SWx and S6b, roles from who initiates which command, a request seen on both sides of a relay shown as one transaction with two hops, a relayed failure counted once.
  • Treats a SIP call as a procedure with time to ring, to answer and talk time, who released it and why, and a busy or declined callee as ended-by-user rather than a failure — a classification that lives in the cause table, not in code.
  • Exports procedure records (--xdr) and a pinned-field JSON summary, both byte-for-byte reproducible, so jq can answer "what is the failure rate across this batch".
  • Speaks English or Traditional Chinese (--lang zh_TW, or the switch in the browser), deliberately never the system locale: the same command must print the same words on two machines, because output gets pasted into tickets.
  • Needs to be told about non-standard ports. A capture that starts after the TCP connections are up has no HTTP/2 preface for tshark to find; adapters declare the common cases and --decode-as covers the rest.

On a large capture, narrow before you draw:

bash
telcoladder analyze big.pcapng --subscriber 001011234567895telcoladder analyze big.pcapng --since 120 --until 180telcoladder analyze big.pcapng --filter 'ngap || s1ap'      # any tshark display filter

Whatever narrowing could not reach is listed explicitly, never silently dropped. Dissection runs at roughly 0.19 s/MB and is linear (a 145 MB, 780k-frame file in 28 s on one machine); tshark output is streamed, so memory follows the messages kept rather than the file size.

Prior art, and why this exists anyway

These tools came first and are worth your time. TelcoLadder is not trying to replace them.

ProjectWhat it doesWhy TelcoLadder still exists
telekom/5g-trace-visualizerpcap → SVG sequence diagrams for 5GC (HTTP/2, NAS, PFCP). Deutsche Telekom, Apache-2.0.Unmaintained since Aug 2023. PlantUML output needs plantuml.jar; driven from Jupyter notebooks with a large config surface aimed at k8s deployments.
irontec/sngrepExcellent, actively maintained ncurses SIP flow viewer.Terminal-only and SIP-only — you cannot paste its output into a document, and it does not touch 5G.
sipcapture/homerFull capture platform: server, agents, database, web UI.It is infrastructure you deploy and operate. TelcoLadder is a command you run against one file.
dgudtsov/pcap2umlIMS call flows across SIP/Diameter/MAP/CAMEL → PlantUML.The closest in spirit. No 5G support (no NGAP/NAS-5GS), PlantUML output.
agranig/pcap2mermaidSIP → Mermaid, in Perl.Two days of commits in January 2019, then nothing. It proved people want this; nobody picked it up.

What none of them do together: 5G and 4G and IMS in one correlated diagram, Mermaid as the output, and a verified explanation of what went wrong.

Honest limitations

  • SBI is verified against exactly one deployment, Open5GS with an SCP, and only for null-scheme SUCIs and cleartext h2c. Production SBI is usually TLS: those frames are counted in not visible, per port. tshark preferences pass straight through (--tshark-pref tls.keylog_file:…), so a key log can be supplied as in Wireshark, but no TLS fixture exists here and that path is not covered by the tests. N2 is unaffected either way.
  • A fully transparent SCP that sends no 3gpp-Sbi-Target-apiRoot is indistinguishable from the endpoint and falls back to an unlabelled IP. The correct failure direction, and a real gap.
  • Diameter covers seven interfaces with roles and curated causes (S6a/S6d, Cx/Dx, Sh, Rx, Gx, SWx, S6b); the rest — Rf included — decode and show their Application-Id with no role inference. Every Diameter fixture is written from RFC 6733, not captured: TCP only, no SCTP, invented timing.
  • Four behavior rules have no capture behind them. S10 inter-MME handover, the Xn/X2 path switch, CS fallback and the Cx authentication delay inside a call are written from message names and covered only by synthetic tests; how they read a real capture is unmeasured. The chain shown before a failure is the order of messages within one segment, not proven causation.
  • SIP alone does not name the core proxies. The UE and the P-CSCF come from Gm itself — the security-agreement headers, or which address holds IPsec associations with several peers, falling back to a Contact that carries a subscriber identity; an I-CSCF, S-CSCF or AS is named only when its Cx or Sh exchange is in the same capture. Gm is the only SIP reference point labelled — Mw and ISC are not, because no capture here has verified them. H.248 gets neutral MGC / MGW roles and no reference point, because the protocol alone cannot say whether it is Iq, Mn or Mp.
  • Calls and numbers join only on evidence. B2BUA legs become one call only when they share a charging ID (ICID) and overlap in time — a B2BUA or SBC that replaces the ICID leaves separate rows. A number joins HSS, charging and ENUM records only in international form; a local-form number is never completed with a guessed country code. VoLTE, VoNR and VoWiFi are shown only where P-Access-Network-Info declares them; without that header the access is reported as not declared.
  • Only 9 of the 21 cause tables cite a clause. The other 12 name the specification and stop. An absent clause is better than a wrong one.
  • The 4G, IMS and handover fixtures are written byte by byte with tshark as the oracle: exact about the protocol, silent about any real deployment. Each scenario.md lists what its fixture cannot prove. UE radio capability is not parsed: the NR and LTE RRC containers are skipped during extraction because dissecting them is slow, and stay readable in the per-frame decode tree.
  • NAS after Security Mode Command is encrypted and its content is invisible; the packets still appear as their NGAP carrier. The same holds for IPsec ESP on Gm: only NULL-encrypted ESP is read, and encrypted ESP is counted as unreadable. GTP-U joins the subscriber but carries no throughput or loss KPIs; there is no RTP adapter; ISUP and CAMEL are recognised but not read.
  • Joins through a tunnel an SBI message quotes are inferences. They bind by direction, inside a time window, never across a release, and never where they would give one flow two SUPIs; the summary counts each one. What remains: a stale forwarded quote that arrives after its tunnel was released, where the UPF reused that exact TEID within 10 s for a UE whose flow shows no SUPI, could still be joined. On a single capture point that order violates the protocol.
  • Mermaid gets slow with very large flows. Use --max-messages; truncation is always stated inside the diagram.
  • anonymize proves absence only for what tshark can name. Identities it never decoded stay where they are; TLS payloads are opaque; gzip bodies and bodies reassembled across DATA frames are refused rather than guessed at; IPv6 text and binary forms, and TAC text and binary forms, are pseudonymised independently. The report lists every one of these.

How it is verified

A flow missing three messages looks exactly like a correct one, so the suite cross-checks against tshark as an independent oracle rather than only asserting on its own parse: message counts, procedure and message names, every cause table, and the identity keys of the fixtures built to provoke a wrong merge. New tests are mutation-checked — the code is broken on purpose and the test must go red. Every push runs the full suite on Python 3.11, 3.12 and 3.13 on Linux with tshark 4.2, and on macOS and Windows with tshark 4.6; the badge at the top is live. What the badge does not cover is named at the top of .github/workflows/ci.yml.

Air-gapped by construction

There is no network path out of this tool. The analysis is a child tshark process reading a file; serve binds the loopback address only and refuses other Host headers; the MCP transport is stdio; the browser bundle is packaged with the code and references no external resource; nothing phones home and no model is involved anywhere in the pipeline. Uploaded captures are kept in the system temp directory with mode 0600 until released or idle-expired, and for anything large you paste a path so nothing is copied at all.

Going deeper

The engine — streaming architecture and its measured throughput, the identity model and key recycling, the cause library and its oracle discipline, the N26 stitching, release attribution, timers — is written up in docs/deep-dive.md. The operating guide for real captures is docs/user-guide.md; the contract for adding a protocol is docs/plugin-contract.md; the contract for an agent using the tool is AGENTS.md.

Contributing, and reporting problems

CONTRIBUTING.md is short. It has two rules that matter more than anything else in it: no real subscriber or customer data, anywhere, and every spec clause is verified by a human, never generated.

Found a vulnerability? SECURITY.md — not a public issue.

License

PolyForm Noncommercial License 1.0.0. See LICENSE.

Free for personal, non-commercial, and educational research use. Commercial deployment, commercial distribution, or embedding into for-profit offerings requires a separate commercial licence: open a GitHub issue titled "Commercial licence" or contact the maintainer through the repository, and expect a reply on terms rather than a form.

Release 0.1.0 was published under Apache-2.0 and remains available under those terms. Third-party material keeps its own licence: the browser bundle's dependencies (MIT/ISC, listed in NOTICE) and the http2-multistream fixture (Apache-2.0, Deutsche Telekom).

來源:README.md,提交 c4e1a13

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

2
  1. v0.4.0最新Sep 17, 2026
  2. v0.3.0Sep 16, 2026

評分

已滿足適用檢查項的 40%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

    請在儲存庫或註冊中心條目中宣告授權條款。