static int restore_tcp_queues(int sk, TcpStreamEntry *tse, int fd) { u32 len; if (restore_prepare_socket(sk)) return -1; len = tse->inq_len; if (len && send_tcp_queue(sk, TCP_RECV_QUEUE, len, fd)) return -1; /* * All data in a write buffer can be divided on two parts sent * but not yet acknowledged data and unsent data. * The TCP stack must know which data have been sent, because * acknowledgment can be received for them. These data must be * restored in repair mode. */ len = tse->outq_len - tse->unsq_len; if (len && send_tcp_queue(sk, TCP_SEND_QUEUE, len, fd)) return -1; /* * The second part of data have never been sent to outside, so * they can be restored without any tricks. */ len = tse->unsq_len; tcp_repair_off(sk); if (len && __send_tcp_queue(sk, TCP_SEND_QUEUE, len, fd)) return -1; if (tcp_repair_on(sk)) return -1; return 0; }
static void rst_tcp_repair_off(struct rst_tcp_sock *rts) { int aux, ret; aux = rts->reuseaddr; pr_debug("pie: Turning repair off for %d (reuse %d)\n", rts->sk, aux); tcp_repair_off(rts->sk); ret = sys_setsockopt(rts->sk, SOL_SOCKET, SO_REUSEADDR, &aux, sizeof(aux)); if (ret < 0) pr_perror("Failed to restore of SO_REUSEADDR on socket (%d)", ret); }
static void tcp_unlock_one(struct inet_sk_desc *sk) { int ret; list_del(&sk->rlist); if (!(root_ns_mask & CLONE_NEWNET)) { ret = nf_unlock_connection(sk); if (ret < 0) pr_perror("Failed to unlock TCP connection"); } tcp_repair_off(sk->rfd); /* * tcp_repair_off modifies SO_REUSEADDR so * don't forget to restore original value. */ restore_opt(sk->rfd, SOL_SOCKET, SO_REUSEADDR, &sk->cpt_reuseaddr); close(sk->rfd); }
static int libsoccr_set_sk_data_noq(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size) { struct tcp_repair_opt opts[4]; int addr_size, mstate; int onr = 0; __u32 seq; if (!data || data_size < SOCR_DATA_MIN_SIZE) { loge("Invalid input parameters\n"); return -1; } if (!sk->dst_addr || !sk->src_addr) { loge("Destination or/and source addresses aren't set\n"); return -1; } mstate = 1 << data->state; if (data->state == TCP_LISTEN) { loge("Unable to handle listen sockets\n"); return -1; } if (sk->src_addr->sa.sa_family == AF_INET) addr_size = sizeof(sk->src_addr->v4); else addr_size = sizeof(sk->src_addr->v6); if (bind(sk->fd, &sk->src_addr->sa, addr_size)) { logerr("Can't bind inet socket back"); return -1; } if (mstate & (RCVQ_FIRST_FIN | RCVQ_SECOND_FIN)) data->inq_seq--; /* outq_seq is adjusted due to not accointing the fin packet */ if (mstate & (SNDQ_FIRST_FIN | SNDQ_SECOND_FIN)) data->outq_seq--; if (set_queue_seq(sk, TCP_RECV_QUEUE, data->inq_seq - data->inq_len)) return -2; seq = data->outq_seq - data->outq_len; if (data->state == TCP_SYN_SENT) seq--; if (set_queue_seq(sk, TCP_SEND_QUEUE, seq)) return -3; if (sk->dst_addr->sa.sa_family == AF_INET) addr_size = sizeof(sk->dst_addr->v4); else addr_size = sizeof(sk->dst_addr->v6); if (data->state == TCP_SYN_SENT && tcp_repair_off(sk->fd)) return -1; if (connect(sk->fd, &sk->dst_addr->sa, addr_size) == -1 && errno != EINPROGRESS) { loge("Can't connect inet socket back\n"); return -1; } if (data->state == TCP_SYN_SENT && tcp_repair_on(sk->fd)) return -1; logd("\tRestoring TCP options\n"); if (data->opt_mask & TCPI_OPT_SACK) { logd("\t\tWill turn SAK on\n"); opts[onr].opt_code = TCPOPT_SACK_PERM; opts[onr].opt_val = 0; onr++; } if (data->opt_mask & TCPI_OPT_WSCALE) { logd("\t\tWill set snd_wscale to %u\n", data->snd_wscale); logd("\t\tWill set rcv_wscale to %u\n", data->rcv_wscale); opts[onr].opt_code = TCPOPT_WINDOW; opts[onr].opt_val = data->snd_wscale + (data->rcv_wscale << 16); onr++; } if (data->opt_mask & TCPI_OPT_TIMESTAMPS) { logd("\t\tWill turn timestamps on\n"); opts[onr].opt_code = TCPOPT_TIMESTAMP; opts[onr].opt_val = 0; onr++; } logd("Will set mss clamp to %u\n", data->mss_clamp); opts[onr].opt_code = TCPOPT_MAXSEG; opts[onr].opt_val = data->mss_clamp; onr++; if (data->state != TCP_SYN_SENT && setsockopt(sk->fd, SOL_TCP, TCP_REPAIR_OPTIONS, opts, onr * sizeof(struct tcp_repair_opt)) < 0) { logerr("Can't repair options"); return -2; } if (data->opt_mask & TCPI_OPT_TIMESTAMPS) { if (setsockopt(sk->fd, SOL_TCP, TCP_TIMESTAMP, &data->timestamp, sizeof(data->timestamp)) < 0) { logerr("Can't set timestamp"); return -3; } } return 0; }
void libsoccr_resume(struct libsoccr_sk *sk) { tcp_repair_off(sk->fd); libsoccr_release(sk); }