Commit 88ef4a5a authored by KOVACS Krisztian's avatar KOVACS Krisztian Committed by David S. Miller

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: default avatarKOVACS Krisztian <hidden@sch.bme.hu>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 79876874
...@@ -72,7 +72,8 @@ struct inet_request_sock { ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment