Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The modified TCP packet was successfully sent, but the message before the modification was still retransmitted #100

Open
BinaryRyan opened this issue Sep 10, 2024 · 2 comments

Comments

@BinaryRyan
Copy link

What I did?

I tried to add a small piece of my own data to the PSH tcp payload, and it can be seen that the transmission was successful and the server was able to respond to the ACK message. However, the Linux kernel seems to have dropped this reply ACK message and continued to send the message I modified before.

send successfully

send successfully

retransmitted

send successfully

Soure Code

int packet_callback(struct nfq_q_handle* qh, struct nfgenmsg* nfmsg,
                    struct nfq_data* nfa, void* data)
{
    struct nfqnl_msg_packet_hdr* ph;
    unsigned char* raw;
    int nfp_len, status;
    struct pkt_buff* pktbuf;
    struct iphdr* iph;
    struct tcphdr* tcph;
    uint16_t seq;
    unsigned char* payload;
    int plen;
    uint32_t verdict = NF_ACCEPT;
    uint8_t local_out = 0;

    ph = nfq_get_msg_packet_hdr(nfa);
    if (!ph)
    {
        printf("error: cannot get nf message packet hdr\n");
        return NF_ACCEPT;
    }

    nfp_len = nfq_get_payload(nfa, &raw);
    if (nfp_len < 0)
    {
        printf("error: invalid payload length %d\n", nfp_len);
        return NF_ACCEPT;
    }

    pktbuf = pktb_alloc(AF_INET, raw, nfp_len, 0x1000);
    if (!pktbuf)
    {
        printf("error: cannot allocate pkt buff\n");
        return NF_ACCEPT;
    }

    iph = nfq_ip_get_hdr(pktbuf);
    if (iph->protocol != IPPROTO_TCP)
    {
        pktb_free(pktbuf);
        return NF_ACCEPT;
    }

    status = nfq_ip_set_transport_header(pktbuf, iph);
    if (status < 0)
    {
        printf("error: cannot set transport header to pkt buff\n");
        pktb_free(pktbuf);
        return NF_ACCEPT;
    }

    tcph = nfq_tcp_get_hdr(pktbuf);
    if (!tcph)
    {
        printf("error: cannot get tcp hdr\n");
        pktb_free(pktbuf);
        return NF_ACCEPT;
    }

    payload = nfq_tcp_get_payload(tcph, pktbuf);
    plen = nfq_get_payload(nfa, &payload);

    const char* rep = "hello server\n";
    if ((local_out = nfq_get_outdev(nfa)))
    {
        uint32_t tcp_plen = get_tcp_payload_len(iph, tcph);
        if (tcph->ack && tcph->psh && !tcph->fin && !tcph->rst&&!injected)
        {
            printf("injected\n");
            nfq_tcp_mangle_ipv4(pktbuf, 0, 0, rep, strlen(rep));
            injected = true;
        }
    }

    _print_conn_info(iph, tcph);
    nfq_ip_set_checksum(iph);
    return nfq_set_verdict(qh, ntohl(ph->packet_id), verdict, pktb_len(pktbuf),
                           pktb_data(pktbuf));
}
@oremanj
Copy link
Owner

oremanj commented Jan 29, 2025

This is a Python library, so your C code is somewhat out-of-scope, but it appears you are trying to insert data in the middle of a TCP stream rather than overwriting existing data. As the documentation for nfq_tcp_mangle_ipv4 mentions: "After changing the length of a TCP message, the application will need to mangle sequence numbers in both directions until another change puts them in sync again." Remember that the sender doesn't know about the data you added, so when the sender receives an ACK that covers that data, it's anyone's guess what it's going to conclude.

In general, if you want to modify traffic for a reliable protocol like TCP, you'll need much more involved modification logic that can make everything that happens after your modification correctly reflect your modifications. The longer packet implies that later packets' sequence numbers will need to be increased and reply ACKs will need to be decreased, for example. If your modified packet gets retransmitted, you'll need to inject the modification in the transmitted version also. It's much more difficult than doing modifications that don't change the length.

@BinaryRyan
Copy link
Author

If I decrease the sequence number in the response direction, then the entire transmission sequence is incorrect. Is there a way to synchronize the current connection sequence number to the kernel TCP state machine with less invasiveness.It can be observed that when sending out, TCP packets are correct, otherwise the other party would not respond correctly to ACK.thanks for ur advice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants