私はRustでUDP透過プロキシを書いています。いくつかのクレートを使用しています。
- ソケット2=> RAWソケットの作成へのアクセス
- nix::sys::socket=> すべての低レベルソケットAPI呼び出しへのアクセス
- std::net::socket=> 標準ソケットへのアクセス
プロキシとして機能するはずのマシンが、ターゲット マシンのゲートウェイとして設定されています。
プロキシマシンでは Linux カーネルのリダイレクト機能が有効になっています。以下のスニペットを参照してください。
#!/bin/sh
# Redirect packets coming to the computer
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
# Disable ICMP redirection
sysctl -w net.ipv4.conf.all.send_redirects=0
マシンには、NFTABLES
すべての着信トラフィックをプロキシプログラムにリダイレクトするルールも設定されています。以下のスニペットを参照してください。
#!/bin/sh
# Setting up NFTABLES
nft add table filter
nft add chain filter divert "{ type filter hook prerouting priority -150; }"
nft add rule filter divert meta l4proto udp socket transparent 1 meta mark set 1 accept
#nft add table ip nat
#nft -- add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
# Creating a new rule that redirects UDP traffic from P1-P2 to port 35
nft add rule filter divert udp dport 80-65525 tproxy to :35 meta mark set 1 accept
#nft add rule ip nat prerouting udp dport 80-65525 redirect to :35
コメントアウトされた部分からわかるように、私はNAT PREROUTING
との両方を試しましたTPROXY
。 広範囲にわたる調査とテストの結果、NAT PREROUTING
プロキシ (ポート 35 でリッスンしている) を使用すると、クライアントからの着信トラフィックがすべて取得されますが、ソケットからパケットを読み取ると、元の宛先アドレスがプロキシ マシンの IP で上書きされる (これは望ましくありません) ことがわかりました。 しかし、代わりに を使用すると、着信TPROXY
トラフィックがすべて取得されるわけではなく、マシンが「認識するはず」のもの (たとえば、ブロードキャスト トラフィックや、プロキシ マシンの MAC アドレスを宛先とするトラフィック) のみが取得されます。つまり、接続されたクライアントからのトラフィックがすべて認識されるわけではありません。
私が設定していることに注意する必要がありますIP_TRANSPARENT
。
これらは私がプログラムで設定したものです
use socket2::{Socket, Domain, Type, Protocol};
use std::os::fd::{OwnedFd, RawFd, AsRawFd};
use nix::sys::socket::{
...
sockopt::{IpTransparent, Ipv4OrigDstAddr, Ipv4PacketInfo},
setsockopt,
...
};
...
let client_to_proxy_socket = match Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::UDP)) { ... };
let socket_ref: OwnedFd = client_to_proxy_socket.into();
let active: bool = true;
match setsockopt(&socket_ref, IpTransparent, &active) { ... }; // IP_TRANSPARENT
match setsockopt(&socket_ref, Ipv4OrigDstAddr, &active) { ... }; // SO_ORIGINAL_DST
match setsockopt(&socket_ref, Ipv4PacketInfo, &active) { ... }; // IP_PKTINFO
...
私が試したことに関して言えば、バリエーションや異なる構造を持つルールとコードのさまざまな組み合わせを試したと言わざるを得ません。
すでに何度も訪れて読んだリンクの短いリストを投稿します
- Rust で RX および TX タイムスタンプ用の非同期ソケット recvmsg を実装する
- 受信したUDPパケットの宛先アドレスを取得する
- iptables を使用してシステム全体のトラフィックをローカル プロキシ サーバーにリダイレクトする
- REDIRECTの代わりにiptables TPROXYを使用する
- 透過プロキシの IPTables 構成
私が期待していることとしては、すべての着信トラフィックを取得し、それをTPROXY
ポート 35 にリダイレクトすることを期待しています。
私も stackoverflow に同様の質問を投稿しましたが、これはプログラミングに関する質問だけでなく、ネットワーク/Linux に関する質問でもある可能性があることに気づきました。
もう 1 つ注意したいのは、昨日のテスト中に、無効にしたにもかかわらずICMP redirection
(最初のスニペットを参照)、マシンが ICMP リダイレクト メッセージを送信し、Wireshark で読み取っているのがわかり、かなり困惑したことです。