Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- [HTTP Configuration](./examples/http_config/)
- [gRPC Auth (random)](./examples/grpc_auth_random/)
- [Envoy filter metadata](./examples/envoy_filter_metadata/)
- [TCP Rerouting](./examples/tcp_rerouting/)

## Articles & blog posts from the community

Expand Down
16 changes: 8 additions & 8 deletions bazel/cargo/Cargo.Bazel.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ dependencies = [

[[package]]
name = "log"
version = "0.4.27"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"

[[package]]
name = "mockalloc"
Expand All @@ -59,9 +59,9 @@ dependencies = [

[[package]]
name = "proc-macro2"
version = "1.0.101"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
Expand All @@ -77,9 +77,9 @@ dependencies = [

[[package]]
name = "quote"
version = "1.0.41"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
Expand All @@ -97,6 +97,6 @@ dependencies = [

[[package]]
name = "unicode-ident"
version = "1.0.19"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
6 changes: 3 additions & 3 deletions bazel/cargo/remote/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ alias(
)

alias(
name = "log-0.4.27",
actual = "@crates_vendor__log-0.4.27//:log",
name = "log-0.4.28",
actual = "@crates_vendor__log-0.4.28//:log",
tags = ["manual"],
)

alias(
name = "log",
actual = "@crates_vendor__log-0.4.27//:log",
actual = "@crates_vendor__log-0.4.28//:log",
tags = ["manual"],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ rust_library(
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "0.4.27",
version = "0.4.28",
)
4 changes: 2 additions & 2 deletions bazel/cargo/remote/BUILD.mockalloc-macros-0.1.0.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ rust_proc_macro(
}),
version = "0.1.0",
deps = [
"@crates_vendor__proc-macro2-1.0.101//:proc_macro2",
"@crates_vendor__quote-1.0.41//:quote",
"@crates_vendor__proc-macro2-1.0.103//:proc_macro2",
"@crates_vendor__quote-1.0.42//:quote",
"@crates_vendor__syn-1.0.109//:syn",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ rust_library(
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "1.0.101",
version = "1.0.103",
deps = [
"@crates_vendor__proc-macro2-1.0.101//:build_script_build",
"@crates_vendor__unicode-ident-1.0.19//:unicode_ident",
"@crates_vendor__proc-macro2-1.0.103//:build_script_build",
"@crates_vendor__unicode-ident-1.0.22//:unicode_ident",
],
)

Expand Down Expand Up @@ -155,7 +155,7 @@ cargo_build_script(
"noclippy",
"norustfmt",
],
version = "1.0.101",
version = "1.0.103",
visibility = ["//visibility:private"],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,10 @@ rust_library(
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "1.0.41",
version = "1.0.42",
deps = [
"@crates_vendor__proc-macro2-1.0.101//:proc_macro2",
"@crates_vendor__quote-1.0.41//:build_script_build",
"@crates_vendor__proc-macro2-1.0.103//:proc_macro2",
"@crates_vendor__quote-1.0.42//:build_script_build",
],
)

Expand Down Expand Up @@ -155,7 +155,7 @@ cargo_build_script(
"noclippy",
"norustfmt",
],
version = "1.0.41",
version = "1.0.42",
visibility = ["//visibility:private"],
)

Expand Down
6 changes: 3 additions & 3 deletions bazel/cargo/remote/BUILD.syn-1.0.109.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ rust_library(
}),
version = "1.0.109",
deps = [
"@crates_vendor__proc-macro2-1.0.101//:proc_macro2",
"@crates_vendor__quote-1.0.41//:quote",
"@crates_vendor__proc-macro2-1.0.103//:proc_macro2",
"@crates_vendor__quote-1.0.42//:quote",
"@crates_vendor__syn-1.0.109//:build_script_build",
"@crates_vendor__unicode-ident-1.0.19//:unicode_ident",
"@crates_vendor__unicode-ident-1.0.22//:unicode_ident",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ rust_library(
"@rules_rust//rust/platform:x86_64-unknown-uefi": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "1.0.19",
version = "1.0.22",
)
44 changes: 22 additions & 22 deletions bazel/cargo/remote/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ _NORMAL_DEPENDENCIES = {
"": {
_COMMON_CONDITION: {
"hashbrown": Label("@crates_vendor//:hashbrown-0.16.0"),
"log": Label("@crates_vendor//:log-0.4.27"),
"log": Label("@crates_vendor//:log-0.4.28"),
},
},
}
Expand Down Expand Up @@ -454,12 +454,12 @@ def crate_repositories():

maybe(
http_archive,
name = "crates_vendor__log-0.4.27",
sha256 = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94",
name = "crates_vendor__log-0.4.28",
sha256 = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432",
type = "tar.gz",
urls = ["https://static.crates.io/crates/log/0.4.27/download"],
strip_prefix = "log-0.4.27",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.log-0.4.27.bazel"),
urls = ["https://static.crates.io/crates/log/0.4.28/download"],
strip_prefix = "log-0.4.28",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.log-0.4.28.bazel"),
)

maybe(
Expand All @@ -484,22 +484,22 @@ def crate_repositories():

maybe(
http_archive,
name = "crates_vendor__proc-macro2-1.0.101",
sha256 = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de",
name = "crates_vendor__proc-macro2-1.0.103",
sha256 = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8",
type = "tar.gz",
urls = ["https://static.crates.io/crates/proc-macro2/1.0.101/download"],
strip_prefix = "proc-macro2-1.0.101",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.proc-macro2-1.0.101.bazel"),
urls = ["https://static.crates.io/crates/proc-macro2/1.0.103/download"],
strip_prefix = "proc-macro2-1.0.103",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.proc-macro2-1.0.103.bazel"),
)

maybe(
http_archive,
name = "crates_vendor__quote-1.0.41",
sha256 = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1",
name = "crates_vendor__quote-1.0.42",
sha256 = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f",
type = "tar.gz",
urls = ["https://static.crates.io/crates/quote/1.0.41/download"],
strip_prefix = "quote-1.0.41",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.quote-1.0.41.bazel"),
urls = ["https://static.crates.io/crates/quote/1.0.42/download"],
strip_prefix = "quote-1.0.42",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.quote-1.0.42.bazel"),
)

maybe(
Expand All @@ -514,16 +514,16 @@ def crate_repositories():

maybe(
http_archive,
name = "crates_vendor__unicode-ident-1.0.19",
sha256 = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d",
name = "crates_vendor__unicode-ident-1.0.22",
sha256 = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5",
type = "tar.gz",
urls = ["https://static.crates.io/crates/unicode-ident/1.0.19/download"],
strip_prefix = "unicode-ident-1.0.19",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.unicode-ident-1.0.19.bazel"),
urls = ["https://static.crates.io/crates/unicode-ident/1.0.22/download"],
strip_prefix = "unicode-ident-1.0.22",
build_file = Label("@proxy_wasm_rust_sdk//bazel/cargo/remote:BUILD.unicode-ident-1.0.22.bazel"),
)

return [
struct(repo = "crates_vendor__hashbrown-0.16.0", is_dev_dep = False),
struct(repo = "crates_vendor__log-0.4.27", is_dev_dep = False),
struct(repo = "crates_vendor__log-0.4.28", is_dev_dep = False),
struct(repo = "crates_vendor__mockalloc-0.1.2", is_dev_dep = True),
]
19 changes: 19 additions & 0 deletions examples/tcp_rerouting/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
publish = false
name = "proxy-wasm-example-tcp-rerouting"
version = "0.0.1"
authors = ["Proxy-Wasm contributors"]
description = "Proxy-Wasm plugin example: TCP Rerouting based on source IP"
license = "Apache-2.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
log = "0.4"
proxy-wasm = { path = "../../" }
prost = "0.12"

[build-dependencies]
prost-build = "0.12"
81 changes: 81 additions & 0 deletions examples/tcp_rerouting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
## Proxy-Wasm plugin example: TCP Rerouting

Proxy-Wasm TCP filter that dynamically routes connections to different upstream clusters based on the source IP address.

Most WASM filter examples focus on HTTP, but this example shows how to work at the TCP/IP level.

This example is inspired by the [wasmerang](https://github.com/SiiiTschiii/wasmerang) project, which demonstrates advanced TCP routing patterns in Envoy/Istio/K8s using WASM filters.

### Overview

This example demonstrates how to build a TCP filter that:

- Intercepts incoming TCP connections
- Extracts the source IP address
- Routes traffic to different upstream clusters based on whether the last octet is even or odd
- **Even last octet** → routes to `egress-router1`
- **Odd last octet** → routes to `egress-router2`

The filter uses Envoy's `set_envoy_filter_state` foreign function to dynamically override the TCP proxy cluster at runtime, requiring proper protobuf encoding via the included `set_envoy_filter_state.proto` file.

### Building

Build the WASM plugin from the example directory:

```sh
$ cargo build --target wasm32-wasip1 --release
```

### Running with Docker Compose

This example can be run with [`docker compose`](https://docs.docker.com/compose/install/) and has a matching Envoy configuration.

From the example directory:

```sh
$ docker compose up
```

### Test the Routing

In separate terminals, test the routing behavior with different source IP addresses:

```bash
# Even IP (last octet 10) → routes to egress-router1
docker run --rm -it --network tcp_rerouting_envoymesh --ip 172.22.0.10 curlimages/curl curl http://proxy:10000/ip -H "Host: httpbin.org"

# Odd IP (last octet 11) → routes to egress-router2
docker run --rm -it --network tcp_rerouting_envoymesh --ip 172.22.0.11 curlimages/curl curl http://proxy:10000/ip -H "Host: httpbin.org"
```

### Expected Output

Check the Docker Compose logs to see the WASM filter in action:

```console
$ docker compose logs -f
```

**For even IP (last octet 10) → routes to egress-router1:**

```
proxy-1 | [TCP WASM] Source address: 172.22.0.10:39484
proxy-1 | [TCP WASM] Source IP last octet: 10, intercepting ALL traffic
proxy-1 | [TCP WASM] Routing to egress-router1
proxy-1 | [TCP WASM] set_envoy_filter_state status (envoy.tcp_proxy.cluster): Ok(None)
proxy-1 | [TCP WASM] Rerouting to egress-router1 via filter state
proxy-1 | [2025-11-20T03:08:18.423Z] cluster=egress-router1 src=172.22.0.10:39484 dst=172.22.0.2:10000 -> 35.170.145.70:80
```

**For odd IP (last octet 11) → routes to egress-router2:**

```
proxy-1 | [TCP WASM] Source address: 172.22.0.11:55320
proxy-1 | [TCP WASM] Source IP last octet: 11, intercepting ALL traffic
proxy-1 | [TCP WASM] Routing to egress-router2
proxy-1 | [TCP WASM] set_envoy_filter_state status (envoy.tcp_proxy.cluster): Ok(None)
proxy-1 | [TCP WASM] Rerouting to egress-router2 via filter state
proxy-1 | [2025-11-20T03:08:39.974Z] cluster=egress-router2 src=172.22.0.11:55320 dst=172.22.0.2:10000 -> 52.44.182.178:80
```

The `Ok(None)` status confirms that the filter state was successfully set, and you can see in the access logs that traffic is being routed to the correct clusters (`egress-router1` for even IPs, `egress-router2` for odd IPs).
11 changes: 11 additions & 0 deletions examples/tcp_rerouting/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::fs;

fn main() {
let out_dir = "src/generated";
fs::create_dir_all(out_dir).unwrap();
prost_build::Config::new()
.out_dir(out_dir)
.compile_protos(&["src/set_envoy_filter_state.proto"], &["src/"])
.unwrap();
println!("cargo:rerun-if-changed=src/set_envoy_filter_state.proto");
}
18 changes: 18 additions & 0 deletions examples/tcp_rerouting/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
services:
proxy:
image: envoyproxy/envoy:v1.34.1
entrypoint: /usr/local/bin/envoy -c /etc/envoy.yaml -l info --service-cluster proxy
volumes:
- ./envoy/envoy.yaml:/etc/envoy.yaml
- ./target/wasm32-wasip1/release/proxy_wasm_example_tcp_rerouting.wasm:/etc/tcp_rerouting.wasm
networks:
- envoymesh
ports:
- "10000:10000"
- "8001:8001"

networks:
envoymesh:
ipam:
config:
- subnet: 172.22.0.0/16
Loading