由于:linux 新内核tcp/ip协议栈中添加了 TCP_NEW_SYN_RECV; 所以 在判断sk是否为transparent 时 需要考虑其状态;
static bool tproxy_sk_is_transparent(struct sock *sk) { switch (sk->sk_state) { case TCP_TIME_WAIT: if (inet_twsk(sk)->tw_transparent) return true; break; case TCP_NEW_SYN_RECV: if (inet_rsk(inet_reqsk(sk))->no_srccheck) return true; break; default: if (inet_sk(sk)->transparent) return true; } sock_gen_put(sk); return false; }
/** * tcp_make_synack - Prepare a SYN-ACK. * sk: listener socket * dst: dst entry attached to the SYNACK * req: request_sock pointer * * Allocate one skb and build a SYNACK packet. * @dst is consumed : Caller should not use it again. */ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, struct request_sock *req, struct tcp_fastopen_cookie *foc, bool attach_req) { struct inet_request_sock *ireq = inet_rsk(req); const struct tcp_sock *tp = tcp_sk(sk); struct tcp_md5sig_key *md5 = NULL; struct tcp_out_options opts; struct sk_buff *skb; int tcp_header_size; struct tcphdr *th; u16 user_mss; int mss; skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); ------------------------------- if (attach_req) { skb_set_owner_w(skb, req_to_sk(req)); } else { /* sk is a const pointer, because we want to express multiple * cpu might call us concurrently. * sk->sk_wmem_alloc in an atomic, we can promote to rw. */ skb_set_owner_w(skb, (struct sock *)sk); } ----------------------------------- }
处理syn包回复syn_ack时, 设置回复报文skb结构时, 其skb->sk 可能指向req_sock 可能指向listen sk;此时和以前内核版本不一样;
所以后续处理报文以及判断此skb的transparent属性时 需要判断其sk具体指向以及数值
对于 sk 的释放:
/* All sockets share common refcount, but have different destructors */ void sock_gen_put(struct sock *sk) { if (!atomic_dec_and_test(&sk->sk_refcnt)) return; if (sk->sk_state == TCP_TIME_WAIT) inet_twsk_free(inet_twsk(sk)); else if (sk->sk_state == TCP_NEW_SYN_RECV) reqsk_free(inet_reqsk(sk)); else sk_free(sk); } EXPORT_SYMBOL_GPL(sock_gen_put); void sock_edemux(struct sk_buff *skb) { sock_gen_put(skb->sk); }
/* assign a socket to the skb -- consumes sk */
static void
nf_tproxy_assign_sock(struct sk_buff *skb, struct sock *sk)
{
skb_orphan(skb);
skb->sk = sk;
skb->destructor = sock_edemux;
}
也就是需要分各种状态释放skb->sk