tunnelscope 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tunnelscope-0.2.1/LICENSE +21 -0
- tunnelscope-0.2.1/MANIFEST.in +5 -0
- tunnelscope-0.2.1/PKG-INFO +166 -0
- tunnelscope-0.2.1/README.md +150 -0
- tunnelscope-0.2.1/docs/bidirectional.md +77 -0
- tunnelscope-0.2.1/docs/demo.md +67 -0
- tunnelscope-0.2.1/docs/images/two-vm-results.png +0 -0
- tunnelscope-0.2.1/docs/receiver-observations.md +55 -0
- tunnelscope-0.2.1/docs/releases/v0.2.1.md +24 -0
- tunnelscope-0.2.1/docs/v0.1-scope.md +32 -0
- tunnelscope-0.2.1/docs/validation/ack-return-blocked.md +25 -0
- tunnelscope-0.2.1/docs/validation/mtu-boundary.md +65 -0
- tunnelscope-0.2.1/docs/validation/pmtu-blackhole.md +54 -0
- tunnelscope-0.2.1/docs/validation/two-vm-field-test.md +48 -0
- tunnelscope-0.2.1/docs/validation/two-vm-receiver-correlation.md +50 -0
- tunnelscope-0.2.1/examples/mtu-boundary.json +269 -0
- tunnelscope-0.2.1/examples/pmtu-blackhole.json +153 -0
- tunnelscope-0.2.1/labs/ack_return_blocked.py +118 -0
- tunnelscope-0.2.1/labs/mtu_boundary.py +80 -0
- tunnelscope-0.2.1/labs/pmtu_blackhole.py +113 -0
- tunnelscope-0.2.1/pyproject.toml +28 -0
- tunnelscope-0.2.1/setup.cfg +4 -0
- tunnelscope-0.2.1/tests/test_delivery.py +213 -0
- tunnelscope-0.2.1/tests/test_fragmentation.py +103 -0
- tunnelscope-0.2.1/tunnelscope-logo-blue.png +0 -0
- tunnelscope-0.2.1/tunnelscope.egg-info/PKG-INFO +166 -0
- tunnelscope-0.2.1/tunnelscope.egg-info/SOURCES.txt +29 -0
- tunnelscope-0.2.1/tunnelscope.egg-info/dependency_links.txt +1 -0
- tunnelscope-0.2.1/tunnelscope.egg-info/entry_points.txt +2 -0
- tunnelscope-0.2.1/tunnelscope.egg-info/top_level.txt +1 -0
- tunnelscope-0.2.1/tunnelscope.py +517 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TunnelScope contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tunnelscope
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Evidence-based MTU and packet-size diagnostics for Linux networks
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Repository, https://github.com/lazypanic999/tunnelscope
|
|
7
|
+
Keywords: network,mtu,pmtu,diagnostics
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
<img src="https://raw.githubusercontent.com/lazypanic999/tunnelscope/main/tunnelscope-logo-blue.png" alt="TunnelScope blue compass and vortex logo" width="400">
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
# TunnelScope
|
|
22
|
+
|
|
23
|
+
Evidence-based MTU and packet-size diagnostics for Linux networks.
|
|
24
|
+
|
|
25
|
+
**Status: v0.2.1 alpha prototype. UDP delivery probes, Linux IPv4 Don't Fragment mode, per-direction report combination, optional receiver observations and controlled MTU labs are available. Automatic path-MTU discovery and root-cause diagnosis are not implemented.**
|
|
26
|
+
|
|
27
|
+
## The problem
|
|
28
|
+
|
|
29
|
+
A connection can appear healthy while larger transfers fail. Small probes may succeed even when larger packets cannot traverse the path. Tunnel overhead, MTU configuration and blocked Path MTU Discovery feedback can contribute to this behavior. Other causes can produce similar symptoms.
|
|
30
|
+
|
|
31
|
+
TunnelScope aims to help network engineers, system administrators and learners investigate these failures through repeatable measurements and inspectable evidence.
|
|
32
|
+
|
|
33
|
+
## Planned first version
|
|
34
|
+
|
|
35
|
+
- A Python command-line tool and a cooperating receiver for controlled Linux environments.
|
|
36
|
+
- Repeated, size-controlled IPv4 UDP probes with fragmentation disabled.
|
|
37
|
+
- Separate measurements for each direction, with timeouts and loss recorded explicitly.
|
|
38
|
+
- JSON reports containing probe sizes, outcomes, relevant interface information and test settings.
|
|
39
|
+
- A reproducible Linux lab demonstrating healthy delivery, explicit packet-too-large feedback and a possible PMTU black hole.
|
|
40
|
+
|
|
41
|
+
A failed probe alone will not be labeled as proof of an MTU problem. Reports separate observations, hypotheses and missing evidence. An observed working packet size is not presented as the exact path MTU.
|
|
42
|
+
|
|
43
|
+
## Milestones
|
|
44
|
+
|
|
45
|
+
- [x] **M0 - Reproduce the problem:** build a small Linux network-namespace lab and record a healthy baseline and a controlled MTU failure.
|
|
46
|
+
- [x] **M1 - Probe and receive:** implement bounded, identifiable probes and acknowledgements between two endpoints.
|
|
47
|
+
- [x] **M2 - Explain the evidence:** export JSON and distinguish successful delivery, explicit errors and inconclusive timeouts.
|
|
48
|
+
- [x] **M3 - Validate:** check the tool against known lab configurations, document limitations and publish a short demo.
|
|
49
|
+
- [x] **M4 - Observe at the receiver:** record which identified probes reached the cooperating receiver and correlate them with sender outcomes.
|
|
50
|
+
- [x] **M5 - Make evidence usable:** validate receiver-observed timeouts in a controlled lab and provide a concise terminal view of reports.
|
|
51
|
+
|
|
52
|
+
Kubernetes, VPN-specific workflows, IPv6 and 5G user-plane tunnels are possible later directions. They are not currently supported features.
|
|
53
|
+
|
|
54
|
+
For a quick walkthrough of both controlled failure modes, see the [two-minute Linux demo](https://github.com/lazypanic999/tunnelscope/blob/main/docs/demo.md).
|
|
55
|
+
The [two-VM validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/two-vm-field-test.md) documents a successful bidirectional DF run between Ubuntu and Debian guests.
|
|
56
|
+
The [v0.1 scope](https://github.com/lazypanic999/tunnelscope/blob/main/docs/v0.1-scope.md) lists what the installable prototype does and does not cover.
|
|
57
|
+
The [v0.2 receiver workflow](https://github.com/lazypanic999/tunnelscope/blob/main/docs/receiver-observations.md) explains how to capture and correlate receiver evidence.
|
|
58
|
+
The [two-VM correlation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/two-vm-receiver-correlation.md) documents the new workflow on independent Linux guests.
|
|
59
|
+
The [blocked ACK return lab](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/ack-return-blocked.md) validates a receiver-observed sender timeout.
|
|
60
|
+
|
|
61
|
+
Use `tunnelscope show report.json` for a short terminal table of a probe,
|
|
62
|
+
bidirectional comparison, correlation, or lab report. JSON remains the
|
|
63
|
+
machine-readable source of evidence.
|
|
64
|
+
|
|
65
|
+
## Install locally
|
|
66
|
+
|
|
67
|
+
From the repository root, in a Python 3.10+ virtual environment:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
python3 -m pip install .
|
|
71
|
+
tunnelscope --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The package installs the `tunnelscope` command. It has no third-party runtime dependencies. Published releases can be installed with `python3 -m pip install tunnelscope`. The laboratory scripts still run from a source checkout.
|
|
75
|
+
|
|
76
|
+
## Getting started
|
|
77
|
+
|
|
78
|
+
Requires Python 3.10 or newer. No third-party runtime packages are needed. Start with a local experiment in two terminals, from the repository directory. Use `tunnelscope` in place of `python tunnelscope.py` after installing the package.
|
|
79
|
+
|
|
80
|
+
Terminal 1 (receiver):
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
python tunnelscope.py receive
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Terminal 2 (sender):
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
python tunnelscope.py probe 127.0.0.1 --sizes 64,512,1200,1400 --count 3 --output report.json
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The receiver exits after 100 datagrams or 30 seconds without a datagram. Restart it if it has already exited. `--max-packets` and `--idle-timeout` change these limits.
|
|
93
|
+
|
|
94
|
+
Probe sizes are **UDP payload bytes**, including TunnelScope's 24-byte header. They exclude IP and UDP headers. The receiver sends only a small acknowledgement, so this is not a same-sized round-trip test. Reverse endpoint roles to investigate delivery in the other direction.
|
|
95
|
+
|
|
96
|
+
Each probe report includes a `source` snapshot taken from the first connected sender socket. It records the local IPv4 address. On Linux, it also records the selected interface and its link MTU when discoverable, plus `kernel_route_mtu_bytes` when the kernel supplies it. The link MTU and kernel route MTU are different facts; neither is an independently measured end-to-end path MTU. A failed connection may leave `source` as `null`, and optional fields may be absent.
|
|
97
|
+
|
|
98
|
+
`acknowledged` means that the receiver got that payload and its acknowledgement returned. `timeout` means no matching acknowledgement arrived before the deadline; it does not prove an MTU issue. `socket_error` records a socket error. Without `--dont-fragment`, fragmentation follows OS defaults; the tool does not force it on or off. The CLI exits successfully when it produces a report; inspect per-probe statuses for delivery outcomes.
|
|
99
|
+
|
|
100
|
+
JSON reports also include `summary.by_payload_size`. Each entry counts `acknowledged`, `packet_too_large`, `timeout` and `socket_error` attempts separately. Its `assessment` is `delivery_observed`, `kernel_rejected_df_payload`, `inconclusive`, `socket_error` or `mixed_observations`. Repeated payload sizes share one entry, while individual attempts remain in `results`. The summary does not infer an exact path MTU or turn a timeout into a diagnosis.
|
|
101
|
+
|
|
102
|
+
The `evidence` section lists counted observations, tentative hypotheses and missing checks separately. A clean pattern where every acknowledged size is below every timed-out size suggests a possible size-related delivery problem; in DF mode it also lists a possible PMTU-feedback black hole. Filtering and ordinary loss remain alternative explanations. Mixed or reversed size patterns produce no such hypothesis. Missing evidence calls out same-sized reverse traffic, receiver/path observation for timeouts, ICMP feedback visibility in DF mode and fragmentation control when DF is off. These are prompts for investigation, not automatic root-cause findings.
|
|
103
|
+
|
|
104
|
+
To compare directions, run `probe` once from A to B and once from B to A, then combine the two JSON files:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
python tunnelscope.py combine a-to-b.json b-to-a.json --output bidirectional.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The command preserves the two reports and aligns per-size assessments; it does not initiate a remote measurement. See the [two-endpoint workflow](https://github.com/lazypanic999/tunnelscope/blob/main/docs/bidirectional.md) for the receiver and sender steps. `endpoint_check` compares the recorded IPv4 addresses but cannot authenticate endpoints or account for address translation.
|
|
111
|
+
|
|
112
|
+
### Linux IPv4 Don't Fragment mode
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
python tunnelscope.py probe 192.0.2.2 --sizes 64,1252,1253,1400 --count 1 --dont-fragment --output report.json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Use the address of your lab receiver; `192.0.2.2` is an example. This mode sets `IP_MTU_DISCOVER=IP_PMTUDISC_DO` on each sender socket. The kernel sets DF and rejects datagrams above its currently known path MTU. It does not bypass cached PMTU information or search automatically for a boundary. The flag requires Linux, including WSL2. Other platforms reject it; socket-option errors stop the experiment rather than silently reverting to defaults.
|
|
119
|
+
|
|
120
|
+
In DF mode, `EMSGSIZE` is reported as `packet_too_large`, with its numeric `errno`. When available, `kernel_reported_mtu_bytes` contains the connected socket's `IP_MTU` value. That value is kernel knowledge, not an independently measured end-to-end MTU. Timeouts remain inconclusive. The JSON schema version remains 1 with additive fields and the new `packet_too_large` status; consumers must handle it explicitly.
|
|
121
|
+
|
|
122
|
+
### Reproduce a known MTU boundary
|
|
123
|
+
|
|
124
|
+
On Linux with root access and iproute2 installed:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
sudo python3 labs/mtu_boundary.py > mtu-boundary.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The lab creates two temporary network namespaces connected by a veth pair with MTU 1280. It probes both directions and checks that 1252-byte UDP payloads succeed while 1253-byte payloads fail in DF mode (20-byte IPv4 header + 8-byte UDP header). It changes no host interface MTU or host route and removes its namespaces on completion or ordinary interruption. As with any process, forced termination such as SIGKILL can prevent cleanup.
|
|
131
|
+
|
|
132
|
+
This validates a directly attached link boundary, not an unknown multi-hop bottleneck or a PMTU black hole. See the [validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/mtu-boundary.md) and [captured example report](https://github.com/lazypanic999/tunnelscope/blob/main/examples/mtu-boundary.json).
|
|
133
|
+
|
|
134
|
+
### Reproduce blocked PMTU feedback
|
|
135
|
+
|
|
136
|
+
On Linux with root access, iproute2, iptables and sysctl installed:
|
|
137
|
+
|
|
138
|
+
```sh
|
|
139
|
+
sudo python3 labs/pmtu_blackhole.py > pmtu-blackhole.json
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
This lab creates a sender, router and receiver in temporary network namespaces. The sender-facing link has MTU 1500; the router's receiver-facing link has MTU 1280. The router drops only its outgoing ICMP fragmentation-needed messages. In DF mode, 64- and 1252-byte UDP payloads are acknowledged, while 1253- and 1400-byte payloads time out. The lab changes no host routes, interfaces or firewall rules and removes its namespaces on ordinary completion or interruption. Forced termination such as SIGKILL can prevent cleanup.
|
|
143
|
+
|
|
144
|
+
The known lab topology explains these timeouts; a timeout on an unknown network remains inconclusive. See the [validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/pmtu-blackhole.md) and [captured report](https://github.com/lazypanic999/tunnelscope/blob/main/examples/pmtu-blackhole.json). This lab demonstrates one controlled failure mode; it does not establish automatic black-hole detection.
|
|
145
|
+
|
|
146
|
+
The receiver binds to loopback by default. For your own two-host lab, use `--bind <receiver-lab-IPv4>` and probe that address. The experimental protocol is unencrypted and unauthenticated; use a controlled lab, not a public service.
|
|
147
|
+
|
|
148
|
+
Run checks:
|
|
149
|
+
|
|
150
|
+
```sh
|
|
151
|
+
python -m unittest discover -s tests -v
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Privileged Linux integration check (also run by CI on Ubuntu):
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
sudo env TUNNELSCOPE_RUN_NETNS_TESTS=1 python3 -m unittest discover -s tests -v
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Prior art and scope
|
|
161
|
+
|
|
162
|
+
Existing tools such as ping, tracepath and packet analyzers already provide important building blocks. TunnelScope will explore whether controlled two-endpoint tests and evidence-oriented reporting make this investigation easier. It is not a replacement for a full packet analyzer.
|
|
163
|
+
|
|
164
|
+
## Contributing
|
|
165
|
+
|
|
166
|
+
Early feedback is welcome through GitHub Issues, especially reproducible examples where small traffic succeeds and larger transfers fail. Describe the environment, expected behavior and observed behavior. Use synthetic or sanitized examples; do not attach credentials or private packet captures.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/lazypanic999/tunnelscope/main/tunnelscope-logo-blue.png" alt="TunnelScope blue compass and vortex logo" width="400">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# TunnelScope
|
|
6
|
+
|
|
7
|
+
Evidence-based MTU and packet-size diagnostics for Linux networks.
|
|
8
|
+
|
|
9
|
+
**Status: v0.2.1 alpha prototype. UDP delivery probes, Linux IPv4 Don't Fragment mode, per-direction report combination, optional receiver observations and controlled MTU labs are available. Automatic path-MTU discovery and root-cause diagnosis are not implemented.**
|
|
10
|
+
|
|
11
|
+
## The problem
|
|
12
|
+
|
|
13
|
+
A connection can appear healthy while larger transfers fail. Small probes may succeed even when larger packets cannot traverse the path. Tunnel overhead, MTU configuration and blocked Path MTU Discovery feedback can contribute to this behavior. Other causes can produce similar symptoms.
|
|
14
|
+
|
|
15
|
+
TunnelScope aims to help network engineers, system administrators and learners investigate these failures through repeatable measurements and inspectable evidence.
|
|
16
|
+
|
|
17
|
+
## Planned first version
|
|
18
|
+
|
|
19
|
+
- A Python command-line tool and a cooperating receiver for controlled Linux environments.
|
|
20
|
+
- Repeated, size-controlled IPv4 UDP probes with fragmentation disabled.
|
|
21
|
+
- Separate measurements for each direction, with timeouts and loss recorded explicitly.
|
|
22
|
+
- JSON reports containing probe sizes, outcomes, relevant interface information and test settings.
|
|
23
|
+
- A reproducible Linux lab demonstrating healthy delivery, explicit packet-too-large feedback and a possible PMTU black hole.
|
|
24
|
+
|
|
25
|
+
A failed probe alone will not be labeled as proof of an MTU problem. Reports separate observations, hypotheses and missing evidence. An observed working packet size is not presented as the exact path MTU.
|
|
26
|
+
|
|
27
|
+
## Milestones
|
|
28
|
+
|
|
29
|
+
- [x] **M0 - Reproduce the problem:** build a small Linux network-namespace lab and record a healthy baseline and a controlled MTU failure.
|
|
30
|
+
- [x] **M1 - Probe and receive:** implement bounded, identifiable probes and acknowledgements between two endpoints.
|
|
31
|
+
- [x] **M2 - Explain the evidence:** export JSON and distinguish successful delivery, explicit errors and inconclusive timeouts.
|
|
32
|
+
- [x] **M3 - Validate:** check the tool against known lab configurations, document limitations and publish a short demo.
|
|
33
|
+
- [x] **M4 - Observe at the receiver:** record which identified probes reached the cooperating receiver and correlate them with sender outcomes.
|
|
34
|
+
- [x] **M5 - Make evidence usable:** validate receiver-observed timeouts in a controlled lab and provide a concise terminal view of reports.
|
|
35
|
+
|
|
36
|
+
Kubernetes, VPN-specific workflows, IPv6 and 5G user-plane tunnels are possible later directions. They are not currently supported features.
|
|
37
|
+
|
|
38
|
+
For a quick walkthrough of both controlled failure modes, see the [two-minute Linux demo](https://github.com/lazypanic999/tunnelscope/blob/main/docs/demo.md).
|
|
39
|
+
The [two-VM validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/two-vm-field-test.md) documents a successful bidirectional DF run between Ubuntu and Debian guests.
|
|
40
|
+
The [v0.1 scope](https://github.com/lazypanic999/tunnelscope/blob/main/docs/v0.1-scope.md) lists what the installable prototype does and does not cover.
|
|
41
|
+
The [v0.2 receiver workflow](https://github.com/lazypanic999/tunnelscope/blob/main/docs/receiver-observations.md) explains how to capture and correlate receiver evidence.
|
|
42
|
+
The [two-VM correlation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/two-vm-receiver-correlation.md) documents the new workflow on independent Linux guests.
|
|
43
|
+
The [blocked ACK return lab](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/ack-return-blocked.md) validates a receiver-observed sender timeout.
|
|
44
|
+
|
|
45
|
+
Use `tunnelscope show report.json` for a short terminal table of a probe,
|
|
46
|
+
bidirectional comparison, correlation, or lab report. JSON remains the
|
|
47
|
+
machine-readable source of evidence.
|
|
48
|
+
|
|
49
|
+
## Install locally
|
|
50
|
+
|
|
51
|
+
From the repository root, in a Python 3.10+ virtual environment:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
python3 -m pip install .
|
|
55
|
+
tunnelscope --help
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The package installs the `tunnelscope` command. It has no third-party runtime dependencies. Published releases can be installed with `python3 -m pip install tunnelscope`. The laboratory scripts still run from a source checkout.
|
|
59
|
+
|
|
60
|
+
## Getting started
|
|
61
|
+
|
|
62
|
+
Requires Python 3.10 or newer. No third-party runtime packages are needed. Start with a local experiment in two terminals, from the repository directory. Use `tunnelscope` in place of `python tunnelscope.py` after installing the package.
|
|
63
|
+
|
|
64
|
+
Terminal 1 (receiver):
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
python tunnelscope.py receive
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Terminal 2 (sender):
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
python tunnelscope.py probe 127.0.0.1 --sizes 64,512,1200,1400 --count 3 --output report.json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The receiver exits after 100 datagrams or 30 seconds without a datagram. Restart it if it has already exited. `--max-packets` and `--idle-timeout` change these limits.
|
|
77
|
+
|
|
78
|
+
Probe sizes are **UDP payload bytes**, including TunnelScope's 24-byte header. They exclude IP and UDP headers. The receiver sends only a small acknowledgement, so this is not a same-sized round-trip test. Reverse endpoint roles to investigate delivery in the other direction.
|
|
79
|
+
|
|
80
|
+
Each probe report includes a `source` snapshot taken from the first connected sender socket. It records the local IPv4 address. On Linux, it also records the selected interface and its link MTU when discoverable, plus `kernel_route_mtu_bytes` when the kernel supplies it. The link MTU and kernel route MTU are different facts; neither is an independently measured end-to-end path MTU. A failed connection may leave `source` as `null`, and optional fields may be absent.
|
|
81
|
+
|
|
82
|
+
`acknowledged` means that the receiver got that payload and its acknowledgement returned. `timeout` means no matching acknowledgement arrived before the deadline; it does not prove an MTU issue. `socket_error` records a socket error. Without `--dont-fragment`, fragmentation follows OS defaults; the tool does not force it on or off. The CLI exits successfully when it produces a report; inspect per-probe statuses for delivery outcomes.
|
|
83
|
+
|
|
84
|
+
JSON reports also include `summary.by_payload_size`. Each entry counts `acknowledged`, `packet_too_large`, `timeout` and `socket_error` attempts separately. Its `assessment` is `delivery_observed`, `kernel_rejected_df_payload`, `inconclusive`, `socket_error` or `mixed_observations`. Repeated payload sizes share one entry, while individual attempts remain in `results`. The summary does not infer an exact path MTU or turn a timeout into a diagnosis.
|
|
85
|
+
|
|
86
|
+
The `evidence` section lists counted observations, tentative hypotheses and missing checks separately. A clean pattern where every acknowledged size is below every timed-out size suggests a possible size-related delivery problem; in DF mode it also lists a possible PMTU-feedback black hole. Filtering and ordinary loss remain alternative explanations. Mixed or reversed size patterns produce no such hypothesis. Missing evidence calls out same-sized reverse traffic, receiver/path observation for timeouts, ICMP feedback visibility in DF mode and fragmentation control when DF is off. These are prompts for investigation, not automatic root-cause findings.
|
|
87
|
+
|
|
88
|
+
To compare directions, run `probe` once from A to B and once from B to A, then combine the two JSON files:
|
|
89
|
+
|
|
90
|
+
```sh
|
|
91
|
+
python tunnelscope.py combine a-to-b.json b-to-a.json --output bidirectional.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The command preserves the two reports and aligns per-size assessments; it does not initiate a remote measurement. See the [two-endpoint workflow](https://github.com/lazypanic999/tunnelscope/blob/main/docs/bidirectional.md) for the receiver and sender steps. `endpoint_check` compares the recorded IPv4 addresses but cannot authenticate endpoints or account for address translation.
|
|
95
|
+
|
|
96
|
+
### Linux IPv4 Don't Fragment mode
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
python tunnelscope.py probe 192.0.2.2 --sizes 64,1252,1253,1400 --count 1 --dont-fragment --output report.json
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Use the address of your lab receiver; `192.0.2.2` is an example. This mode sets `IP_MTU_DISCOVER=IP_PMTUDISC_DO` on each sender socket. The kernel sets DF and rejects datagrams above its currently known path MTU. It does not bypass cached PMTU information or search automatically for a boundary. The flag requires Linux, including WSL2. Other platforms reject it; socket-option errors stop the experiment rather than silently reverting to defaults.
|
|
103
|
+
|
|
104
|
+
In DF mode, `EMSGSIZE` is reported as `packet_too_large`, with its numeric `errno`. When available, `kernel_reported_mtu_bytes` contains the connected socket's `IP_MTU` value. That value is kernel knowledge, not an independently measured end-to-end MTU. Timeouts remain inconclusive. The JSON schema version remains 1 with additive fields and the new `packet_too_large` status; consumers must handle it explicitly.
|
|
105
|
+
|
|
106
|
+
### Reproduce a known MTU boundary
|
|
107
|
+
|
|
108
|
+
On Linux with root access and iproute2 installed:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
sudo python3 labs/mtu_boundary.py > mtu-boundary.json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The lab creates two temporary network namespaces connected by a veth pair with MTU 1280. It probes both directions and checks that 1252-byte UDP payloads succeed while 1253-byte payloads fail in DF mode (20-byte IPv4 header + 8-byte UDP header). It changes no host interface MTU or host route and removes its namespaces on completion or ordinary interruption. As with any process, forced termination such as SIGKILL can prevent cleanup.
|
|
115
|
+
|
|
116
|
+
This validates a directly attached link boundary, not an unknown multi-hop bottleneck or a PMTU black hole. See the [validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/mtu-boundary.md) and [captured example report](https://github.com/lazypanic999/tunnelscope/blob/main/examples/mtu-boundary.json).
|
|
117
|
+
|
|
118
|
+
### Reproduce blocked PMTU feedback
|
|
119
|
+
|
|
120
|
+
On Linux with root access, iproute2, iptables and sysctl installed:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
sudo python3 labs/pmtu_blackhole.py > pmtu-blackhole.json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This lab creates a sender, router and receiver in temporary network namespaces. The sender-facing link has MTU 1500; the router's receiver-facing link has MTU 1280. The router drops only its outgoing ICMP fragmentation-needed messages. In DF mode, 64- and 1252-byte UDP payloads are acknowledged, while 1253- and 1400-byte payloads time out. The lab changes no host routes, interfaces or firewall rules and removes its namespaces on ordinary completion or interruption. Forced termination such as SIGKILL can prevent cleanup.
|
|
127
|
+
|
|
128
|
+
The known lab topology explains these timeouts; a timeout on an unknown network remains inconclusive. See the [validation record](https://github.com/lazypanic999/tunnelscope/blob/main/docs/validation/pmtu-blackhole.md) and [captured report](https://github.com/lazypanic999/tunnelscope/blob/main/examples/pmtu-blackhole.json). This lab demonstrates one controlled failure mode; it does not establish automatic black-hole detection.
|
|
129
|
+
|
|
130
|
+
The receiver binds to loopback by default. For your own two-host lab, use `--bind <receiver-lab-IPv4>` and probe that address. The experimental protocol is unencrypted and unauthenticated; use a controlled lab, not a public service.
|
|
131
|
+
|
|
132
|
+
Run checks:
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
python -m unittest discover -s tests -v
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Privileged Linux integration check (also run by CI on Ubuntu):
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
sudo env TUNNELSCOPE_RUN_NETNS_TESTS=1 python3 -m unittest discover -s tests -v
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Prior art and scope
|
|
145
|
+
|
|
146
|
+
Existing tools such as ping, tracepath and packet analyzers already provide important building blocks. TunnelScope will explore whether controlled two-endpoint tests and evidence-oriented reporting make this investigation easier. It is not a replacement for a full packet analyzer.
|
|
147
|
+
|
|
148
|
+
## Contributing
|
|
149
|
+
|
|
150
|
+
Early feedback is welcome through GitHub Issues, especially reproducible examples where small traffic succeeds and larger transfers fail. Describe the environment, expected behavior and observed behavior. Use synthetic or sanitized examples; do not attach credentials or private packet captures.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Measure both directions
|
|
2
|
+
|
|
3
|
+
TunnelScope's receiver sends a small acknowledgement. One `probe` run therefore
|
|
4
|
+
measures delivery of the requested payload in one direction, plus return of the
|
|
5
|
+
small acknowledgement. To measure the reverse direction, the endpoints must
|
|
6
|
+
exchange sender and receiver roles. This workflow is for a controlled Linux
|
|
7
|
+
environment where both sides can run Python 3.10+ and reach each other over UDP.
|
|
8
|
+
|
|
9
|
+
Use the actual endpoint IPv4 addresses in place of `A_IP` and `B_IP`. Start each
|
|
10
|
+
receiver shortly before its probe; by default it exits after 30 seconds idle.
|
|
11
|
+
|
|
12
|
+
## A to B
|
|
13
|
+
|
|
14
|
+
On endpoint B:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
python3 tunnelscope.py receive --bind B_IP
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
On endpoint A:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
python3 tunnelscope.py probe B_IP --sizes 64,1252,1253,1400 --count 3 --dont-fragment --output a-to-b.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## B to A
|
|
27
|
+
|
|
28
|
+
On endpoint A:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
python3 tunnelscope.py receive --bind A_IP
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
On endpoint B:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
python3 tunnelscope.py probe A_IP --sizes 64,1252,1253,1400 --count 3 --dont-fragment --output b-to-a.json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Copy `b-to-a.json` to the machine holding `a-to-b.json`. Then run:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
python3 tunnelscope.py combine a-to-b.json b-to-a.json --output bidirectional.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`bidirectional.json` contains the unmodified probe reports under `directions`,
|
|
47
|
+
with `a-to-b` and `b-to-a` labels supplied by the command order. Its
|
|
48
|
+
`comparison.by_payload_size` aligns each direction's assessment for the same
|
|
49
|
+
UDP payload size. A missing size has a `null` assessment. The command does not
|
|
50
|
+
turn two timeouts into a diagnosis.
|
|
51
|
+
Each embedded report's `evidence` describes that one run; `combine` preserves
|
|
52
|
+
it without retroactively treating the other file as verified evidence.
|
|
53
|
+
|
|
54
|
+
`endpoint_check` is `reversed_ipv4_match` when both recorded source IPv4
|
|
55
|
+
addresses equal the opposite report's target address. It is
|
|
56
|
+
`ipv4_mismatch_or_translation` when they differ, or `unavailable` if either
|
|
57
|
+
source snapshot is missing. NAT, multiple local addresses and user-selected
|
|
58
|
+
files can affect this check; the command cannot verify that the files came
|
|
59
|
+
from the intended endpoints.
|
|
60
|
+
|
|
61
|
+
## Source fields
|
|
62
|
+
|
|
63
|
+
`source.ipv4` is the first connected sender socket's local IPv4 address. On
|
|
64
|
+
Linux, `source.interface` and `source.interface_mtu_bytes` are included when
|
|
65
|
+
the address can be matched to a local interface. `source.kernel_route_mtu_bytes`
|
|
66
|
+
is the kernel's current MTU value for that connected route when available. A
|
|
67
|
+
link MTU is local interface configuration; a kernel route MTU can reflect
|
|
68
|
+
cached path knowledge. Neither field alone proves the end-to-end path MTU.
|
|
69
|
+
|
|
70
|
+
The report contains a source snapshot, not a live record of route changes
|
|
71
|
+
during later attempts. When a socket cannot connect, `source` can be `null`.
|
|
72
|
+
The probe protocol is unauthenticated and unencrypted; use a controlled lab.
|
|
73
|
+
|
|
74
|
+
For each direction, you can also save observations at the receiving endpoint
|
|
75
|
+
and use `tunnelscope correlate` to check which individual probes arrived. See
|
|
76
|
+
the [receiver observation workflow](receiver-observations.md). This provides
|
|
77
|
+
different evidence from a reverse-direction probe.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# TunnelScope: two-minute Linux demo
|
|
2
|
+
|
|
3
|
+
Run this from the repository root on Linux with root access, Python 3.10+,
|
|
4
|
+
iproute2, iptables and sysctl. The labs create temporary network namespaces;
|
|
5
|
+
they do not change host interfaces, routes or firewall rules. Forced termination
|
|
6
|
+
such as SIGKILL can prevent namespace cleanup.
|
|
7
|
+
|
|
8
|
+
## 1. Run two controlled experiments
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
sudo python3 labs/mtu_boundary.py > boundary.json
|
|
12
|
+
sudo python3 labs/pmtu_blackhole.py > blackhole.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The first experiment uses a direct 1280-byte link. The second routes traffic
|
|
16
|
+
from a 1500-byte link onto a 1280-byte link while blocking the router's ICMP
|
|
17
|
+
fragmentation-needed feedback.
|
|
18
|
+
|
|
19
|
+
## 2. Compare what the sender observed
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
python3 - <<'PY'
|
|
23
|
+
import json
|
|
24
|
+
|
|
25
|
+
with open("boundary.json", encoding="utf-8") as source:
|
|
26
|
+
boundary = json.load(source)
|
|
27
|
+
with open("blackhole.json", encoding="utf-8") as source:
|
|
28
|
+
blackhole = json.load(source)
|
|
29
|
+
|
|
30
|
+
def show(label, results):
|
|
31
|
+
statuses = ", ".join(f"{row['payload_bytes']}={row['status']}" for row in results)
|
|
32
|
+
print(f"{label}: {statuses}")
|
|
33
|
+
|
|
34
|
+
for direction in boundary["directions"]:
|
|
35
|
+
show(direction["direction"], direction["results"])
|
|
36
|
+
show("blocked ICMP", blackhole["probe"]["results"])
|
|
37
|
+
print("blocked feedback packets:", blackhole["blocked_feedback_packets"])
|
|
38
|
+
PY
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Example output (statuses are checked by the labs; the firewall counter can vary):
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
a-to-b: 64=acknowledged, 1252=acknowledged, 1253=packet_too_large, 1400=packet_too_large
|
|
45
|
+
b-to-a: 64=acknowledged, 1252=acknowledged, 1253=packet_too_large, 1400=packet_too_large
|
|
46
|
+
blocked ICMP: 64=acknowledged, 1252=acknowledged, 1253=timeout, 1400=timeout
|
|
47
|
+
blocked feedback packets: 2
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The direct-link sender receives a local `EMSGSIZE` error above 1252 UDP payload
|
|
51
|
+
bytes. In the routed lab, the large DF packets cannot cross the 1280-byte
|
|
52
|
+
egress link, and the router's ICMP feedback is blocked. The sender sees only
|
|
53
|
+
timeouts. The lab knows why; an unknown network path would require more
|
|
54
|
+
evidence before calling a timeout a PMTU black hole.
|
|
55
|
+
|
|
56
|
+
## 3. Inspect the JSON evidence
|
|
57
|
+
|
|
58
|
+
Each probe report keeps individual attempts in `results`, counts outcomes
|
|
59
|
+
per payload size in `summary.by_payload_size`, and separates observations,
|
|
60
|
+
possible explanations and missing checks in `evidence`. The routed lab also records
|
|
61
|
+
`blocked_feedback_packets` from its isolated firewall rule. Compare your run
|
|
62
|
+
with the [direct-link example](../examples/mtu-boundary.json) and the
|
|
63
|
+
[blocked-feedback example](../examples/pmtu-blackhole.json).
|
|
64
|
+
|
|
65
|
+
The validation records explain the [direct-link boundary](validation/mtu-boundary.md)
|
|
66
|
+
and [routed black-hole scenario](validation/pmtu-blackhole.md). These labs do
|
|
67
|
+
not validate arbitrary networks, VPNs, IPv6 or same-sized return traffic.
|
|
Binary file
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Correlate receiver observations
|
|
2
|
+
|
|
3
|
+
In v0.2, a cooperating receiver can save the probe IDs and payload sizes it
|
|
4
|
+
observed. The sender also includes each 128-bit random probe ID in its JSON
|
|
5
|
+
results. From v0.2.1, the sender puts one random run ID in every payload, and
|
|
6
|
+
both reports record it. Correlation answers whether a particular probe reached
|
|
7
|
+
the receiver and whether the receiver attempted to send an acknowledgement.
|
|
8
|
+
|
|
9
|
+
Start the receiver on endpoint B and give it an output path:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
tunnelscope receive --bind B_IP --output receiver.json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Run the sender on endpoint A:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
tunnelscope probe B_IP --sizes 64,1252,1253,1400 --count 3 --dont-fragment --output a-to-b.json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
After the sender finishes, stop the receiver with Ctrl-C or wait for its idle
|
|
22
|
+
timeout. The receiver writes `receiver.json` when it exits. Copy it to the
|
|
23
|
+
machine holding `a-to-b.json`, then run:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
tunnelscope correlate a-to-b.json receiver.json --output correlation.json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`correlation.json` has one row per sender attempt. `receiver_observed: true`
|
|
30
|
+
confirms that the matching payload arrived at this receiver. A timeout with
|
|
31
|
+
`receiver_observed: true` narrows the investigation toward acknowledgement
|
|
32
|
+
transmission or return delivery, but does not identify which failed. A successful
|
|
33
|
+
acknowledgement send call only confirms that the local socket accepted it.
|
|
34
|
+
|
|
35
|
+
`receiver_observed: false` is inconclusive unless the receiver was running for
|
|
36
|
+
the full probe period and its report is complete. A packet may have been lost,
|
|
37
|
+
filtered, sent to another endpoint or missed because capture started late.
|
|
38
|
+
`unmatched_receiver_observations` counts valid probes seen by the receiver that
|
|
39
|
+
were not present in the sender file. It can reveal a mixed or incorrect pairing.
|
|
40
|
+
|
|
41
|
+
`pairing.run_id_check` is `matched` when the receiver observed this sender run.
|
|
42
|
+
The command rejects a receiver file containing only observations from another
|
|
43
|
+
run. An empty receiver file cannot establish which run it covered and is marked
|
|
44
|
+
`unverified_no_receiver_observations`. `pairing.endpoint_checks` compares the
|
|
45
|
+
target port and, unless the receiver bound to `0.0.0.0`, the target IPv4 address.
|
|
46
|
+
Mismatches need review; address translation can legitimately change them.
|
|
47
|
+
The two UTC capture windows and the receiver's `exit_reason` help review
|
|
48
|
+
coverage, but the command does not compare clocks across hosts because they
|
|
49
|
+
may be unsynchronized.
|
|
50
|
+
|
|
51
|
+
The reports are unauthenticated. Use them only in a controlled environment and
|
|
52
|
+
pair the files from the same run. Reports created before v0.2 do not contain
|
|
53
|
+
probe IDs and cannot be correlated. v0.2 reports can still be correlated by
|
|
54
|
+
probe ID, but their run ID check is unavailable. Receiver observation is complementary to
|
|
55
|
+
running probes in the reverse direction; it does not replace that test.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# TunnelScope v0.2.1
|
|
2
|
+
|
|
3
|
+
First public alpha release of the Python command-line prototype.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- Bounded IPv4 UDP probes with optional Linux Don't Fragment mode, JSON evidence,
|
|
8
|
+
and separate per-direction comparison.
|
|
9
|
+
- Receiver observation reports and `correlate` for matching individual probes.
|
|
10
|
+
Run IDs and endpoint checks help catch incorrectly paired reports.
|
|
11
|
+
- `show` prints concise terminal tables for probe, correlation, bidirectional
|
|
12
|
+
comparison and lab JSON reports.
|
|
13
|
+
- Reproducible Linux namespace labs for a direct MTU boundary, blocked PMTU
|
|
14
|
+
feedback and a blocked acknowledgement return.
|
|
15
|
+
- Two-VM validation of successful delivery and receiver correlation in both
|
|
16
|
+
directions.
|
|
17
|
+
|
|
18
|
+
## Known limits
|
|
19
|
+
|
|
20
|
+
Timeouts remain inconclusive without cooperating receiver or path evidence.
|
|
21
|
+
The CLI does not discover an exact end-to-end path MTU or prove a root cause on
|
|
22
|
+
an unknown network. The UDP protocol is unauthenticated and unencrypted; run
|
|
23
|
+
it only in a controlled environment. IPv6, VPN-specific, Kubernetes and 5G
|
|
24
|
+
workflows are not implemented.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# TunnelScope v0.1 scope
|
|
2
|
+
|
|
3
|
+
v0.1 is an installable prototype of the existing Python CLI. It can be built
|
|
4
|
+
and installed locally; it is not yet published to a package index.
|
|
5
|
+
|
|
6
|
+
## Included
|
|
7
|
+
|
|
8
|
+
- A `tunnelscope` console command with `receive`, `probe` and `combine`.
|
|
9
|
+
- Bounded IPv4 UDP payload probes and small acknowledgements between controlled
|
|
10
|
+
endpoints.
|
|
11
|
+
- Optional Linux Don't Fragment mode and explicit local `EMSGSIZE` reporting.
|
|
12
|
+
- JSON reports with per-size counts, source/interface snapshot, observations,
|
|
13
|
+
tentative hypotheses and missing evidence.
|
|
14
|
+
- Separate direction reports that can be combined without treating either
|
|
15
|
+
direction as proof of the other's behavior.
|
|
16
|
+
- Direct-link MTU boundary and blocked-feedback Linux namespace labs.
|
|
17
|
+
- A two-VM bidirectional delivery validation record.
|
|
18
|
+
|
|
19
|
+
## Outside v0.1
|
|
20
|
+
|
|
21
|
+
- Automatic discovery of an exact end-to-end path MTU or root cause.
|
|
22
|
+
- Automatic remote orchestration, authentication or encryption.
|
|
23
|
+
- IPv6, VPN-specific, Kubernetes or 5G tunnel workflows.
|
|
24
|
+
- A graphical interface and a published package-index release.
|
|
25
|
+
|
|
26
|
+
## Before a public release
|
|
27
|
+
|
|
28
|
+
The local wheel and source distribution must build and install cleanly on
|
|
29
|
+
supported Python versions. We also need to choose and add a project license,
|
|
30
|
+
confirm the package name and publish a release only after reviewing the
|
|
31
|
+
distribution metadata and contents. These decisions are separate from local
|
|
32
|
+
v0.1 packaging.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Blocked acknowledgement return validation
|
|
2
|
+
|
|
3
|
+
Run the controlled lab as root on Linux with iproute2 and iptables:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
sudo python3 labs/ack_return_blocked.py > ack-return-blocked.json
|
|
7
|
+
python3 tunnelscope.py show ack-return-blocked.json
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The lab creates two temporary network namespaces on a 1500-byte direct link.
|
|
11
|
+
The receiver observes two UDP probes and sends small acknowledgements. A rule
|
|
12
|
+
in the sender namespace drops only incoming UDP packets from the receiver's
|
|
13
|
+
port. The lab changes no host firewall rule, route or interface and removes
|
|
14
|
+
the namespaces when it exits normally.
|
|
15
|
+
|
|
16
|
+
In the validated run, both 64- and 1400-byte probes timed out at the sender.
|
|
17
|
+
The receiver recorded both probes and both local acknowledgement sends. The
|
|
18
|
+
correlation reported `timed_out_but_receiver_observed: 2`, a matched run ID,
|
|
19
|
+
and zero unmatched receiver observations. The isolated firewall counted two
|
|
20
|
+
blocked acknowledgements.
|
|
21
|
+
|
|
22
|
+
This establishes the cause only inside the known lab topology. On an unknown
|
|
23
|
+
network, the same sender/receiver pattern narrows the investigation to the
|
|
24
|
+
acknowledgement path but does not identify a failing hop or rule. Forced
|
|
25
|
+
termination such as SIGKILL can prevent namespace cleanup.
|