psiphon 2.0.2__tar.gz → 2.0.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psiphon
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: Foreground native Psiphon packet tunnel and explicit local proxy for Linux
5
5
  Author: KpihX
6
6
  Author-email: KpihX <kapoivha@gmail.com>
@@ -132,6 +132,22 @@ Tailscale/campus DNS present. Sixteen produced verified packet-tunnel downloads;
132
132
  all sessions restored the original routes and per-link DNS domains. See
133
133
  `BENCHMARKS.md` for failures and qualifications.
134
134
 
135
+ ### 2.0.3: local container/VM bridge exception
136
+
137
+ The broad nonlocal IPv4 statement above now has one explicit exception: existing
138
+ directly connected IPv4 prefixes on Linux bridges stay on those bridges. Their
139
+ routes are copied into the temporary VPN table, not changed in the main table,
140
+ and removed in reverse rollback. This keeps Docker/VM local APIs reachable while
141
+ Internet traffic still selects the TUN. It is not a blanket RFC1918, WiFi LAN or
142
+ physical-uplink bypass. New bridges created after connection are not automatically
143
+ watched; reconnect when adding network topology during a session.
144
+
145
+ The failure was reproduced with Docker traffic selecting psiphon0. After the fix,
146
+ a live Germany session kept the container path local and returned the xsearch
147
+ engine inventory and real search results over both Unix IPC and TCP. iproute2
148
+ omits the `scope` field in some filtered JSON results; the regression fixture
149
+ uses this observed shape, not an assumed schema.
150
+
135
151
  Each successful mutation has an inverse. The supervisor owns the engine and
136
152
  observes a private pipe: normal exit, startup failure, SIGTERM, Ctrl-C or controller
137
153
  SIGKILL closes it, stops/reaps the engine, and rolls back in reverse order. Cleanup
@@ -115,6 +115,22 @@ Tailscale/campus DNS present. Sixteen produced verified packet-tunnel downloads;
115
115
  all sessions restored the original routes and per-link DNS domains. See
116
116
  `BENCHMARKS.md` for failures and qualifications.
117
117
 
118
+ ### 2.0.3: local container/VM bridge exception
119
+
120
+ The broad nonlocal IPv4 statement above now has one explicit exception: existing
121
+ directly connected IPv4 prefixes on Linux bridges stay on those bridges. Their
122
+ routes are copied into the temporary VPN table, not changed in the main table,
123
+ and removed in reverse rollback. This keeps Docker/VM local APIs reachable while
124
+ Internet traffic still selects the TUN. It is not a blanket RFC1918, WiFi LAN or
125
+ physical-uplink bypass. New bridges created after connection are not automatically
126
+ watched; reconnect when adding network topology during a session.
127
+
128
+ The failure was reproduced with Docker traffic selecting psiphon0. After the fix,
129
+ a live Germany session kept the container path local and returned the xsearch
130
+ engine inventory and real search results over both Unix IPC and TCP. iproute2
131
+ omits the `scope` field in some filtered JSON results; the regression fixture
132
+ uses this observed shape, not an assumed schema.
133
+
118
134
  Each successful mutation has an inverse. The supervisor owns the engine and
119
135
  observes a private pipe: normal exit, startup failure, SIGTERM, Ctrl-C or controller
120
136
  SIGKILL closes it, stops/reaps the engine, and rolls back in reverse order. Cleanup
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "psiphon"
3
- version = "2.0.2"
3
+ version = "2.0.3"
4
4
  description = "Foreground native Psiphon packet tunnel and explicit local proxy for Linux"
5
5
  readme = "README.md"
6
6
  license = "BUSL-1.1"
@@ -1,5 +1,6 @@
1
1
  """Conservative native TUN routing, with only session-scoped owned resources."""
2
2
 
3
+ import ipaddress
3
4
  import json
4
5
  import os
5
6
  import re
@@ -87,6 +88,37 @@ def check_user_binding(interface: str) -> None:
87
88
  ) from exc
88
89
 
89
90
 
91
+ def connected_bridge_routes() -> list[dict]:
92
+ """Keep directly-connected container/VM bridges local, not RFC1918 at large.
93
+
94
+ Only existing unicast scope-link IPv4 routes on actual Linux bridges qualify.
95
+ Never copy a default route, gateway, physical uplink or arbitrary policy table.
96
+ """
97
+ links = json.loads(run(["ip", "-j", "-d", "link", "show"]))
98
+ bridges = {
99
+ link["ifname"]
100
+ for link in links
101
+ if link.get("linkinfo", {}).get("info_kind") == "bridge"
102
+ }
103
+ routes = json.loads(
104
+ run(["ip", "-j", "-4", "route", "show", "table", "main", "scope", "link"])
105
+ )
106
+ selected = []
107
+ for route in routes:
108
+ if (
109
+ route.get("dev") not in bridges
110
+ or route.get("gateway")
111
+ or route.get("type", "unicast") != "unicast"
112
+ # iproute2 omits "scope" in JSON when the scope=link filter is used.
113
+ or route.get("scope", "link") != "link"
114
+ ):
115
+ continue
116
+ network = ipaddress.ip_network(route.get("dst", "0.0.0.0/0"), strict=False)
117
+ if network.version == 4 and network.prefixlen:
118
+ selected.append({"dst": str(network), "dev": route["dev"]})
119
+ return selected
120
+
121
+
90
122
  def configure(owner, uplink: str, uid: int | None = None) -> None:
91
123
  tun = config.TUN_NAME
92
124
  owner.apply(
@@ -124,6 +156,21 @@ def configure(owner, uplink: str, uid: int | None = None) -> None:
124
156
  ["ip", family, "route", "add", *route, "table", config.ROUTE_TABLE],
125
157
  ["ip", family, "route", "del", *route, "table", config.ROUTE_TABLE],
126
158
  )
159
+ if family == "-4":
160
+ for local in connected_bridge_routes():
161
+ direct = [
162
+ local["dst"],
163
+ "dev",
164
+ local["dev"],
165
+ "scope",
166
+ "link",
167
+ "table",
168
+ config.ROUTE_TABLE,
169
+ ]
170
+ owner.apply(
171
+ ["ip", "-4", "route", "add", *direct],
172
+ ["ip", "-4", "route", "del", *direct],
173
+ )
127
174
  # Explicitly uplink-bound IPv4 sockets bypass (required by ConsoleClient).
128
175
  # IPv6 is blocked for all nonlocal traffic for this session.
129
176
  if family == "-4":
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes