int restore_socket_opts(int sk, SkOptsEntry *soe) { int ret = 0, val; struct timeval tv; /* In kernel a bufsize value is doubled. */ u32 bufs[2] = { soe->so_sndbuf / 2, soe->so_rcvbuf / 2}; pr_info("%d restore sndbuf %d rcv buf %d\n", sk, soe->so_sndbuf, soe->so_rcvbuf); /* setsockopt() multiplies the input values by 2 */ ret |= userns_call(sk_setbufs, UNS_ASYNC, bufs, sizeof(bufs), sk); if (soe->has_so_priority) { pr_debug("\trestore priority %d for socket\n", soe->so_priority); ret |= restore_opt(sk, SOL_SOCKET, SO_PRIORITY, &soe->so_priority); } if (soe->has_so_rcvlowat) { pr_debug("\trestore rcvlowat %d for socket\n", soe->so_rcvlowat); ret |= restore_opt(sk, SOL_SOCKET, SO_RCVLOWAT, &soe->so_rcvlowat); } if (soe->has_so_mark) { pr_debug("\trestore mark %d for socket\n", soe->so_mark); ret |= restore_opt(sk, SOL_SOCKET, SO_MARK, &soe->so_mark); } if (soe->has_so_passcred && soe->so_passcred) { val = 1; pr_debug("\tset passcred for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_PASSCRED, &val); } if (soe->has_so_passsec && soe->so_passsec) { val = 1; pr_debug("\tset passsec for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_PASSSEC, &val); } if (soe->has_so_dontroute && soe->so_dontroute) { val = 1; pr_debug("\tset dontroute for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_DONTROUTE, &val); } if (soe->has_so_no_check && soe->so_no_check) { val = 1; pr_debug("\tset no_check for socket\n"); ret |= restore_opt(sk, SOL_SOCKET, SO_NO_CHECK, &val); } tv.tv_sec = soe->so_snd_tmo_sec; tv.tv_usec = soe->so_snd_tmo_usec; ret |= restore_opt(sk, SOL_SOCKET, SO_SNDTIMEO, &tv); tv.tv_sec = soe->so_rcv_tmo_sec; tv.tv_usec = soe->so_rcv_tmo_usec; ret |= restore_opt(sk, SOL_SOCKET, SO_RCVTIMEO, &tv); ret |= restore_bound_dev(sk, soe); ret |= restore_socket_filter(sk, soe); /* The restore of SO_REUSEADDR depends on type of socket */ return ret; }
static int sk_setbufs(void *arg, int fd, pid_t pid) { u32 *buf = (u32 *)arg; if (restore_opt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &buf[0])) return -1; if (restore_opt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &buf[1])) return -1; return 0; }
static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii) { int ifd, aux; TcpStreamEntry *tse; pr_info("Restoring TCP connection id %x ino %x\n", ii->ie->id, ii->ie->ino); ifd = open_image(CR_FD_TCP_STREAM, O_RSTR, ii->ie->ino); if (ifd < 0) goto err; if (pb_read_one(ifd, &tse, PB_TCP_STREAM) < 0) goto err_c; if (restore_tcp_seqs(sk, tse)) goto err_c; if (inet_bind(sk, ii)) goto err_c; if (inet_connect(sk, ii)) goto err_c; if (restore_tcp_opts(sk, tse)) goto err_c; if (restore_tcp_queues(sk, tse, ifd)) goto err_c; if (tse->has_nodelay && tse->nodelay) { aux = 1; if (restore_opt(sk, SOL_TCP, TCP_NODELAY, &aux)) goto err_c; } if (tse->has_cork && tse->cork) { aux = 1; if (restore_opt(sk, SOL_TCP, TCP_CORK, &aux)) goto err_c; } tcp_stream_entry__free_unpacked(tse, NULL); close(ifd); return 0; err_c: tcp_stream_entry__free_unpacked(tse, NULL); close(ifd); err: return -1; }
static int restore_mreqs(int sk, PacketSockEntry *pse) { int i; for (i = 0; i < pse->n_mclist; i++) { PacketMclist *ml; struct packet_mreq_max mreq; ml = pse->mclist[i]; pr_info("Restoring mreq type %d\n", ml->type); if (ml->addr.len > sizeof(mreq.mr_address)) { pr_err("To big mcaddr %zu\n", ml->addr.len); return -1; } mreq.mr_ifindex = ml->index; mreq.mr_type = ml->type; mreq.mr_alen = ml->addr.len; memcpy(mreq.mr_address, ml->addr.data, ml->addr.len); if (restore_opt(sk, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq)) return -1; } return 0; }
static int restore_ring(int sk, int type, PacketRing *ring) { struct tpacket_req3 req; if (!ring) return 0; pr_debug("\tRestoring %d ring\n", type); req.tp_block_size = ring->block_size; req.tp_block_nr = ring->block_nr; req.tp_frame_size = ring->frame_size; req.tp_frame_nr = ring->frame_nr; req.tp_retire_blk_tov = ring->retire_tmo; req.tp_sizeof_priv = ring->sizeof_priv; req.tp_feature_req_word = ring->features; return restore_opt(sk, SOL_PACKET, type, &req); }
static int restore_socket_filter(int sk, SkOptsEntry *soe) { int ret; struct sock_fprog sfp; if (!soe->n_so_filter) return 0; pr_info("Restoring socket filter\n"); sfp.len = soe->n_so_filter; sfp.filter = xmalloc(soe->n_so_filter * sfp.len); if (!sfp.filter) return -1; decode_filter(soe->so_filter, sfp.filter, sfp.len); ret = restore_opt(sk, SOL_SOCKET, SO_ATTACH_FILTER, &sfp); xfree(sfp.filter); return 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 open_packet_sk(struct file_desc *d) { struct packet_sock_info *psi; PacketSockEntry *pse; struct sockaddr_ll addr; int sk, yes; psi = container_of(d, struct packet_sock_info, d); pse = psi->pse; pr_info("Opening packet socket id %#x\n", pse->id); sk = socket(PF_PACKET, pse->type, pse->protocol); if (sk < 0) { pr_perror("Can't create packet sock"); goto err; } memset(&addr, 0, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_ifindex = pse->ifindex; if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) { pr_perror("Can't bind packet socket"); goto err_cl; } if (restore_opt(sk, SOL_PACKET, PACKET_VERSION, &pse->version)) goto err_cl; if (restore_opt(sk, SOL_PACKET, PACKET_RESERVE, &pse->reserve)) goto err_cl; if (restore_opt(sk, SOL_PACKET, PACKET_TIMESTAMP, &pse->timestamp)) goto err_cl; if (restore_opt(sk, SOL_PACKET, PACKET_COPY_THRESH, &pse->copy_thresh)) goto err_cl; if (pse->aux_data) { yes = 1; if (restore_opt(sk, SOL_PACKET, PACKET_AUXDATA, &yes)) goto err_cl; } if (pse->orig_dev) { yes = 1; if (restore_opt(sk, SOL_PACKET, PACKET_ORIGDEV, &yes)) goto err_cl; } if (pse->vnet_hdr) { yes = 1; if (restore_opt(sk, SOL_PACKET, PACKET_VNET_HDR, &yes)) goto err_cl; } if (pse->loss) { yes = 1; if (restore_opt(sk, SOL_PACKET, PACKET_LOSS, &yes)) goto err_cl; } if (restore_mreqs(sk, pse)) goto err_cl; if (restore_rings(sk, pse)) goto err_cl; if (pse->has_fanout) { pr_info("Restoring fanout %x\n", pse->fanout); if (restore_opt(sk, SOL_PACKET, PACKET_FANOUT, &pse->fanout)) goto err_cl; } if (rst_file_params(sk, pse->fown, pse->flags)) goto err_cl; if (restore_socket_opts(sk, pse->opts)) goto err_cl; return sk; err_cl: close(sk); err: return -1; }