diff --git a/crtools.c b/crtools.c index a5a8eaa03..cf9851d60 100644 --- a/crtools.c +++ b/crtools.c @@ -22,6 +22,8 @@ #include "syscall.h" #include "uts_ns.h" #include "ipc_ns.h" +#include "files.h" +#include "sk-inet.h" struct cr_options opts; @@ -347,6 +349,7 @@ int main(int argc, char *argv[]) { "namespaces", required_argument, 0, 'n' }, { "ext-unix-sk", no_argument, 0, 'x' }, { "help", no_argument, 0, 'h' }, + { SK_EST_PARAM, no_argument, 0, 42 }, { }, }; @@ -410,6 +413,10 @@ int main(int argc, char *argv[]) log_level++; } break; + case 42: + pr_info("Will dump TCP connections\n"); + opts.tcp_established_ok = true; + break; case 'h': default: goto usage; diff --git a/include/crtools.h b/include/crtools.h index 6625448eb..5ae6791b2 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -66,6 +66,7 @@ struct cr_options { bool show_pages_content; bool restore_detach; bool ext_unix_sk; + bool tcp_established_ok; unsigned int namespaces_flags; }; diff --git a/include/sk-inet.h b/include/sk-inet.h index 7d65c7944..bfcd74dd9 100644 --- a/include/sk-inet.h +++ b/include/sk-inet.h @@ -23,4 +23,16 @@ struct inet_sk_info { int inet_bind(int sk, struct inet_sk_info *); int inet_connect(int sk, struct inet_sk_info *); + +static inline int dump_one_tcp(int sk, struct inet_sk_desc *sd) +{ + return -1; +} + +static inline int restore_one_tcp(int sk, struct inet_sk_info *si) +{ + return -1; +} + +#define SK_EST_PARAM "tcp-established" #endif diff --git a/include/sockets.h b/include/sockets.h index 3b809a5d8..ebd4c3a1e 100644 --- a/include/sockets.h +++ b/include/sockets.h @@ -39,7 +39,7 @@ struct socket_desc { struct socket_desc *lookup_socket(int ino); int sk_collect_one(int ino, int family, struct socket_desc *d); int dump_one_inet(struct socket_desc *_sk, struct fd_parms *p, - const struct cr_fdset *cr_fdset); + int lfd, const struct cr_fdset *cr_fdset); int dump_one_unix(const struct socket_desc *_sk, struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset); struct nlmsghdr; diff --git a/sk-inet.c b/sk-inet.c index 75ee145b8..9d2f61d83 100644 --- a/sk-inet.c +++ b/sk-inet.c @@ -72,6 +72,13 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) return 0; } break; + case TCP_ESTABLISHED: + if (!opts.tcp_established_ok) { + pr_err("Connected TCP socket, consider using %s option.\n", + SK_EST_PARAM); + return 0; + } + break; default: pr_err("Unknown state %d\n", sk->state); return 0; @@ -80,8 +87,11 @@ static int can_dump_inet_sk(const struct inet_sk_desc *sk) return 1; } +#define tcp_connection(sk) (((sk)->proto == IPPROTO_TCP) && \ + ((sk)->state == TCP_ESTABLISHED)) + int dump_one_inet(struct socket_desc *_sk, struct fd_parms *p, - const struct cr_fdset *cr_fdset) + int lfd, const struct cr_fdset *cr_fdset) { struct inet_sk_desc *sk = (struct inet_sk_desc *)_sk; struct inet_sk_entry ie; @@ -123,6 +133,10 @@ int dump_one_inet(struct socket_desc *_sk, struct fd_parms *p, show_one_inet("Dumping", sk); show_one_inet_img("Dumped", &ie); sk->sd.already_dumped = 1; + + if (tcp_connection(sk)) + return dump_one_tcp(lfd, sk); + return 0; err: @@ -221,6 +235,18 @@ static int open_inet_sk(struct file_desc *d) return -1; } + if (tcp_connection(&ii->ie)) { + if (!opts.tcp_established_ok) { + pr_err("Connected TCP socket in image\n"); + goto err; + } + + if (restore_one_tcp(sk, ii)) + goto err; + + goto done; + } + /* * Listen sockets are easiest ones -- simply * bind() and listen(), and that's all. @@ -244,7 +270,7 @@ static int open_inet_sk(struct file_desc *d) if (ii->ie.state == TCP_ESTABLISHED && inet_connect(sk, ii)) goto err; - +done: if (rst_file_params(sk, &ii->ie.fown, ii->ie.flags)) goto err; diff --git a/sockets.c b/sockets.c index 0a3258e47..2e6e88e65 100644 --- a/sockets.c +++ b/sockets.c @@ -81,7 +81,7 @@ int dump_socket(struct fd_parms *p, int lfd, const struct cr_fdset *cr_fdset) return dump_one_unix(sk, p, lfd, cr_fdset); case AF_INET: case AF_INET6: - return dump_one_inet(sk, p, cr_fdset); + return dump_one_inet(sk, p, lfd, cr_fdset); default: pr_err("BUG! Unknown socket collected\n"); break; @@ -220,8 +220,8 @@ int collect_sockets(void) req.r.i.sdiag_family = AF_INET; req.r.i.sdiag_protocol = IPPROTO_TCP; req.r.i.idiag_ext = 0; - /* Only listening sockets supported yet */ - req.r.i.idiag_states = 1 << TCP_LISTEN; + /* Only listening and established sockets supported yet */ + req.r.i.idiag_states = (1 << TCP_LISTEN) | (1 << TCP_ESTABLISHED); tmp = collect_sockets_nl(nl, &req, sizeof(req), inet_tcp_receive_one); if (tmp) err = tmp;