Skip to content

Commit db87d75

Browse files
author
root
committed
srcport_rewrite N:1 flatten, bump to 0.0.7
Allow srcport_rewrite to be a single port regardless of srcport range size. Sender squashes every matched src port onto that one; receiver mirrors, squashing whatever random wire src port a symmetric NAT on the path handed us back to a fixed app-side port. 1:1 same-size mapping still works as before.
1 parent ea150ed commit db87d75

6 files changed

Lines changed: 32 additions & 13 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "transparent-udp-obfus"
3-
version = "0.0.6"
3+
version = "0.0.7"
44
edition = "2021"
55

66
[[bin]]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ Each rule:
139139
| `srcport` | u16 or `[lo, hi]` | Optional. |
140140
| `dstport` | u16 | Optional. |
141141
| `dstport_rewrite` | u16 | Optional. If set, overwrite dst port after encoding / before decoding. |
142-
| `srcport_rewrite` | u16 or `[lo, hi]` | Optional. Requires `srcport`. Range size must match `srcport`. Sender maps app→wire (`srcport``srcport_rewrite`); receiver maps back (`srcport` matches wire, `srcport_rewrite` is the app range to restore). |
142+
| `srcport_rewrite` | u16 or `[lo, hi]` | Optional. Requires `srcport`. Either a range of the same size as `srcport` (1:1 offset mapping) or a single port (N:1 flatten — every matched src port is squashed onto it). Sender maps app→wire; receiver maps back. Flatten mode is intended for symmetric NAT on the path: the NAT randomises the wire src port, so the receiver sets `srcport_rewrite` to a single port to pin everything back to a fixed app-side port. |
143143

144144
### Cipher mode
145145

src/config.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,18 @@ impl Config {
131131
if a > b || c > d {
132132
anyhow::bail!("{}: port range must have lo <= hi", name);
133133
}
134-
if (b - a) != (d - c) {
134+
// Allow either an equal-size 1:1 range mapping, or an N:1
135+
// flatten where srcport_rewrite is a single port and any
136+
// srcport in the matched range is squashed onto it. The
137+
// flatten form is there to cope with symmetric NAT on the
138+
// path randomising the wire src port: the receiver can't
139+
// recover the original, so we force everything to a fixed
140+
// app-side port instead.
141+
let flatten = c == d;
142+
if !flatten && (b - a) != (d - c) {
135143
anyhow::bail!(
136-
"{}: srcport_rewrite size ({}) must equal srcport size ({})",
144+
"{}: srcport_rewrite must be either a single port (flatten) \
145+
or a range the same size as srcport ({} vs {})",
137146
name,
138147
d - c + 1,
139148
b - a + 1,

src/receiver.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,15 @@ fn handle(
120120
// Symmetric to sender's srcport rewrite. On this side `srcport` matches
121121
// the wire (rewritten) range and `srcport_rewrite` is the original app
122122
// range to restore. Validated equal-size at config load.
123-
let new_sport = if let Some((orig_lo, _)) = rule.srcport_rewrite {
124-
let (wire_lo, _) = rule.srcport.unwrap();
125-
orig_lo + (peer.port() - wire_lo)
123+
let new_sport = if let Some((orig_lo, orig_hi)) = rule.srcport_rewrite {
124+
if orig_lo == orig_hi {
125+
// N:1 flatten: squash whatever random wire src port a symmetric
126+
// NAT handed us back to a fixed app-side port.
127+
orig_lo
128+
} else {
129+
let (wire_lo, _) = rule.srcport.unwrap();
130+
orig_lo + (peer.port() - wire_lo)
131+
}
126132
} else {
127133
peer.port()
128134
};

src/sender.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,15 @@ fn handle(buf: &mut [u8], ctx: &SenderCtx) {
8484
if let Some(new_dp) = rule.dstport_rewrite {
8585
packet::write_dport(buf, &parsed, new_dp);
8686
}
87-
if let Some((rw_lo, _)) = rule.srcport_rewrite {
88-
// Validated at config load: srcport is always set when srcport_rewrite is,
89-
// and the ranges have identical size.
90-
let (app_lo, _) = rule.srcport.unwrap();
91-
let new_sp = rw_lo + (parsed.src_port - app_lo);
87+
if let Some((rw_lo, rw_hi)) = rule.srcport_rewrite {
88+
// Validated at config load: srcport is set, and srcport_rewrite is
89+
// either the same size (1:1 offset) or a single port (N:1 flatten).
90+
let new_sp = if rw_lo == rw_hi {
91+
rw_lo
92+
} else {
93+
let (app_lo, _) = rule.srcport.unwrap();
94+
rw_lo + (parsed.src_port - app_lo)
95+
};
9296
packet::write_sport(buf, &parsed, new_sp);
9397
}
9498
packet::recompute_udp_checksum(buf, &parsed);

0 commit comments

Comments
 (0)