mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 09:58:09 +00:00
inet: raw -- Add checkpoint and restore of raw sockets
Just like with other inet sockets simply fetch additional data (such as ICMP) and restore it back then. Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> Signed-off-by: Andrei Vagin <avagin@gmail.com>
This commit is contained in:
parent
072778c4ac
commit
c2cbcaf8ac
120
criu/sk-inet.c
120
criu/sk-inet.c
@ -11,6 +11,8 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
|
||||
#include "../soccr/soccr.h"
|
||||
|
||||
@ -112,10 +114,8 @@ static void show_one_inet_img(const char *act, const InetSkEntry *e)
|
||||
static int can_dump_ipproto(int ino, int proto, int type)
|
||||
{
|
||||
/* Raw sockets may have any protocol inside */
|
||||
if (type == SOCK_RAW) {
|
||||
pr_err("Unsupported raw socket %x\n", ino);
|
||||
return 0;
|
||||
}
|
||||
if (type == SOCK_RAW)
|
||||
return 1;
|
||||
|
||||
/* Make sure it's a proto we support */
|
||||
switch (proto) {
|
||||
@ -307,12 +307,76 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int dump_ip_opts(int sk, IpOptsEntry *ioe)
|
||||
static int ip_raw_opts_alloc(int family, int proto, IpOptsRawEntry *r)
|
||||
{
|
||||
if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
|
||||
if (family == AF_INET6)
|
||||
r->n_icmpv_filter = NELEMS_AS_ARRAY(struct icmp6_filter,
|
||||
r->icmpv_filter);
|
||||
else
|
||||
r->n_icmpv_filter = NELEMS_AS_ARRAY(struct icmp_filter,
|
||||
r->icmpv_filter);
|
||||
r->icmpv_filter = xmalloc(pb_repeated_size(r, icmpv_filter));
|
||||
pr_debug("r->n_icmpv_filter %d size %d\n",
|
||||
(int)r->n_icmpv_filter,
|
||||
(int)pb_repeated_size(r, icmpv_filter));
|
||||
if (!r->icmpv_filter)
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ip_raw_opts_free(IpOptsRawEntry *r)
|
||||
{
|
||||
r->n_icmpv_filter = 0;
|
||||
xfree(r->icmpv_filter);
|
||||
}
|
||||
|
||||
static int dump_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = ip_raw_opts_alloc(family, proto, r);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (family == AF_INET6) {
|
||||
ret |= dump_opt(sk, SOL_IPV6, IPV6_HDRINCL, &r->hdrincl);
|
||||
|
||||
if (proto == IPPROTO_ICMPV6)
|
||||
ret |= do_dump_opt(sk, SOL_ICMPV6, ICMPV6_FILTER,
|
||||
r->icmpv_filter,
|
||||
pb_repeated_size(r, icmpv_filter));
|
||||
} else {
|
||||
ret |= dump_opt(sk, SOL_IP, IP_HDRINCL, &r->hdrincl);
|
||||
ret |= dump_opt(sk, SOL_IP, IP_NODEFRAG, &r->nodefrag);
|
||||
r->has_nodefrag = !!r->nodefrag;
|
||||
|
||||
if (proto == IPPROTO_ICMP)
|
||||
ret |= do_dump_opt(sk, SOL_RAW, ICMP_FILTER,
|
||||
r->icmpv_filter,
|
||||
pb_repeated_size(r, icmpv_filter));
|
||||
}
|
||||
r->has_hdrincl = !!r->hdrincl;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dump_ip_opts(int sk, int family, int type, int proto, IpOptsEntry *ioe)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (type == SOCK_RAW) {
|
||||
/*
|
||||
* Raw sockets might need allocate more space
|
||||
* and fetch additional options.
|
||||
*/
|
||||
ret |= dump_ip_raw_opts(sk, family, proto, ioe->raw);
|
||||
} else {
|
||||
/* Due to kernel code we can use SOL_IP instead of SOL_IPV6 */
|
||||
ret |= dump_opt(sk, SOL_IP, IP_FREEBIND, &ioe->freebind);
|
||||
ioe->has_freebind = ioe->freebind;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -342,6 +406,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
FileEntry fe = FILE_ENTRY__INIT;
|
||||
InetSkEntry ie = INET_SK_ENTRY__INIT;
|
||||
IpOptsEntry ipopts = IP_OPTS_ENTRY__INIT;
|
||||
IpOptsRawEntry ipopts_raw = IP_OPTS_RAW_ENTRY__INIT;
|
||||
SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
|
||||
int ret = -1, err = -1, proto, aux, type;
|
||||
|
||||
@ -356,6 +421,9 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
if (!can_dump_ipproto(p->stat.st_ino, proto, type))
|
||||
goto err;
|
||||
|
||||
if (type == SOCK_RAW)
|
||||
sk = (struct inet_sk_desc *)lookup_socket_ino(p->stat.st_ino, family);
|
||||
else
|
||||
sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino, family, proto);
|
||||
if (IS_ERR(sk))
|
||||
goto err;
|
||||
@ -366,6 +434,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
}
|
||||
|
||||
sk->cork = false;
|
||||
if (type != SOCK_RAW) {
|
||||
switch (proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
@ -382,6 +451,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!can_dump_inet_sk(sk))
|
||||
goto err;
|
||||
@ -405,6 +475,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
ie.fown = (FownEntry *)&p->fown;
|
||||
ie.opts = &skopts;
|
||||
ie.ip_opts = &ipopts;
|
||||
ie.ip_opts->raw = &ipopts_raw;
|
||||
|
||||
ie.n_src_addr = PB_ALEN_INET;
|
||||
ie.n_dst_addr = PB_ALEN_INET;
|
||||
@ -451,7 +522,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
memcpy(ie.src_addr, sk->src_addr, pb_repeated_size(&ie, src_addr));
|
||||
memcpy(ie.dst_addr, sk->dst_addr, pb_repeated_size(&ie, dst_addr));
|
||||
|
||||
if (dump_ip_opts(lfd, &ipopts))
|
||||
if (dump_ip_opts(lfd, family, type, proto, &ipopts))
|
||||
goto err;
|
||||
|
||||
if (dump_socket_opts(lfd, &skopts))
|
||||
@ -465,7 +536,7 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
err = dump_one_tcp(lfd, sk);
|
||||
err = (type != SOCK_RAW) ? dump_one_tcp(lfd, sk) : 0;
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
@ -482,9 +553,14 @@ static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int fa
|
||||
fe.id = ie.id;
|
||||
fe.isk = &ie;
|
||||
|
||||
/* Unchain not need field back */
|
||||
if (type != SOCK_RAW)
|
||||
ie.ip_opts->raw = NULL;
|
||||
|
||||
if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE))
|
||||
goto err;
|
||||
err:
|
||||
ip_raw_opts_free(&ipopts_raw);
|
||||
release_skopts(&skopts);
|
||||
xfree(ie.src_addr);
|
||||
xfree(ie.dst_addr);
|
||||
@ -654,13 +730,37 @@ static int post_open_inet_sk(struct file_desc *d, int sk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int restore_ip_opts(int sk, IpOptsEntry *ioe)
|
||||
static int restore_ip_raw_opts(int sk, int family, int proto, IpOptsRawEntry *r)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (r->icmpv_filter) {
|
||||
if (proto == IPPROTO_ICMP || proto == IPPROTO_ICMPV6) {
|
||||
ret |= do_restore_opt(sk, family == AF_INET6 ? SOL_ICMPV6 : SOL_RAW,
|
||||
family == AF_INET6 ? ICMPV6_FILTER : ICMP_FILTER,
|
||||
r->icmpv_filter, pb_repeated_size(r, icmpv_filter));
|
||||
}
|
||||
}
|
||||
|
||||
if (r->has_nodefrag)
|
||||
ret |= restore_opt(sk, SOL_IP, IP_NODEFRAG, &r->nodefrag);
|
||||
if (r->has_hdrincl)
|
||||
ret |= restore_opt(sk, family == AF_INET6 ? SOL_IPV6 : SOL_IP,
|
||||
family == AF_INET6 ? IPV6_HDRINCL : IP_HDRINCL,
|
||||
&r->hdrincl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int restore_ip_opts(int sk, int family, int proto, IpOptsEntry *ioe)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (ioe->has_freebind)
|
||||
ret |= restore_opt(sk, SOL_IP, IP_FREEBIND, &ioe->freebind);
|
||||
|
||||
if (ioe->raw)
|
||||
ret |= restore_ip_raw_opts(sk, family, proto, ioe->raw);
|
||||
return ret;
|
||||
}
|
||||
static int open_inet_sk(struct file_desc *d, int *new_fd)
|
||||
@ -683,7 +783,7 @@ static int open_inet_sk(struct file_desc *d, int *new_fd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM)) {
|
||||
if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM) && (ie->type != SOCK_RAW)) {
|
||||
pr_err("Unsupported socket type: %d\n", ie->type);
|
||||
return -1;
|
||||
}
|
||||
@ -763,7 +863,7 @@ done:
|
||||
if (rst_file_params(sk, ie->fown, ie->flags))
|
||||
goto err;
|
||||
|
||||
if (ie->ip_opts && restore_ip_opts(sk, ie->ip_opts))
|
||||
if (ie->ip_opts && restore_ip_opts(sk, ie->family, ie->proto, ie->ip_opts))
|
||||
goto err;
|
||||
|
||||
if (restore_socket_opts(sk, ie->opts))
|
||||
|
@ -4,11 +4,16 @@ import "opts.proto";
|
||||
import "fown.proto";
|
||||
import "sk-opts.proto";
|
||||
|
||||
message ip_opts_raw_entry {
|
||||
optional bool hdrincl = 1;
|
||||
optional bool nodefrag = 2;
|
||||
optional bool checksum = 3;
|
||||
repeated uint32 icmpv_filter = 4;
|
||||
}
|
||||
|
||||
message ip_opts_entry {
|
||||
optional bool freebind = 1;
|
||||
// For raw sockets support
|
||||
// optional bool hdrincl = 2;
|
||||
// optional bool nodefrag = 3;
|
||||
optional ip_opts_raw_entry raw = 2;
|
||||
}
|
||||
|
||||
message inet_sk_entry {
|
||||
|
Loading…
x
Reference in New Issue
Block a user