Rust UDP透明代理:TPROXY无法接收全部待重定向流量的问题
Rust UDP透明代理TPROXY配置问题
使用的依赖crate
- socket2:用于创建RAW socket
- nix::sys::socket:用于调用底层socket API
- std::net::socket:用于标准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:代理监听35端口可接收全部客户端流量,但读取数据包时原目标地址会被覆盖为代理机器IP
- TPROXY:仅能接收广播流量和目标MAC为代理机器的流量,无法获取所有客户端流量
程序相关实现
已遵循Linux内核tproxy手册配置,程序中设置了IP_TRANSPARENT等选项:
Socket配置代码
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) { ... }; match setsockopt(&socket_ref, Ipv4OrigDstAddr, &active) { ... }; match setsockopt(&socket_ref, Ipv4PacketInfo, &active) { ... }; ...
recvmsg处理代码
let target_address: SockaddrIn = match recvmsg::<SockaddrIn>(*socket_clone, &mut iov, Some(&mut cmsg_space!(nix_msghdr)), flags) { Ok(t) => { let ctrl_msg: Vec<ControlMessageOwned> = t.cmsgs().collect(); let mut res: SockaddrIn = SockaddrIn::new(0, 0, 0, 0, 0); for c in ctrl_msg { if let ControlMessageOwned::Ipv4OrigDstAddr(b) = c { let addr: [u8; 4] = convert_u32_to_4u8(b.sin_addr.s_addr); let port: u16 = b.sin_port; let new_port: u16 = ((port & (0xFF << 8)) >> 8) | ((port & 0xFF) << 8); res = SockaddrIn::new(addr[0], addr[1], addr[2], addr[3], new_port); } if let ControlMessageOwned::Ipv4PacketInfo(b) = c { debug!("IP_PKTINFO => {:?}", b); } } res }, Err(e) => { error!("Could not extract the original destination from the socket ; Error => {}", e); std::process::exit(15); } };
注:完整程序达400行,此处仅展示相关代码。
内容的提问来源于stack exchange,提问作者User582016482
相关产品推荐
相关产品推荐

