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); /* 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; }
static unsigned int tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct iphdr *iph = ip_hdr(skb); const struct xt_tproxy_target_info *tgi = par->targinfo; struct udphdr _hdr, *hp; struct sock *sk; hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) return NF_DROP; sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), iph->protocol, iph->saddr, tgi->laddr ? tgi->laddr : iph->daddr, hp->source, tgi->lport ? tgi->lport : hp->dest, par->in, true); /* NOTE: assign_sock consumes our sk reference */ if (sk && nf_tproxy_assign_sock(skb, sk)) { /* This should be in a separate target, but we don't do multiple targets on the same rule yet */ skb->mark = (skb->mark & ~tgi->mark_mask) ^ tgi->mark_value; pr_debug("redirecting: proto %u %08x:%u -> %08x:%u, mark: %x\n", iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark); return NF_ACCEPT; } pr_debug("no socket, dropping: proto %u %08x:%u -> %08x:%u, mark: %x\n", iph->protocol, ntohl(iph->daddr), ntohs(hp->dest), ntohl(tgi->laddr), ntohs(tgi->lport), skb->mark); return NF_DROP; }
struct sock* xt_socket_get4_sk(const struct sk_buff *skb, struct xt_action_param *par) { const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; __be32 daddr, saddr; __be16 dport = 0, sport = 0; u8 protocol = 0; #ifdef XT_SOCKET_HAVE_CONNTRACK struct nf_conn const *ct; enum ip_conntrack_info ctinfo; #endif if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) return NULL; protocol = iph->protocol; saddr = iph->saddr; sport = hp->source; daddr = iph->daddr; dport = hp->dest; } else if (iph->protocol == IPPROTO_ICMP) { if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, &sport, &dport)) return NULL; } else { return NULL; } #ifdef XT_SOCKET_HAVE_CONNTRACK /* Do the lookup with the original socket address in case this is a * reply packet of an established SNAT-ted connection. */ ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct) && ((iph->protocol != IPPROTO_ICMP && ctinfo == IP_CT_ESTABLISHED_REPLY) || (iph->protocol == IPPROTO_ICMP && ctinfo == IP_CT_RELATED_REPLY)) && (ct->status & IPS_SRC_NAT_DONE)) { daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; dport = (iph->protocol == IPPROTO_TCP) ? ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port : ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; } #endif sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY); pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n", protocol, &saddr, ntohs(sport), &daddr, ntohs(dport), &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); return sk; }
static bool socket_match(const struct sk_buff *skb, struct xt_action_param *par, const struct xt_socket_mtinfo1 *info) { const struct iphdr *iph = ip_hdr(skb); struct udphdr _hdr, *hp = NULL; struct sock *sk; __be32 daddr, saddr; __be16 dport, sport; u8 protocol; #ifdef XT_SOCKET_HAVE_CONNTRACK struct nf_conn const *ct; enum ip_conntrack_info ctinfo; #endif if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) { hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) return false; protocol = iph->protocol; saddr = iph->saddr; sport = hp->source; daddr = iph->daddr; dport = hp->dest; } else if (iph->protocol == IPPROTO_ICMP) { if (extract_icmp4_fields(skb, &protocol, &saddr, &daddr, &sport, &dport)) return false; } else { return false; } #ifdef XT_SOCKET_HAVE_CONNTRACK /* Do the lookup with the original socket address in case this is a * reply packet of an established SNAT-ted connection. */ ct = nf_ct_get(skb, &ctinfo); if (ct && !nf_ct_is_untracked(ct) && ((iph->protocol != IPPROTO_ICMP && ctinfo == IP_CT_ESTABLISHED_REPLY) || (iph->protocol == IPPROTO_ICMP && ctinfo == IP_CT_RELATED_REPLY)) && (ct->status & IPS_SRC_NAT_DONE)) { daddr = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; dport = (iph->protocol == IPPROTO_TCP) ? ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port : ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; } #endif sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), protocol, saddr, daddr, sport, dport, par->in, NFT_LOOKUP_ANY); if (sk != NULL) { bool wildcard; bool transparent = true; /* Ignore sockets listening on INADDR_ANY */ wildcard = (sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->inet_rcv_saddr == 0); /* Ignore non-transparent sockets, if XT_SOCKET_TRANSPARENT is used */ if (info && info->flags & XT_SOCKET_TRANSPARENT) transparent = ((sk->sk_state != TCP_TIME_WAIT && inet_sk(sk)->transparent) || (sk->sk_state == TCP_TIME_WAIT && inet_twsk(sk)->tw_transparent)); xt_socket_put_sk(sk); if (wildcard || !transparent) sk = NULL; } pr_debug("proto %hhu %pI4:%hu -> %pI4:%hu (orig %pI4:%hu) sock %p\n", protocol, &saddr, ntohs(sport), &daddr, ntohs(dport), &iph->daddr, hp ? ntohs(hp->dest) : 0, sk); return (sk != NULL); }
unsigned int tproxy_func(unsigned int hooknum, struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int(*okfn)(struct sk_buff*)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; __be32 newdst; struct nf_nat_range newrange; union nf_conntrack_man_proto min, max; struct iphdr *nowiph; struct udphdr _hdr, *hp; struct sock *sk; struct net_device *dev; uint16_t dport = 3333; uint32_t sip = 0xc0a80101; uint32_t taddr; nowiph = (struct iphdr *)skb_network_header(skb); if(nowiph->protocol != IPPROTO_TCP && nowiph->protocol != IPPROTO_UDP) { printk("1 "); return NF_ACCEPT; } taddr = ntohl(nowiph->saddr); if ( ((taddr & 0xFFFFFF00) != (sip & 0xFFFFFF00)) || (taddr == sip) ) { //ignore local ip or not subnet ip printk("2 "); return NF_ACCEPT; } hp = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_hdr), &_hdr); if (hp == NULL) { printk("3 "); return NF_ACCEPT; } /* nowtcp = (struct tcphdr *)(skb->data + (nowiph->ihl*4)); if(ntohs(nowtcp->dest) != 80) { return NF_ACCEPT; } */ dev = skb->dev; if (!dev) { printk("4 "); return NF_ACCEPT; } if(htons(23) == hp->dest || htons(3333) == hp->dest) { return NF_ACCEPT; } newdst = htonl(sip); sk = nf_tproxy_get_sock_v4(dev_net(skb->dev), nowiph->protocol, nowiph->saddr, //newdst, nowiph->daddr, hp->source, //htonl(dport), hp->dest, dev, true); if(sk == NULL) { printk("pass sk, src=0x%02x target=0x%02x port=%d, %d\n", nowiph->saddr, nowiph->daddr, hp->source, hp->dest); return NF_ACCEPT; } printk("pass sk, src=0x%02x target=0x%02x port=%d, %d\n", nowiph->saddr, nowiph->daddr, hp->source, hp->dest); //printk("got sk, src=0x%02x target=0x%02x\n", nowiph->saddr, nowiph->daddr); NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING); /* min.tcp.port = htons(dport); max.tcp.port = htons(dport); ct = nf_ct_get(skb, &ctinfo); NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); newrange = ((struct nf_nat_range) { IP_NAT_RANGE_PROTO_SPECIFIED | IP_NAT_RANGE_MAP_IPS, newdst, newdst, min, max }); */ /* dev = skb->input_dev; if (dev != NULL) { printk("input_devindex=%d\n", dev->ifindex); } */ return NF_ACCEPT; /* Hand modified range to generic setup. */ //return nf_nat_setup_info(ct, &newrange, hooknum); }