TCP serial number adjustment extension function of contrack

Time:2019-11-8

When the TCP load length of the message changes (remember that the emphasis here is on the length of the TCP load), it will affect the sending sequence number of the sending direction (who sent the modified message, then the sending discovery here refers to that direction) and the response sequence number of the response direction message. The more common function is alg, and the syn agent function requires serial number adjustment. After the serial number of TCP changes, the sack options related to the serial number also need to be adjusted.

Seqadj extension

The connection tracking uses the seqadj extension function to realize serial number adjustment. A serial number adjustment control block NF ﹣ conn ﹣ seqadj is added to the connection tracking

/**
 * struct nf_ct_seqadj - sequence number adjustment information
 *Correction_pos: position of the last TCP sequence number modification
 *@ offset before: sequence number offset before last modification
 *After: sequence number offset after last modification
 */
struct nf_ct_seqadj {
    U32 correction ﹣ POS; / * original serial number of the message whose TCP load length was last modified*/
    S32 offset_before; / * cumulative TCP load length of the last modified message*/
    S32 offset_after; / * cumulative length after the last modification of TCP message*/
};

struct nf_conn_seqadj {
    struct nf_ct_seqadj    seq[IP_CT_DIR_MAX];
};

Use the following figure to explain the meaning of the member NF ABCD CT ABCD seqadj:
TCP serial number adjustment extension function of contrack
1. When the connection trace is created, if the helper extension function exists or synproxy is started, the seqadj extension control block will be added for CT. When the helper adds the seqadj extension, it initializes the member to 0. Assuming that the sequence number of the first syn message is 5000, the content of its seqadj extended control block is shown as the value on the left of the figure above, that is, all are 0 (the figure above only shows one direction, and the other direction is similar).

2. When the TCP load length changes for the first time, the serial number of the message is 10000. Assuming that the TCP load of the message increases by 10 bytes, the nf_ct_seqadj control block will be set:

correction_pos=10000
offset_before=0
offset_after=10

3. When the TCP load length changes for the second time, the serial number of the message is 20000. Assuming that the TCP load length of this message becomes shorter by 5 bytes, the nf_ct_seqadj control block will be set:

correction_pos=20000
offset_before=10
offset_after=5

Initialize seqadj control block

When constructing NAT information with the NF NAT setup info function, if the connection trace informationChanges, and CT has help, a seqadj control block will be added for the CT

/*Modify the NAT quintuple according to the provided NAT type and scope*/
unsigned int
nf_nat_setup_info(struct nf_conn *ct,
          const struct nf_nat_range *range,
          enum nf_nat_manip_type maniptype)
{
    ...
        
    nf_ct_invert_tuplepr(&curr_tuple,
                 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
    /*Get the five tuples of request direction after NAT according to the five tuples of request direction*/
    get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
    /*If the five tuples in the new request direction are different from the original one, the five tuples in the response direction need to be changed*/
    if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
        struct nf_conntrack_tuple reply;

        /* Alter conntrack table so will recognize replies. */
        /*Get a new quintuple of response direction from the new quintuple*/
        nf_ct_invert_tuplepr(&reply, &new_tuple);
        /*Replace five tuples of response direction*/
        nf_conntrack_alter_reply(ct, &reply);

        /* Non-atomic: we own this at the moment. */
        if (maniptype == NF_NAT_MANIP_SRC)
            ct->status |= IPS_SRC_NAT;
        else
            ct->status |= IPS_DST_NAT;
        /*Determine whether help exists in the connection, if so, you must add the SEQ adj extension function*/
        if (nfct_help(ct) && !nfct_seqadj(ct))
            if (!nfct_seqadj_ext_add(ct))
                return NF_DROP;
    }
    ...
        
    return NF_ACCEPT;
}
static inline struct nf_conn_seqadj *nfct_seqadj_ext_add(struct nf_conn *ct)
{
    return nf_ct_ext_add(ct, NF_CT_EXT_SEQADJ, GFP_ATOMIC);
}

void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
{
    unsigned int newlen, newoff, oldlen, alloc;
    struct nf_ct_ext *old, *new;
    struct nf_ct_ext_type *t;

    /* Conntrack must not be confirmed to avoid races on reallocation. */
    WARN_ON(nf_ct_is_confirmed(ct));

    old = ct->ext;

    if (old) {
        if (__nf_ct_ext_exist(old, id))
            return NULL;
        oldlen = old->len;
    } else {
        oldlen = sizeof(*new);
    }

    rcu_read_lock();
    t = rcu_dereference(nf_ct_ext_types[id]);
    if (!t) {
        rcu_read_unlock();
        return NULL;
    }

    newoff = ALIGN(oldlen, t->align);
    newlen = newoff + t->len;
    rcu_read_unlock();

    alloc = max(newlen, NF_CT_EXT_PREALLOC);
    kmemleak_not_leak(old);
    new = __krealloc(old, alloc, gfp);
    if (!new)
        return NULL;

    if (!old) {
        memset(new->offset, 0, sizeof(new->offset));
        ct->ext = new;
    } else if (new != old) {
        kfree_rcu(old, rcu);
        rcu_assign_pointer(ct->ext, new);
    }

    new->offset[id] = newoff;
    new->len = newlen;
    //Initialize to 0
    memset((void *)new + newoff, 0, newlen - newoff);
    return (void *)new + newoff;
}

TCP load length changes

Transmission in FTPPORTOrder orWhen PASV answersALG processing will be performed, and if NAT is enabled, it will be modifiedPORTOrder orPASV’s responseThe contents of TCP load change.

/* Generic function for mangling variable-length address changes inside
 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
 * command in FTP).
 *
 * Takes care about all the nasty sequence number changes, checksumming,
 * skb enlargement, ...
 *
 * */
bool __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
                struct nf_conn *ct,
                enum ip_conntrack_info ctinfo,
                unsigned int protoff,
                unsigned int match_offset,
                unsigned int match_len,
                const char *rep_buffer,
                unsigned int rep_len, bool adjust)
{
    const struct nf_nat_l3proto *l3proto;
    struct tcphdr *tcph;
    int oldlen, datalen;

    if (!skb_make_writable(skb, skb->len))
        return false;

    if (rep_len > match_len &&
        rep_len - match_len > skb_tailroom(skb) &&
        !enlarge_skb(skb, rep_len - match_len))
        return false;

    SKB_LINEAR_ASSERT(skb);

    tcph = (void *)skb->data + protoff;

    oldlen = skb->len - protoff;
    /*To modify the message content, FTP modifies the parameters of the port / PASV command, so you need to input the starting address match [offset] and the length match [len] of the parameters
     *And the starting address and length of the new parameters*/
    mangle_contents(skb, protoff + tcph->doff*4,
            match_offset, match_len, rep_buffer, rep_len);

    datalen = skb->len - protoff;
    /*Recalculate check code*/
    l3proto = __nf_nat_l3proto_find(nf_ct_l3num(ct));
    l3proto->csum_recalc(skb, IPPROTO_TCP, tcph, &tcph->check,
                 datalen, oldlen);
    /*If the length changes, you need to adjust the serial number. Match [len] is the length of the original port command content, and rep [len] is the modified length*/
    /*Remember that the serial number of the TCP header has not been changed here, so tcph - > SEQ is still the original value*/
    if (adjust && rep_len != match_len)
        nf_ct_seqadj_set(ct, ctinfo, tcph->seq,
                 (int) rep len - (int) match len); // change the length, change the length to positive, change the length to negative

    return true;
}

int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
             __be32 seq, s32 off)
{
    Struct nf_conn_seqadj * seqadj = NF ct_seqadj (CT); / * get serial number adjustment control block*/
    enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
    struct nf_ct_seqadj *this_way;

    if (off == 0)
        return 0;

    if (unlikely(!seqadj)) {
        WARN_ONCE(1, "Missing nfct_seqadj_ext_add() setup call\n");
        return 0;
    }

    set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);

    spin_lock_bh(&ct->lock);
    This way = & seqadj - > SEQ [dir]; / * obtain the serial number information of this direction. At the beginning, all three are 0*/
    If (this way - > offset before = = this way - > offset after // it will be equal only when it is initialized, indicating that the TCP load length changes for the first time
        Before (this way - > correction (POS, tohl (SEQ)) {/ * the new serial number is greater than the last adjustment, and subsequent adjustment*/
        This way - > correction ﹣ POS = ntohl (SEQ); / * set the original serial number of the message whose TCP load has changed this time*/
        This way - > offset before = this way - > offset after; / * overwrite the last modified value of serial number length change*/
        This way - > offset after + = off; / * update the change length of accumulated serial number after this modification*/
    }
    spin_unlock_bh(&ct->lock);
    return 0;
}

Adjusting the serial number in the confirm function

The priority of confirm is NF ﹣ IP ﹣ pri ﹣ contrack ﹣ confirm, the lowest priority, that is, the last function executed.

static unsigned int ipv4_confirm(void *priv,
                 struct sk_buff *skb,
                 const struct nf_hook_state *state)
{
    struct nf_conn *ct;
    enum ip_conntrack_info ctinfo;

    ct = nf_ct_get(skb, &ctinfo);
    if (!ct || ctinfo == IP_CT_RELATED_REPLY)
        goto out;

    /* adjust seqs for loopback traffic only in outgoing direction */
    //Adjust the serial number. Why only adjust the outgoing direction? I didn't understand.
    if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
        !nf_is_loopback_packet(skb)) {
        if (!nf_ct_seq_adjust(skb, ct, ctinfo, ip_hdrlen(skb))) {
            NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
            return NF_DROP;
        }
    }
out:
    /* We've seen it coming out the other side: confirm it */
    return nf_conntrack_confirm(skb);
}

/* TCP sequence number adjustment.  Returns 1 on success, 0 on failure */
int nf_ct_seq_adjust(struct sk_buff *skb,
             struct nf_conn *ct, enum ip_conntrack_info ctinfo,
             unsigned int protoff)
{
    enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
    struct tcphdr *tcph;
    __be32 newseq, newack;
    s32 seqoff, ackoff;
    struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);
    struct nf_ct_seqadj *this_way, *other_way;
    int res = 1;

    this_way  = &seqadj->seq[dir];
    other_way = &seqadj->seq[!dir];

    if (!skb_make_writable(skb, protoff + sizeof(*tcph)))
        return 0;

    tcph = (void *)skb->data + protoff;
    spin_lock_bh(&ct->lock);
    //This judgment is very critical. There are 7 cases in total. See the following detailed analysis
    //After is used here, and there is no equal sign, that is to say, tcph - > SEQ = = this way - > correction Fu POS
    //Use seqoff = this way - > offset before, which is practical.
    If (after (toph (tcph - > SEQ), this way - > correction (POS)) / * the new message serial number is after the latest modification, so use after, otherwise use before*/
        seqoff = this_way->offset_after;
    else
        seqoff = this_way->offset_before;

    Newseq = htonl (tohl (tcph - > SEQ) + seqoff); / * the new serial number is equal to the original serial number plus the offset*/
    /*Correction of TCP check code*/
    inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, false);
    pr_debug("Adjusting sequence number from %u->%u\n",
         ntohl(tcph->seq), ntohl(newseq));
    tcph->seq = newseq;

    If (! Tcph - > ACK) / * if the answer flag is not set, exit directly*/
        goto out;
    /*Adjust the confirmation serial number to match the offset of the sending serial number in the opposite direction,
     *Judge whether the message is the message before the last modification or the message after.
     *Other way - > correction POS records the original serial number of the message whose transmission direction has changed. Tcph - > ack_qis the receiver's modification serial number
     *For the response of the subsequent message, subtracting other way - > offset before here is the response sequence number of the original transmission sequence number message.
     */
    if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
          other_way->correction_pos))
        ackoff = other_way->offset_after;
    else
        ackoff = other_way->offset_before;

    newack = htonl(ntohl(tcph->ack_seq) - ackoff);
    inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack,
                 false);
    pr_debug("Adjusting ack number from %u->%u, ack from %u->%u\n",
         ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
         ntohl(newack));
    tcph->ack_seq = newack;
    //Adjust the sack option.
    res = nf_ct_sack_adjust(skb, protoff, tcph, ct, ctinfo);
out:
    spin_unlock_bh(&ct->lock);

    return res;
}

Situation 1:
TCP serial number adjustment extension function of contrack

At present, there is no change of TCP load length,after(ntohl(tcph->seq), this_way->correction_pos)If it is true, seqoff = this way – > offset after; that is, if it is 0, tcph – > SEQ will not be actually modified.

Situation 2:

TCP serial number adjustment extension function of contrack

At present, there has been a change of TCP load length,after(ntohl(tcph->seq), this_way->correction_pos)If it is true, seqoff = this way – > offset after; if it is 10, modify tcph – > SEQ = tcph – > SEQ + 10.

Situation 3:

TCP serial number adjustment extension function of contrack

At present, there has been a change in TCP load length, but the current message’s serial number is 6000, which is less than this way – > correction fupos. This is caused by the message getting lost,after(ntohl(tcph->seq), this_way->correction_pos)If it is false, seqoff = this way – > offset before; that is, if it is 0, tcph – > SEQ will not be actually modified.

Situation 4:

TCP serial number adjustment extension function of contrack

There have been two changes of TCP load length,after(ntohl(tcph->seq), this_way->correction_pos)If it is true, seqoff = this way – > offset after; that is, if it is 5, modify tcph – > SEQ = tcph – > SEQ + 5.

Situation 5:

TCP serial number adjustment extension function of contrack

At present, there have been two changes of TCP load length, but the current message serial number is 16000, which is less than this way – > correction_pos. This is caused by the message getting lost,after(ntohl(tcph->seq), this_way->correction_pos)If it is false, seqoff = this way – > offset before; that is to say, if it is 10, tcph – > SEQ = tcph – > SEQ + 10 will be actually modified.

Situation 6:

TCP serial number adjustment extension function of contrack

At present, there have been two changes of TCP load length, but the current message serial number is 6000, which is less than this way – > correction ﹐ POS. This is caused by the message getting lost,after(ntohl(tcph->seq), this_way->correction_pos)If it is false, seqoff = this way – > offset before; that is to say, if it is 10, tcph – > SEQ = tcph – > SEQ + 10 will be actually modified.This modification is wrong because the message with serial number 6000 does not need to modify the serial number.That is to say, Netfilter can’t correctly handle the lost packets before two changes of TCP load length.

Adjustment of response serial number

The answer sequence number represents the next byte sequence number that the receiver expects to receive. It is equal to the sending serial number of the message received by the receiver plus the length of the message. The receiver can also merge the replies, that is, the reply message does not necessarily correspond to the received message In addition, when receiving the reply serial number, the sender only pays attention to the serial number that is larger than the current one.

Under normal circumstances, one-to-one response message

Situation 1:

TCP serial number adjustment extension function of contrack

At present, there is no change of TCP load length in the sending direction. Tcph – > SEQ = 6000 received by the receiver, assuming the message length is 100, then the response sequence number is tcph – > ack Ou SEQ = 6100.after(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If true, seqoff = this way – > offset after is 0, tcph – > ack > SEQ will not be modified.

Situation 2:

TCP serial number adjustment extension function of contrack

At present, there has been a change of TCP load length in the sending direction, tcph – > SEQ = 10000 received by the receiver, assuming that the message length is 100. Suppose that this response message is a message with the serial number of 10000. Because the length side is 10 long, the response serial number is tcph – > ack_seq = 10110. Tcph – > ACK - other - way – > offset - before = 10110-0 = 10110 is greater than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is true, seqoff = this way – > offset after is 10, modify tcph – > ack = tcph – > ack-10 = 10100. This value is consistent with the normal expected response sequence number of the sender. There is no problem.

Situation 3:

TCP serial number adjustment extension function of contrack

At present, there has been a change of TCP load length in the sending direction. Tcph – > SEQ = 16010 received by the receiver (Netfilter adds 10 bytes to it), assuming that the message length is 100. Suppose that this reply message is a message with the serial number of 16000, and the reply serial number is tcph – > ack_seq = 16110. Tcph – > ACK ﹣ SEQ other ﹣ way – > offset ﹣ before = 16110-0 = 16110 is greater than other ﹣ way – > correction ﹣ POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is true, seqoff = this way – > offset after is 10, modify tcph – > ack = tcph – > ack-10 = 16100. This value is consistent with the normal expected response sequence number of the sender. There is no problem.

Situation 4:

TCP serial number adjustment extension function of contrack

At present, there have been two changes of TCP load length in the sending direction. Suppose the response sequence number is 20000 and the message length is 100. Then the received message’s serial number is 20010 (add 10 bytes to Netfilter). Since the length of this message is reduced by 5 bytes in Netfilter, the actual received message’s length is 95 bytes, and the response serial number is tcph – > ack_seq = 20105. Tcph – > ACK - other - way – > offset - before = 20105 - 5 = 20100 is greater than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is true, seqoff = this way – > offset after is 5, modify tcph – > ack = tcph – > ack-5 = 26105-5 = 26100. This value is consistent with the normal expected response sequence number of the sender. There is no problem.

Situation 5:

TCP serial number adjustment extension function of contrack

At present, TCP load length has changed twice in the sending direction. Tcph – > SEQ = 26005 received by the receiver (Netfilter adds 5 bytes of serial number), assuming that the message length is 100. Suppose that this response message is a message with the serial number of 26000, and the serial number of response is tcph – > ACK Φ SEQ = 26105. Tcph – > ack – other way – > offset before = 26105 – 10 = 26095 is greater than other way – > correction POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is true, seqoff = this way – > offset after is 5, modify tcph – > ack = tcph – > ack-5 = 26105-5 = 26100. This value is consistent with the normal expected response sequence number of the sender. There is no problem.

In the first five cases, Netfilter will not cause the reply sequence number to exceed the last byte + 1 sent by the sender. This is in line with our expectations. There is no previous description of the merging response, which actually meets the requirements.

Under normal circumstances, non one-to-one response, with delay compared with transmission

Situation 1:

TCP serial number adjustment extension function of contrack

The current transmission direction has undergone a change in the TCP load length, and the sender’s situation is shown in the figure above. At this time, the maximum response sequence number of the responder is 6000. Suppose the next 1000 bytes of this response. Then the response sequence number tcph – > ack_seq = 7000. Tcph – > ACK - other - way – > offset - before = 7000 - 0 = 7000 is smaller than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is false, seqoff = this way – > offset before is 0, modifying tcph – > ACK ﹣ SEQ will not change, no problem.

Situation 2:

TCP serial number adjustment extension function of contrack

The current transmission direction has undergone a change in the TCP load length, and the sender’s situation is shown in the figure above. At this time, the maximum response sequence number of the responder is 6000. Suppose the serial number sent by the sender has reached 15000. The next 5000 bytes of this response. Then the response sequence number tcph – > ack_seq = 11000. The response sequence number already contains the response to the 10000 sequence number message with length change. Because the message adds 10 bytes in Netfilter, the actual response should be 10 bytes smaller than the serial number, that is, the real response serial number to the sender is 11000-10 = 10090. Tcph – > ACK - other - way – > offset - before = 11000 - 0 = 11000 is greater than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is true, seqoff = this way – > offset after is 10, modify tcph – > ACK - SEQ = tcph – > ACK - seq-10 = 10090, which is consistent with the expectation, no problem.

Situation 3:

TCP serial number adjustment extension function of contrack

The current transmission direction has undergone two TCP load length changes, and the sender’s situation is shown in the figure above. At this time, the maximum response sequence number of the responder is 6000. Suppose the serial number sent by the sender has reached 25000. The next 2000 bytes of this response. Then the response sequence number tcph – > ack_seq = 8000. The response sequence number does not include the response to the 10000 sequence number message with length change, so the actual response should be the same as the sequence number, that is, the real response sequence number to the sender is 8000. Tcph – > ACK - other - way – > offset - before = 8000 - 5 = 7095 is smaller than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it is false, seqoff = this way – > offset before is 10, modify tcph – > ack = tcph – > ack-10 = 7095, which is inconsistent with the expectation, and there is some problem,Some response problems of message occurred

Situation 4:

TCP serial number adjustment extension function of contrack

The current transmission direction has undergone two TCP load length changes, and the sender’s situation is shown in the figure above. At this time, the maximum response sequence number of the responder is 6000. Suppose the serial number sent by the sender has reached 25000. The next 5000 bytes of this response. Then the response sequence number tcph – > ack_seq = 11000. The response sequence number already contains the response to the 10000 sequence number message with length change. Because the message adds 10 bytes in Netfilter, the actual response should be 10 bytes smaller than the serial number, that is, the real response serial number to the sent response is 11000-10 = 10090. Tcph – > ACK - other - way – > offset - before = 11000 - 0 = 11000 is smaller than other - way – > correction - POS. thereforeafter(ntohl(tcph->ack_seq) – other_way->offset_before,other_way->correction_pos)If it’s false, seqoff = this way – > offset before is 10, modify tcph – > ACK - SEQ = tcph – > ACK - seq-10 = 10090, which is consistent with the expectation, no problem.

Lost response message

Labyrinth response message is similar to delay response, except that when the sender receives the response message, the corresponding byte has been answered, which belongs to repeated response.

Serial number adjustment of sack option

Introduction to sack options:

Kind = 4 is the selective acknowledgement (sack) option.
In TCP communication, if a certain TCP message segment is lost, the TCP module will retransmit all subsequent segments of the last confirmed TCP message segment, so that the TCP message segment that has been transmitted correctly may also be sent repeatedly, thus reducing the TCP performance. Sack technology is to improve this situation. It makes the TCP module only resend the lost TCP segments, and not send all the unconfirmed TCP segments. When the selective confirmation option is used for connection initialization, it indicates whether sack technology is supported. We can modify it
/The proc / sys / net / IPv4 / TCP ﹐ sack kernel variable enables or disables the selective acknowledgment option.

Kind = 5 is the option that sack actually works. The parameter of this option tells the sender the discontinuous data block that has been received and cached by the sender, so that the sender can check and resend the lost data block accordingly. Each edge of block parameter contains a 4-byte ordinal number. The left edge of the block represents the sequence number of the first data of the discontinuous block, while the right edge of the block represents the next sequence number of the last data of the discontinuous block. The data between such a pair of parameters (left and right sides of the block) is not received. Because a block of information occupies 8 bytes, the TCP header option can actually contain up to 4 such discontinuous data blocks (considering the 2 bytes occupied by option type and length).

Analysis on the implementation of sack serial number adjustment:

/* TCP SACK sequence number adjustment */
/*TCP also needs to adjust sack options*/
static unsigned int nf_ct_sack_adjust(struct sk_buff *skb,
                      unsigned int protoff,
                      struct tcphdr *tcph,
                      struct nf_conn *ct,
                      enum ip_conntrack_info ctinfo)
{
    unsigned int dir, optoff, optend;
    struct nf_conn_seqadj *seqadj = nfct_seqadj(ct);

    optoff = protoff + sizeof(struct tcphdr);
    optend = protoff + tcph->doff * 4;

    if (!skb_make_writable(skb, optend))
        return 0;

    dir = CTINFO2DIR(ctinfo);

    while (optoff < optend) {
        /* Usually: option, length. */
        unsigned char *op = skb->data + optoff;

        switch (op[0]) {
        case TCPOPT_EOL:
            return 1;
        case TCPOPT_NOP:
            optoff++;
            continue;
        default:
            /* no partial options */
            If (optoff + 1 = = optend | // no data
                Optoff + OP [1] > optend // length exception
                OP [1] < 2) // length exception
                return 0;
            If (OP [0] = = tcpop_sack & & // sack option
                OP [1] >.
                ((OP [1] - 2)% tcpole ﹐ sack ﹐ perlock) = = 0) // the length minus 2 must be an integral multiple of tcpole ﹐ sack ﹐ perlock.
                nf_ct_sack_block_adjust(skb, tcph, optoff + 2,
                            optoff+op[1],
                            &Seqadj - > SEQ [! Dir]); / * sack deals with the response sequence number, so it is the sequence number control block in the opposite direction*/
            optoff += op[1];
        }
    }
    return 1;
}

Sack serial number adjustment is similar to response serial number adjustment:

/* Adjust one found SACK option including checksum correction */
static void nf_ct_sack_block_adjust(struct sk_buff *skb,
                    struct tcphdr *tcph,
                    unsigned int sackoff,
                    unsigned int sackend,
                    struct nf_ct_seqadj *seq)
{
    while (sackoff < sackend) {
        struct tcp_sack_block_wire *sack;
        __be32 new_start_seq, new_end_seq;

        Sack = (void *) SKB - > data + sackoff; // get sack block
        /*Start serial number*/
        if (after(ntohl(sack->start_seq) - seq->offset_before,
              seq->correction_pos))
            new_start_seq = htonl(ntohl(sack->start_seq) -
                    seq->offset_after);
        else
            new_start_seq = htonl(ntohl(sack->start_seq) -
                    seq->offset_before);

        //End serial number
        if (after(ntohl(sack->end_seq) - seq->offset_before,
              seq->correction_pos))
            new_end_seq = htonl(ntohl(sack->end_seq) -
                      seq->offset_after);
        else
            new_end_seq = htonl(ntohl(sack->end_seq) -
                      seq->offset_before);

        pr_debug("sack_adjust: start_seq: %u->%u, end_seq: %u->%u\n",
             ntohl(sack->start_seq), ntohl(new_start_seq),
             ntohl(sack->end_seq), ntohl(new_end_seq));
        /*Incremental checksum*/
        inet_proto_csum_replace4(&tcph->check, skb,
                     sack->start_seq, new_start_seq, false);
        inet_proto_csum_replace4(&tcph->check, skb,
                     sack->end_seq, new_end_seq, false);
        / * modification * /
        sack->start_seq = new_start_seq;
        sack->end_seq = new_end_seq;
        Sackoff + = sizeof (* sack); / * move to next sack option*/
    }
}

Recommended Today

The use of progressbarcontrol, a progress bar control of devexpress – Taking ZedGraph as an example to add curve progress

scene WinForm control – devexpress18 download installation registration and use in vs: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/100061243 When using ZedGraph to add curves, the number of curves is slower if there are many cases. So in the process of adding curve, the progress needs to be displayed, and the effect is as follows     Note: Blog home page:https://blog.csdn.net/badao_liumang_qizhi […]