u32 banned_flags);
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
                    u32 banned_flags);
+int ipv4_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
+                        bool match_wildcard);
 int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
                         bool match_wildcard);
 void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
 
 
 struct sock *inet6_lookup_listener(struct net *net,
                                   struct inet_hashinfo *hashinfo,
+                                  struct sk_buff *skb, int doff,
                                   const struct in6_addr *saddr,
                                   const __be16 sport,
                                   const struct in6_addr *daddr,
 
 static inline struct sock *__inet6_lookup(struct net *net,
                                          struct inet_hashinfo *hashinfo,
+                                         struct sk_buff *skb, int doff,
                                          const struct in6_addr *saddr,
                                          const __be16 sport,
                                          const struct in6_addr *daddr,
        if (sk)
                return sk;
 
-       return inet6_lookup_listener(net, hashinfo, saddr, sport,
+       return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
                                     daddr, hnum, dif);
 }
 
 static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
-                                             struct sk_buff *skb,
+                                             struct sk_buff *skb, int doff,
                                              const __be16 sport,
                                              const __be16 dport,
                                              int iif)
        if (sk)
                return sk;
 
-       return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
-                             &ipv6_hdr(skb)->saddr, sport,
+       return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb,
+                             doff, &ipv6_hdr(skb)->saddr, sport,
                              &ipv6_hdr(skb)->daddr, ntohs(dport),
                              iif);
 }
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
+                         struct sk_buff *skb, int doff,
                          const struct in6_addr *saddr, const __be16 sport,
                          const struct in6_addr *daddr, const __be16 dport,
                          const int dif);
 
 
 struct sock *__inet_lookup_listener(struct net *net,
                                    struct inet_hashinfo *hashinfo,
+                                   struct sk_buff *skb, int doff,
                                    const __be32 saddr, const __be16 sport,
                                    const __be32 daddr,
                                    const unsigned short hnum,
 
 static inline struct sock *inet_lookup_listener(struct net *net,
                struct inet_hashinfo *hashinfo,
+               struct sk_buff *skb, int doff,
                __be32 saddr, __be16 sport,
                __be32 daddr, __be16 dport, int dif)
 {
-       return __inet_lookup_listener(net, hashinfo, saddr, sport,
+       return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, sport,
                                      daddr, ntohs(dport), dif);
 }
 
 
 static inline struct sock *__inet_lookup(struct net *net,
                                         struct inet_hashinfo *hashinfo,
+                                        struct sk_buff *skb, int doff,
                                         const __be32 saddr, const __be16 sport,
                                         const __be32 daddr, const __be16 dport,
                                         const int dif)
        struct sock *sk = __inet_lookup_established(net, hashinfo,
                                saddr, sport, daddr, hnum, dif);
 
-       return sk ? : __inet_lookup_listener(net, hashinfo, saddr, sport,
-                                            daddr, hnum, dif);
+       return sk ? : __inet_lookup_listener(net, hashinfo, skb, doff, saddr,
+                                            sport, daddr, hnum, dif);
 }
 
 static inline struct sock *inet_lookup(struct net *net,
                                       struct inet_hashinfo *hashinfo,
+                                      struct sk_buff *skb, int doff,
                                       const __be32 saddr, const __be16 sport,
                                       const __be32 daddr, const __be16 dport,
                                       const int dif)
        struct sock *sk;
 
        local_bh_disable();
-       sk = __inet_lookup(net, hashinfo, saddr, sport, daddr, dport, dif);
+       sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
+                          dport, dif);
        local_bh_enable();
 
        return sk;
 
 static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
                                             struct sk_buff *skb,
+                                            int doff,
                                             const __be16 sport,
                                             const __be16 dport)
 {
        if (sk)
                return sk;
        else
-               return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
-                                    iph->saddr, sport,
+               return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb,
+                                    doff, iph->saddr, sport,
                                     iph->daddr, dport, inet_iif(skb));
 }
 
 
        }
 
 lookup:
-       sk = __inet_lookup_skb(&dccp_hashinfo, skb,
+       sk = __inet_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
                               dh->dccph_sport, dh->dccph_dport);
        if (!sk) {
                dccp_pr_debug("failed to look up flow ID in table and "
 
                DCCP_SKB_CB(skb)->dccpd_ack_seq = dccp_hdr_ack_seq(skb);
 
 lookup:
-       sk = __inet6_lookup_skb(&dccp_hashinfo, skb,
+       sk = __inet6_lookup_skb(&dccp_hashinfo, skb, __dccp_hdr_len(dh),
                                dh->dccph_sport, dh->dccph_dport,
                                inet6_iif(skb));
        if (!sk) {
 
        struct sock *sk;
 
        if (req->sdiag_family == AF_INET)
-               sk = inet_lookup(net, hashinfo, req->id.idiag_dst[0],
+               sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[0],
                                 req->id.idiag_dport, req->id.idiag_src[0],
                                 req->id.idiag_sport, req->id.idiag_if);
 #if IS_ENABLED(CONFIG_IPV6)
        else if (req->sdiag_family == AF_INET6) {
                if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
                    ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
-                       sk = inet_lookup(net, hashinfo, req->id.idiag_dst[3],
+                       sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[3],
                                         req->id.idiag_dport, req->id.idiag_src[3],
                                         req->id.idiag_sport, req->id.idiag_if);
                else
-                       sk = inet6_lookup(net, hashinfo,
+                       sk = inet6_lookup(net, hashinfo, NULL, 0,
                                          (struct in6_addr *)req->id.idiag_dst,
                                          req->id.idiag_dport,
                                          (struct in6_addr *)req->id.idiag_src,
 
 
 struct sock *__inet_lookup_listener(struct net *net,
                                    struct inet_hashinfo *hashinfo,
+                                   struct sk_buff *skb, int doff,
                                    const __be32 saddr, __be16 sport,
                                    const __be32 daddr, const unsigned short hnum,
                                    const int dif)
 
                 * Incoming packet is checked with md5 hash with finding key,
                 * no RST generated if md5 hash doesn't match.
                 */
-               sk1 = __inet_lookup_listener(net,
-                                            &tcp_hashinfo, ip_hdr(skb)->saddr,
+               sk1 = __inet_lookup_listener(net, &tcp_hashinfo, NULL, 0,
+                                            ip_hdr(skb)->saddr,
                                             th->source, ip_hdr(skb)->daddr,
                                             ntohs(th->source), inet_iif(skb));
                /* don't send rst if it can't find key */
        TCP_SKB_CB(skb)->sacked  = 0;
 
 lookup:
-       sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
+       sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
+                              th->dest);
        if (!sk)
                goto no_tcp_socket;
 
        switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
        case TCP_TW_SYN: {
                struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
-                                                       &tcp_hashinfo,
+                                                       &tcp_hashinfo, skb,
+                                                       __tcp_hdrlen(th),
                                                        iph->saddr, th->source,
                                                        iph->daddr, th->dest,
                                                        inet_iif(skb));
 
 }
 
 struct sock *inet6_lookup_listener(struct net *net,
-               struct inet_hashinfo *hashinfo, const struct in6_addr *saddr,
+               struct inet_hashinfo *hashinfo,
+               struct sk_buff *skb, int doff,
+               const struct in6_addr *saddr,
                const __be16 sport, const struct in6_addr *daddr,
                const unsigned short hnum, const int dif)
 {
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
+                         struct sk_buff *skb, int doff,
                          const struct in6_addr *saddr, const __be16 sport,
                          const struct in6_addr *daddr, const __be16 dport,
                          const int dif)
        struct sock *sk;
 
        local_bh_disable();
-       sk = __inet6_lookup(net, hashinfo, saddr, sport, daddr, ntohs(dport), dif);
+       sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
+                           ntohs(dport), dif);
        local_bh_enable();
 
        return sk;
 
                 * no RST generated if md5 hash doesn't match.
                 */
                sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev),
-                                          &tcp_hashinfo, &ipv6h->saddr,
+                                          &tcp_hashinfo, NULL, 0,
+                                          &ipv6h->saddr,
                                           th->source, &ipv6h->daddr,
                                           ntohs(th->source), tcp_v6_iif(skb));
                if (!sk1)
        hdr = ipv6_hdr(skb);
 
 lookup:
-       sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest,
-                               inet6_iif(skb));
+       sk = __inet6_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th),
+                               th->source, th->dest, inet6_iif(skb));
        if (!sk)
                goto no_tcp_socket;
 
                struct sock *sk2;
 
                sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
+                                           skb, __tcp_hdrlen(th),
                                            &ipv6_hdr(skb)->saddr, th->source,
                                            &ipv6_hdr(skb)->daddr,
                                            ntohs(th->dest), tcp_v6_iif(skb));
 
  * belonging to established connections going through that one.
  */
 static inline struct sock *
-nf_tproxy_get_sock_v4(struct net *net, const u8 protocol,
+nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
+                     const u8 protocol,
                      const __be32 saddr, const __be32 daddr,
                      const __be16 sport, const __be16 dport,
                      const struct net_device *in,
                      const enum nf_tproxy_lookup_t lookup_type)
 {
        struct sock *sk;
+       struct tcphdr *tcph;
 
        switch (protocol) {
        case IPPROTO_TCP:
                switch (lookup_type) {
                case NFT_LOOKUP_LISTENER:
-                       sk = inet_lookup_listener(net, &tcp_hashinfo,
+                       tcph = hp;
+                       sk = inet_lookup_listener(net, &tcp_hashinfo, skb,
+                                                   ip_hdrlen(skb) +
+                                                     __tcp_hdrlen(tcph),
                                                    saddr, sport,
                                                    daddr, dport,
                                                    in->ifindex);
 
 #ifdef XT_TPROXY_HAVE_IPV6
 static inline struct sock *
-nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
+nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
+                     const u8 protocol,
                      const struct in6_addr *saddr, const struct in6_addr *daddr,
                      const __be16 sport, const __be16 dport,
                      const struct net_device *in,
                      const enum nf_tproxy_lookup_t lookup_type)
 {
        struct sock *sk;
+       struct tcphdr *tcph;
 
        switch (protocol) {
        case IPPROTO_TCP:
                switch (lookup_type) {
                case NFT_LOOKUP_LISTENER:
-                       sk = inet6_lookup_listener(net, &tcp_hashinfo,
+                       tcph = hp;
+                       sk = inet6_lookup_listener(net, &tcp_hashinfo, skb,
+                                                  thoff + __tcp_hdrlen(tcph),
                                                   saddr, sport,
                                                   daddr, ntohs(dport),
                                                   in->ifindex);
                 * to a listener socket if there's one */
                struct sock *sk2;
 
-               sk2 = nf_tproxy_get_sock_v4(net, iph->protocol,
+               sk2 = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol,
                                            iph->saddr, laddr ? laddr : iph->daddr,
                                            hp->source, lport ? lport : hp->dest,
                                            skb->dev, NFT_LOOKUP_LISTENER);
         * 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, iph->protocol,
+       sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol,
                                   iph->saddr, iph->daddr,
                                   hp->source, hp->dest,
                                   skb->dev, NFT_LOOKUP_ESTABLISHED);
        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, iph->protocol,
+               sk = nf_tproxy_get_sock_v4(net, skb, hp, iph->protocol,
                                           iph->saddr, laddr,
                                           hp->source, lport,
                                           skb->dev, NFT_LOOKUP_LISTENER);
                 * to a listener socket if there's one */
                struct sock *sk2;
 
-               sk2 = nf_tproxy_get_sock_v6(par->net, tproto,
+               sk2 = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp, tproto,
                                            &iph->saddr,
                                            tproxy_laddr6(skb, &tgi->laddr.in6, &iph->daddr),
                                            hp->source,
         * addresses, this happens if the redirect already happened
         * and the current packet belongs to an already established
         * connection */
-       sk = nf_tproxy_get_sock_v6(par->net, tproto,
+       sk = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp, tproto,
                                   &iph->saddr, &iph->daddr,
                                   hp->source, hp->dest,
                                   par->in, NFT_LOOKUP_ESTABLISHED);
        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_v6(par->net, tproto,
-                                          &iph->saddr, laddr,
+               sk = nf_tproxy_get_sock_v6(par->net, skb, thoff, hp,
+                                          tproto, &iph->saddr, laddr,
                                           hp->source, lport,
                                           par->in, NFT_LOOKUP_LISTENER);
 
 
  *     box.
  */
 static struct sock *
-xt_socket_get_sock_v4(struct net *net, const u8 protocol,
+xt_socket_get_sock_v4(struct net *net, struct sk_buff *skb, const int doff,
+                     const u8 protocol,
                      const __be32 saddr, const __be32 daddr,
                      const __be16 sport, const __be16 dport,
                      const struct net_device *in)
 {
        switch (protocol) {
        case IPPROTO_TCP:
-               return __inet_lookup(net, &tcp_hashinfo,
+               return __inet_lookup(net, &tcp_hashinfo, skb, doff,
                                     saddr, sport, daddr, dport,
                                     in->ifindex);
        case IPPROTO_UDP:
                                             const struct net_device *indev)
 {
        const struct iphdr *iph = ip_hdr(skb);
+       struct sk_buff *data_skb = NULL;
+       int doff = 0;
        __be32 uninitialized_var(daddr), uninitialized_var(saddr);
        __be16 uninitialized_var(dport), uninitialized_var(sport);
        u8 uninitialized_var(protocol);
                sport = hp->source;
                daddr = iph->daddr;
                dport = hp->dest;
+               data_skb = (struct sk_buff *)skb;
+               doff = iph->protocol == IPPROTO_TCP ?
+                       ip_hdrlen(skb) + __tcp_hdrlen((struct tcphdr *)hp) :
+                       ip_hdrlen(skb) + sizeof(*hp);
 
        } else if (iph->protocol == IPPROTO_ICMP) {
                if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr,
        }
 #endif
 
-       return xt_socket_get_sock_v4(net, protocol, saddr, daddr,
-                                    sport, dport, indev);
+       return xt_socket_get_sock_v4(net, data_skb, doff, protocol, saddr,
+                                    daddr, sport, dport, indev);
 }
 
 static bool
 }
 
 static struct sock *
-xt_socket_get_sock_v6(struct net *net, const u8 protocol,
+xt_socket_get_sock_v6(struct net *net, struct sk_buff *skb, int doff,
+                     const u8 protocol,
                      const struct in6_addr *saddr, const struct in6_addr *daddr,
                      const __be16 sport, const __be16 dport,
                      const struct net_device *in)
 {
        switch (protocol) {
        case IPPROTO_TCP:
-               return inet6_lookup(net, &tcp_hashinfo,
+               return inet6_lookup(net, &tcp_hashinfo, skb, doff,
                                    saddr, sport, daddr, dport,
                                    in->ifindex);
        case IPPROTO_UDP:
        __be16 uninitialized_var(dport), uninitialized_var(sport);
        const struct in6_addr *daddr = NULL, *saddr = NULL;
        struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct sk_buff *data_skb = NULL;
+       int doff = 0;
        int thoff = 0, tproto;
 
        tproto = ipv6_find_hdr(skb, &thoff, -1, NULL, NULL);
                sport = hp->source;
                daddr = &iph->daddr;
                dport = hp->dest;
+               data_skb = (struct sk_buff *)skb;
+               doff = tproto == IPPROTO_TCP ?
+                       thoff + __tcp_hdrlen((struct tcphdr *)hp) :
+                       thoff + sizeof(*hp);
 
        } else if (tproto == IPPROTO_ICMPV6) {
                struct ipv6hdr ipv6_var;
                return NULL;
        }
 
-       return xt_socket_get_sock_v6(net, tproto, saddr, daddr,
+       return xt_socket_get_sock_v6(net, data_skb, doff, tproto, saddr, daddr,
                                     sport, dport, indev);
 }