当前位置:网站首页>iptables目标TPROXY
iptables目标TPROXY
2022-06-30 10:21:00 【redwingz】
TPROXY目标帮助信息如下。
# iptables -j TPROXY -h
TPROXY target options:
--on-port port Redirect connection to port, or the original port if 0
--on-ip ip Optionally redirect to the given IP
--tproxy-mark value[/mask] Mark packets with the given value/mask
如下配置,将目的端口80的报文设置标记1,并且送到本机监听在30080的套接口。
# iptables -t mangle -A PREROUTING -p tcp --dport 80 -j TPROXY \
--tproxy-mark 0x1/0x1 --on-port 30080
#
# iptables -t mangle -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
TPROXY tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
TPROXY redirect 0.0.0.0:30080 mark 0x1/0x1
配置如下的IP路由策略,将标记为1的报文,送到本机回环设备lo处理,本机接收:
# ip rule add fwmark 1 lookup 100
# ip route add local 0.0.0.0/0 dev lo table 100
应用层程序,需要设置套接口IP层选项IP_TRANSPARENT(SOL_IP, IP_TRANSPARENT),以接收代理报文。
TPROXY目标
函数xt_register_targets注册目标结构tproxy_tg_reg。
static struct xt_target tproxy_tg_reg[] __read_mostly = {
{
.name = "TPROXY",
.family = NFPROTO_IPV4,
.table = "mangle",
.target = tproxy_tg4_v1,
.revision = 1,
.targetsize = sizeof(struct xt_tproxy_target_info_v1),
.checkentry = tproxy_tg4_check,
.hooks = 1 << NF_INET_PRE_ROUTING,
.me = THIS_MODULE,
},
static int __init tproxy_tg_init(void)
{
return xt_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg));
配置检查函数如下,对于IPv4协议,启用报文重组功能,透明代理仅支持TCP和UDP协议。
static int tproxy_tg4_check(const struct xt_tgchk_param *par)
{
const struct ipt_ip *i = par->entryinfo;
int err;
err = nf_defrag_ipv4_enable(par->net);
if (err)
return err;
if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP)
&& !(i->invflags & IPT_INV_PROTO))
return 0;
pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
return -EINVAL;
目标处理函数如下,tproxy_tg4使用的参数如上所示:(TPROXY redirect 0.0.0.0:30080 mark 0x1/0x1)
static unsigned int
tproxy_tg4_v1(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_tproxy_target_info_v1 *tgi = par->targinfo;
return tproxy_tg4(xt_net(par), skb, tgi->laddr.ip, tgi->lport,
tgi->mark_mask, tgi->mark_value);
首先,检查报文是否属于连接建立完成的套接口,其次,确定本地的IP地址和端口号,如果TPROXY配置的本地地址为零,使用接收数据包的接口上的IP地址作为本地地址。如果,配置的本地端口为零,使用报文中的目的端口。
static unsigned int
tproxy_tg4(struct net *net, struct sk_buff *skb, __be32 laddr, __be16 lport,
u_int32_t mark_mask, u_int32_t mark_value)
{
const struct iphdr *iph = ip_hdr(skb);
struct udphdr _hdr, *hp;
struct sock *sk;
hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
if (hp == NULL)
return NF_DROP;
/* check if there's an ongoing connection on the packet
* addresses, this happens if the redirect already happened
* and the current packet belongs to an already established
* connection */
sk = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, iph->daddr,
hp->source, hp->dest,
skb->dev, NF_TPROXY_LOOKUP_ESTABLISHED);
laddr = nf_tproxy_laddr4(skb, laddr, iph->daddr);
if (!lport)
lport = hp->dest;
如果以上没有找到连接建立状态的套接口,查找监听状态的套接口。
/* UDP has no TCP_TIME_WAIT state, so we never enter here */
if (sk && sk->sk_state == TCP_TIME_WAIT)
/* reopening a TIME_WAIT connection needs special handling */
sk = nf_tproxy_handle_time_wait4(net, skb, laddr, lport, sk);
else if (!sk)
/* no, there's no established connection, check if
* there's a listener on the redirected addr/port */
sk = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, laddr,
hp->source, lport,
skb->dev, NF_TPROXY_LOOKUP_LISTENER);
如果找到的套接口设置了透明选项,将套接口赋值于skb。否则,丢弃报文。
/* NOTE: assign_sock consumes our sk reference */
if (sk && nf_tproxy_sk_is_transparent(sk)) {
/* This should be in a separate target, but we don't do multiple
targets on the same rule yet */
skb->mark = (skb->mark & ~mark_mask) ^ mark_value;
pr_debug("redirecting: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
iph->protocol, &iph->daddr, ntohs(hp->dest),
&laddr, ntohs(lport), skb->mark);
nf_tproxy_assign_sock(skb, sk);
return NF_ACCEPT;
}
pr_debug("no socket, dropping: proto %hhu %pI4:%hu -> %pI4:%hu, mark: %x\n",
iph->protocol, &iph->saddr, ntohs(hp->source),
&iph->daddr, ntohs(hp->dest), skb->mark);
return NF_DROP;
TCP套接口
对于TCP协议,一般情况下在函数__inet_lookup_skb中查找套接口。
int tcp_v4_rcv(struct sk_buff *skb)
{
th = (const struct tcphdr *)skb->data;
iph = ip_hdr(skb);
lookup:
sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
th->dest, sdif, &refcounted);
但是,如果skb结构中已有可用的套接口,返回此套接口(TPROXY中赋值)。
static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
struct sk_buff *skb, int doff,
const __be16 sport, const __be16 dport,
const int sdif, bool *refcounted)
{
struct sock *sk = skb_steal_sock(skb, refcounted);
const struct iphdr *iph = ip_hdr(skb);
if (sk)
return sk;
对于TIME_WAIT状态的TCP套接口,如果接收到的报文是一个SYN报文,查找是否存在监听状态的套接口,优先使用监听套接口。
struct sock *
nf_tproxy_handle_time_wait4(struct net *net, struct sk_buff *skb,
__be32 laddr, __be16 lport, struct sock *sk)
{
const struct iphdr *iph = ip_hdr(skb);
struct tcphdr _hdr, *hp;
hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr);
if (hp == NULL) {
inet_twsk_put(inet_twsk(sk));
return NULL;
}
if (hp->syn && !hp->rst && !hp->ack && !hp->fin) {
/* SYN to a TIME_WAIT socket, we'd rather redirect it
* to a listener socket if there's one */
struct sock *sk2;
sk2 = nf_tproxy_get_sock_v4(net, skb, iph->protocol,
iph->saddr, laddr ? laddr : iph->daddr,
hp->source, lport ? lport : hp->dest,
skb->dev, NF_TPROXY_LOOKUP_LISTENER);
if (sk2) {
inet_twsk_deschedule_put(inet_twsk(sk));
sk = sk2;
}
}
return sk;
UDP套接口
对于UDP协议,如果skb中套接口结构不为空,使用此套接口(TPROXY中赋值)。
int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
int proto)
{
sk = skb_steal_sock(skb, &refcounted);
if (sk) {
struct dst_entry *dst = skb_dst(skb);
int ret;
if (unlikely(sk->sk_rx_dst != dst))
udp_sk_rx_dst_set(sk, dst);
ret = udp_unicast_rcv_skb(sk, skb, uh);
if (refcounted)
sock_put(sk);
return ret;
}
内核版本 5.10
边栏推荐
- 安徽《合肥市装配式建筑施工图审查设计深度要求》印发;河北衡水市调整装配式建筑预售许可标准
- 经典面试题:负责的模块,针对这些功能点你是怎么设计测试用例的?【杭州多测师】【杭州多测师_王sir】...
- pytorch 笔记:validation ,model.eval V.S torch.no_grad
- 断路器HystrixCircuitBreaker
- SGD has many improved forms. Why do most papers still use SGD?
- 数据库什么时候需要使用索引【杭州多测师】【杭州多测师_王sir】
- 科普达人丨漫画图解什么是eRDMA?
- [机缘参悟-34]:光锥之内皆命运
- LVGL 8.2 Simple Image button
- Dickinson's soul chooses its companion
猜你喜欢

List introduction

Matplotlib notes: contour & Contour

China will force a unified charging interface. If Apple does not bow its head, iPhone will be kicked out of the Chinese market

智能DNA分子纳米机器人模型来了

Retest the cloud native database performance: polardb is still the strongest, while tdsql-c and gaussdb have little change

What is erdma as illustrated by Coptic cartoon?

MATLAB image histogram equalization, namely spatial filtering
![[机缘参悟-34]:光锥之内皆命运](/img/3e/9f5630ba382df7f7ce00705445cef8.jpg)
[机缘参悟-34]:光锥之内皆命运

Sarsa笔记

Q-Learning笔记
随机推荐
今晚19:00知识赋能第2期直播丨OpenHarmony智能家居项目之控制面板界面设计
Rejuvenated Dell and apple hit each other, and the two old PC enterprises declined rapidly
Apple's 5g chip was revealed to have failed in research and development, and the QQ password bug caused heated discussion. Wei Lai responded to the short selling rumors. Today, more big news is here
超长干货 | Kubernetes命名空间详解
Memory escape analysis
深潜Kotlin协程(十七):演员
时间复杂度与空间复杂度
CSDN daily one practice 2021.11.06 question 1 (C language)
Time complexity and space complexity
微信推出图片大爆炸功能;苹果自研 5G 芯片或已失败;微软解决导致 Edge 停止响应的 bug|极客头条...
Robotframework learning notes: environment installation and robotframework browser plug-in installation
matplotlib 笔记: contourf & contour
基于HAL库的LED驱动库
Mysql database foundation: views and variables
Pycharm项目使用pyinstalle打包过程中问题及解决方案
scratch绘制正方形 电子学会图形化编程scratch等级考试二级真题和答案解析2022年6月
Agile Development: super easy to use bucket estimation system
Double-DQN笔记
CSDN博客运营团队2022年H1总结
【深度学习】深度学习检测小目标常用方法