Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set linux kernel not to send RST_ACK, so that I can give SYN_ACK within raw socket

I want to ask a classic question about raw socket programming and linux kernel TCP handling. I've done the research to some same threads like linux raw socket programming question, How to reproduce TCP protocol 3-way handshake with raw sockets correctly?, and TCP ACK spoofing, but still can't get the solution.

I try to make a server which don't listen to any port, but sniff SYN packets from remote hosts. After the server do some calculation, it will send back a SYN_ACK packet to corresponding SYN packet, so that I can create TCP Connection manually, without including kernel's operation. I've create raw socket and send the SYN_ACK over it, but the packet cannot get through to the remote host. When I tcpdump on the server (Ubuntu Server 10.04) and wireshark on client (windows 7), the server returns RST_ACK instead of my SYN_ACK packet. After doing some research, I got information that we cannot preempt kernel's TCP handling.

Is there still any other ways to hack or set the kernel not to responds RST_ACK to those packets? I've added a firewall to local ip of server to tell the kernel that maybe there's something behind the firewall which is waiting for the packet, but still no luck

like image 432
Xzorax Avatar asked Nov 08 '11 08:11

Xzorax


2 Answers

Did you try to drop RST using iptables?

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

should do the job for you.

like image 86
Jekyll Avatar answered Nov 03 '22 08:11

Jekyll


I recommend using ip tables, but since you ask about hacking the kernel as well, here is an explanation of how you could do that (I'm using kernel 4.1.20 as reference):

When a packet is received (a sk_buff), the IP protocol handler will send it to the networking protocol registered:

static int ip_local_deliver_finish(struct sock *sk, struct sk_buff *skb)
{
        ...
        ipprot = rcu_dereference(inet_protos[protocol]);
        if (ipprot) {
           ...
           ret = ipprot->handler(skb);

Assuming the protocol is TCP, the handler is tcp_v4_rcv:

static const struct net_protocol tcp_protocol = {
    .early_demux    =   tcp_v4_early_demux,
    .handler    =  tcp_v4_rcv,
    .err_handler    =   tcp_v4_err,
    .no_policy  =   1,
    .netns_ok   =   1,
    .icmp_strict_tag_validation = 1,
};

So tcp_v4_cv is called. It will try to find the socket for the skb received, and if it doesn't, it will send reset:

int tcp_v4_rcv(struct sk_buff *skb)
{
    sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest);
    if (!sk)
        goto no_tcp_socket;

no_tcp_socket:
    if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
        goto discard_it;

    tcp_v4_send_reset(NULL, skb);
    ...

There are many different ways you can hack this. You could go to the xfrm4_policy_check function and hack/change the policy for AF_INET. Or you can just simply comment out the line that calls xfrm4_policy_check, so that the code will always go to discard_it, or you can just comment out the line that calls tcp_v4_send_reset (which will have more consequences, though).

Hope this helps.

like image 37
Jay Medina Avatar answered Nov 03 '22 09:11

Jay Medina