tcp: Handle TCP SYN+ACK/ACK/RST transparency
The TCP stack sends out SYN+ACK/ACK/RST reply packets in response to incoming packets. The non-local source address check on output bites us again, as replies for transparently redirected traffic won't have a chance to leave the node. This patch selectively sets the FLOWI_FLAG_ANYSRC flag when doing the route lookup for those replies. Transparent replies are enabled if the listening socket has the transparent socket flag set. Signed-off-by: KOVACS Krisztian <hidden@sch.bme.hu> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
79876874ce
commit
88ef4a5a78
3 changed files with 19 additions and 4 deletions
|
@ -72,7 +72,8 @@ struct inet_request_sock {
|
||||||
sack_ok : 1,
|
sack_ok : 1,
|
||||||
wscale_ok : 1,
|
wscale_ok : 1,
|
||||||
ecn_ok : 1,
|
ecn_ok : 1,
|
||||||
acked : 1;
|
acked : 1,
|
||||||
|
no_srccheck: 1;
|
||||||
struct ip_options *opt;
|
struct ip_options *opt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -204,4 +205,9 @@ static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
|
||||||
|
{
|
||||||
|
return inet_sk(sk)->transparent ? FLOWI_FLAG_ANYSRC : 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _INET_SOCK_H */
|
#endif /* _INET_SOCK_H */
|
||||||
|
|
|
@ -140,12 +140,15 @@ static inline void ip_tr_mc_map(__be32 addr, char *buf)
|
||||||
|
|
||||||
struct ip_reply_arg {
|
struct ip_reply_arg {
|
||||||
struct kvec iov[1];
|
struct kvec iov[1];
|
||||||
|
int flags;
|
||||||
__wsum csum;
|
__wsum csum;
|
||||||
int csumoffset; /* u16 offset of csum in iov[0].iov_base */
|
int csumoffset; /* u16 offset of csum in iov[0].iov_base */
|
||||||
/* -1 if not needed */
|
/* -1 if not needed */
|
||||||
int bound_dev_if;
|
int bound_dev_if;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define IP_REPLY_ARG_NOSRCCHECK 1
|
||||||
|
|
||||||
void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
|
void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
|
||||||
unsigned int len);
|
unsigned int len);
|
||||||
|
|
||||||
|
|
|
@ -591,6 +591,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
|
||||||
ip_hdr(skb)->saddr, /* XXX */
|
ip_hdr(skb)->saddr, /* XXX */
|
||||||
sizeof(struct tcphdr), IPPROTO_TCP, 0);
|
sizeof(struct tcphdr), IPPROTO_TCP, 0);
|
||||||
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
|
arg.csumoffset = offsetof(struct tcphdr, check) / 2;
|
||||||
|
arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0;
|
||||||
|
|
||||||
net = dev_net(skb->dst->dev);
|
net = dev_net(skb->dst->dev);
|
||||||
ip_send_reply(net->ipv4.tcp_sock, skb,
|
ip_send_reply(net->ipv4.tcp_sock, skb,
|
||||||
|
@ -606,7 +607,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
|
||||||
|
|
||||||
static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
|
static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
|
||||||
u32 win, u32 ts, int oif,
|
u32 win, u32 ts, int oif,
|
||||||
struct tcp_md5sig_key *key)
|
struct tcp_md5sig_key *key,
|
||||||
|
int reply_flags)
|
||||||
{
|
{
|
||||||
struct tcphdr *th = tcp_hdr(skb);
|
struct tcphdr *th = tcp_hdr(skb);
|
||||||
struct {
|
struct {
|
||||||
|
@ -659,6 +661,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
|
||||||
ip_hdr(skb)->daddr, &rep.th);
|
ip_hdr(skb)->daddr, &rep.th);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
arg.flags = reply_flags;
|
||||||
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
|
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
|
||||||
ip_hdr(skb)->saddr, /* XXX */
|
ip_hdr(skb)->saddr, /* XXX */
|
||||||
arg.iov[0].iov_len, IPPROTO_TCP, 0);
|
arg.iov[0].iov_len, IPPROTO_TCP, 0);
|
||||||
|
@ -681,7 +684,8 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
|
||||||
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
|
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
|
||||||
tcptw->tw_ts_recent,
|
tcptw->tw_ts_recent,
|
||||||
tw->tw_bound_dev_if,
|
tw->tw_bound_dev_if,
|
||||||
tcp_twsk_md5_key(tcptw)
|
tcp_twsk_md5_key(tcptw),
|
||||||
|
tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0
|
||||||
);
|
);
|
||||||
|
|
||||||
inet_twsk_put(tw);
|
inet_twsk_put(tw);
|
||||||
|
@ -694,7 +698,8 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
|
||||||
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
|
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
|
||||||
req->ts_recent,
|
req->ts_recent,
|
||||||
0,
|
0,
|
||||||
tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr));
|
tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr),
|
||||||
|
inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1244,6 +1249,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
|
||||||
ireq = inet_rsk(req);
|
ireq = inet_rsk(req);
|
||||||
ireq->loc_addr = daddr;
|
ireq->loc_addr = daddr;
|
||||||
ireq->rmt_addr = saddr;
|
ireq->rmt_addr = saddr;
|
||||||
|
ireq->no_srccheck = inet_sk(sk)->transparent;
|
||||||
ireq->opt = tcp_v4_save_options(sk, skb);
|
ireq->opt = tcp_v4_save_options(sk, skb);
|
||||||
if (!want_cookie)
|
if (!want_cookie)
|
||||||
TCP_ECN_create_request(req, tcp_hdr(skb));
|
TCP_ECN_create_request(req, tcp_hdr(skb));
|
||||||
|
|
Loading…
Reference in a new issue