2012-07-01 14:42:42 +04:00
|
|
|
#include <sys/types.h>
|
2012-04-26 14:30:42 +04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <arpa/inet.h>
|
2012-05-29 20:11:00 +04:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2012-04-26 14:30:42 +04:00
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
#include "libnetlink.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "inet_diag.h"
|
|
|
|
#include "files.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "sockets.h"
|
2012-04-28 16:42:50 +04:00
|
|
|
#include "sk-inet.h"
|
2012-04-26 14:30:42 +04:00
|
|
|
|
|
|
|
static void show_one_inet(const char *act, const struct inet_sk_desc *sk)
|
|
|
|
{
|
|
|
|
char src_addr[INET_ADDR_LEN] = "<unknown>";
|
|
|
|
|
|
|
|
if (inet_ntop(sk->sd.family, (void *)sk->src_addr, src_addr,
|
|
|
|
INET_ADDR_LEN) == NULL) {
|
|
|
|
pr_perror("Failed to translate address");
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("\t%s: ino 0x%8x family %4d type %4d port %8d "
|
|
|
|
"state %2d src_addr %s\n",
|
|
|
|
act, sk->sd.ino, sk->sd.family, sk->type, sk->src_port,
|
|
|
|
sk->state, src_addr);
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
static void show_one_inet_img(const char *act, const InetSkEntry *e)
|
2012-04-26 14:30:42 +04:00
|
|
|
{
|
|
|
|
char src_addr[INET_ADDR_LEN] = "<unknown>";
|
|
|
|
|
|
|
|
if (inet_ntop(e->family, (void *)e->src_addr, src_addr,
|
|
|
|
INET_ADDR_LEN) == NULL) {
|
|
|
|
pr_perror("Failed to translate address");
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("\t%s: family %d type %d proto %d port %d "
|
|
|
|
"state %d src_addr %s\n",
|
|
|
|
act, e->family, e->type, e->proto, e->src_port,
|
|
|
|
e->state, src_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int can_dump_inet_sk(const struct inet_sk_desc *sk)
|
|
|
|
{
|
|
|
|
if (sk->sd.family != AF_INET && sk->sd.family != AF_INET6) {
|
|
|
|
pr_err("Only IPv4/6 sockets for now\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sk->type == SOCK_DGRAM)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (sk->type != SOCK_STREAM) {
|
|
|
|
pr_err("Only stream and dgram inet sockets for now\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (sk->state) {
|
|
|
|
case TCP_LISTEN:
|
|
|
|
if (sk->rqlen != 0) {
|
|
|
|
/*
|
|
|
|
* Currently the ICONS nla reports the conn
|
|
|
|
* requests for listen sockets. Need to pick
|
|
|
|
* those up and fix the connect job respectively
|
|
|
|
*/
|
|
|
|
pr_err("In-flight connection (l)\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2012-04-28 17:15:12 +04:00
|
|
|
case TCP_ESTABLISHED:
|
|
|
|
if (!opts.tcp_established_ok) {
|
|
|
|
pr_err("Connected TCP socket, consider using %s option.\n",
|
|
|
|
SK_EST_PARAM);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2012-07-01 14:42:42 +04:00
|
|
|
case TCP_CLOSE:
|
|
|
|
/* Trivial case, we just need to create a socket on restore */
|
|
|
|
break;
|
2012-04-26 14:30:42 +04:00
|
|
|
default:
|
|
|
|
pr_err("Unknown state %d\n", sk->state);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-01 14:42:42 +04:00
|
|
|
/* Make sure it's a proto we support */
|
|
|
|
switch (sk->proto) {
|
|
|
|
case IPPROTO_IP:
|
|
|
|
case IPPROTO_TCP:
|
|
|
|
case IPPROTO_UDP:
|
|
|
|
case IPPROTO_UDPLITE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pr_err("Unsupported socket proto %d\n", sk->proto);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-04-28 17:15:12 +04:00
|
|
|
#define tcp_connection(sk) (((sk)->proto == IPPROTO_TCP) && \
|
|
|
|
((sk)->state == TCP_ESTABLISHED))
|
|
|
|
|
2012-07-01 14:42:42 +04:00
|
|
|
static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p)
|
|
|
|
{
|
|
|
|
struct inet_sk_desc *sk;
|
|
|
|
char address[128];
|
|
|
|
socklen_t aux;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
sk = xzalloc(sizeof(*sk));
|
|
|
|
if (!sk)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
/* It should has no peer name */
|
|
|
|
aux = sizeof(address);
|
|
|
|
ret = getsockopt(lfd, SOL_SOCKET, SO_PEERNAME, address, &aux);
|
|
|
|
if (ret != -1 || errno != ENOTCONN) {
|
|
|
|
pr_err("Errno %d returned from unconnected socket\n", errno);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk->sd.ino = p->stat.st_ino;
|
|
|
|
|
|
|
|
ret = do_dump_opt(lfd, SO_DOMAIN, &sk->sd.family, sizeof(sk->sd.family));
|
|
|
|
ret |= do_dump_opt(lfd, SO_TYPE, &sk->type, sizeof(sk->type));
|
|
|
|
ret |= do_dump_opt(lfd, SO_PROTOCOL, &sk->proto, sizeof(sk->proto));
|
|
|
|
if (ret)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (sk->proto == IPPROTO_TCP) {
|
|
|
|
struct tcp_info info;
|
|
|
|
|
|
|
|
aux = sizeof(info);
|
|
|
|
ret = getsockopt(lfd, SOL_TCP, TCP_INFO, &info, &aux);
|
|
|
|
if (ret) {
|
|
|
|
pr_perror("Failt to obtain TCP_INFO");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.tcpi_state != TCP_CLOSE) {
|
|
|
|
pr_err("Socket state %d obtained but expected %d\n",
|
|
|
|
info.tcpi_state, TCP_CLOSE);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk->wqlen = info.tcpi_backoff;
|
|
|
|
}
|
|
|
|
|
|
|
|
sk->state = TCP_CLOSE;
|
|
|
|
|
|
|
|
sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd);
|
|
|
|
|
|
|
|
return sk;
|
|
|
|
err:
|
|
|
|
xfree(sk);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
static int dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p)
|
2012-04-26 14:30:42 +04:00
|
|
|
{
|
2012-05-25 13:09:00 +04:00
|
|
|
struct inet_sk_desc *sk;
|
2012-07-19 09:26:47 +04:00
|
|
|
InetSkEntry ie = INET_SK_ENTRY__INIT;
|
|
|
|
SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
|
|
|
|
FownEntry fown;
|
|
|
|
int ret = -1;
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino);
|
2012-07-01 14:42:42 +04:00
|
|
|
if (!sk) {
|
|
|
|
sk = gen_uncon_sk(lfd, p);
|
|
|
|
if (!sk)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
if (!can_dump_inet_sk(sk))
|
2012-04-26 14:30:42 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
BUG_ON(sk->sd.already_dumped);
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
pb_prep_fown(&fown, &p->fown);
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
ie.id = id;
|
|
|
|
ie.ino = sk->sd.ino;
|
2012-04-26 14:30:42 +04:00
|
|
|
ie.family = sk->sd.family;
|
|
|
|
ie.type = sk->type;
|
|
|
|
ie.proto = sk->proto;
|
|
|
|
ie.state = sk->state;
|
|
|
|
ie.src_port = sk->src_port;
|
|
|
|
ie.dst_port = sk->dst_port;
|
|
|
|
ie.backlog = sk->wqlen;
|
|
|
|
ie.flags = p->flags;
|
2012-07-19 09:26:47 +04:00
|
|
|
|
|
|
|
ie.fown = &fown;
|
|
|
|
ie.opts = &skopts;
|
|
|
|
|
|
|
|
ie.n_src_addr = 4;
|
|
|
|
ie.n_dst_addr = 4;
|
|
|
|
|
|
|
|
ie.src_addr = xmalloc(pb_repeated_size(&ie, src_addr));
|
|
|
|
ie.dst_addr = xmalloc(pb_repeated_size(&ie, dst_addr));
|
|
|
|
|
|
|
|
if (!ie.src_addr || !ie.dst_addr)
|
|
|
|
goto err;
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
memcpy(ie.src_addr, sk->src_addr, sizeof(u32) * 4);
|
|
|
|
memcpy(ie.dst_addr, sk->dst_addr, sizeof(u32) * 4);
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
if (pb_dump_socket_opts(lfd, &skopts))
|
2012-05-05 03:11:56 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
if (pb_write(fdset_fd(glob_fdset, CR_FD_INETSK), &ie, inet_sk_entry))
|
2012-04-26 14:30:42 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
pr_info("Dumping inet socket at %d\n", p->fd);
|
|
|
|
show_one_inet("Dumping", sk);
|
|
|
|
show_one_inet_img("Dumped", &ie);
|
|
|
|
sk->sd.already_dumped = 1;
|
2012-04-28 17:15:12 +04:00
|
|
|
|
|
|
|
if (tcp_connection(sk))
|
2012-07-19 09:26:47 +04:00
|
|
|
ret = dump_one_tcp(lfd, sk);
|
|
|
|
else
|
|
|
|
ret = 0;
|
2012-04-26 14:30:42 +04:00
|
|
|
err:
|
2012-07-19 09:26:47 +04:00
|
|
|
xfree(ie.src_addr);
|
|
|
|
xfree(ie.dst_addr);
|
|
|
|
return ret;
|
2012-04-26 14:30:42 +04:00
|
|
|
}
|
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
static const struct fdtype_ops inet_dump_ops = {
|
|
|
|
.type = FDINFO_INETSK,
|
|
|
|
.make_gen_id = make_gen_id,
|
|
|
|
.dump = dump_one_inet_fd,
|
|
|
|
};
|
|
|
|
|
|
|
|
int dump_one_inet(struct fd_parms *p, int lfd, const struct cr_fdset *set)
|
|
|
|
{
|
|
|
|
return do_dump_gen_file(p, lfd, &inet_dump_ops, set);
|
|
|
|
}
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto)
|
|
|
|
{
|
|
|
|
struct inet_sk_desc *d;
|
|
|
|
struct inet_diag_msg *m = NLMSG_DATA(h);
|
|
|
|
struct rtattr *tb[INET_DIAG_MAX+1];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(m + 1),
|
|
|
|
h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
|
|
|
|
|
|
|
|
d = xzalloc(sizeof(*d));
|
|
|
|
if (!d)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
d->type = type;
|
|
|
|
d->proto = proto;
|
|
|
|
d->src_port = ntohs(m->id.idiag_sport);
|
|
|
|
d->dst_port = ntohs(m->id.idiag_dport);
|
|
|
|
d->state = m->idiag_state;
|
|
|
|
d->rqlen = m->idiag_rqueue;
|
|
|
|
d->wqlen = m->idiag_wqueue;
|
|
|
|
memcpy(d->src_addr, m->id.idiag_src, sizeof(u32) * 4);
|
|
|
|
memcpy(d->dst_addr, m->id.idiag_dst, sizeof(u32) * 4);
|
|
|
|
|
|
|
|
ret = sk_collect_one(m->idiag_inode, family, &d->sd);
|
|
|
|
|
|
|
|
show_one_inet("Collected", d);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-01 14:42:42 +04:00
|
|
|
static u32 zero_addr[4];
|
|
|
|
|
|
|
|
static bool is_bound(struct inet_sk_info *ii)
|
|
|
|
{
|
2012-07-19 09:26:47 +04:00
|
|
|
BUG_ON(sizeof(zero_addr) <
|
|
|
|
max(pb_repeated_size(ii->ie, dst_addr),
|
|
|
|
pb_repeated_size(ii->ie, src_addr)));
|
2012-07-01 14:42:42 +04:00
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
return memcmp(zero_addr, ii->ie->src_addr, pb_repeated_size(ii->ie, src_addr)) ||
|
|
|
|
memcmp(zero_addr, ii->ie->dst_addr, pb_repeated_size(ii->ie, dst_addr));
|
2012-07-01 14:42:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
static int open_inet_sk(struct file_desc *d);
|
|
|
|
|
|
|
|
static struct file_desc_ops inet_desc_ops = {
|
2012-05-04 15:41:05 +04:00
|
|
|
.type = FDINFO_INETSK,
|
2012-04-26 14:30:42 +04:00
|
|
|
.open = open_inet_sk,
|
|
|
|
};
|
|
|
|
|
|
|
|
int collect_inet_sockets(void)
|
|
|
|
{
|
|
|
|
struct inet_sk_info *ii = NULL;
|
|
|
|
int fd, ret = -1;
|
|
|
|
|
|
|
|
fd = open_image_ro(CR_FD_INETSK);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
ii = xmalloc(sizeof(*ii));
|
|
|
|
ret = -1;
|
|
|
|
if (!ii)
|
|
|
|
break;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
ret = pb_read_eof(fd, &ii->ie, inet_sk_entry);
|
2012-04-26 14:30:42 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
file_desc_add(&ii->d, ii->ie->id, &inet_desc_ops);
|
2012-04-28 17:38:46 +04:00
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (tcp_connection(ii->ie))
|
2012-04-28 17:38:46 +04:00
|
|
|
tcp_locked_conn_add(ii);
|
2012-04-26 14:30:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ii)
|
|
|
|
xfree(ii);
|
|
|
|
|
|
|
|
close(fd);
|
2012-07-01 06:28:35 +04:00
|
|
|
return ret;
|
2012-04-26 14:30:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int open_inet_sk(struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct inet_sk_info *ii;
|
2012-04-28 16:42:50 +04:00
|
|
|
int sk;
|
2012-04-26 14:30:42 +04:00
|
|
|
|
|
|
|
ii = container_of(d, struct inet_sk_info, d);
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
show_one_inet_img("Restore", ii->ie);
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (ii->ie->family != AF_INET && ii->ie->family != AF_INET6) {
|
|
|
|
pr_err("Unsupported socket family: %d\n", ii->ie->family);
|
2012-04-26 14:30:42 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if ((ii->ie->type != SOCK_STREAM) && (ii->ie->type != SOCK_DGRAM)) {
|
|
|
|
pr_err("Unsupported socket type: %d\n", ii->ie->type);
|
2012-04-26 14:30:42 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
sk = socket(ii->ie->family, ii->ie->type, ii->ie->proto);
|
2012-04-26 14:30:42 +04:00
|
|
|
if (sk < 0) {
|
|
|
|
pr_perror("Can't create unix socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (tcp_connection(ii->ie)) {
|
2012-04-28 17:15:12 +04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
/*
|
|
|
|
* Listen sockets are easiest ones -- simply
|
|
|
|
* bind() and listen(), and that's all.
|
|
|
|
*/
|
|
|
|
|
2012-07-01 14:42:42 +04:00
|
|
|
if (is_bound(ii)) {
|
|
|
|
if (inet_bind(sk, ii))
|
|
|
|
goto err;
|
|
|
|
}
|
2012-04-26 14:30:42 +04:00
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (ii->ie->state == TCP_LISTEN) {
|
|
|
|
if (ii->ie->proto != IPPROTO_TCP) {
|
|
|
|
pr_err("Wrong socket in listen state %d\n", ii->ie->proto);
|
2012-04-26 14:30:42 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (listen(sk, ii->ie->backlog) == -1) {
|
2012-04-26 14:30:42 +04:00
|
|
|
pr_perror("Can't listen on a socket");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
if (ii->ie->state == TCP_ESTABLISHED &&
|
2012-04-28 16:42:50 +04:00
|
|
|
inet_connect(sk, ii))
|
|
|
|
goto err;
|
2012-04-28 17:15:12 +04:00
|
|
|
done:
|
2012-07-19 09:26:47 +04:00
|
|
|
if (pb_rst_file_params(sk, ii->ie->fown, ii->ie->flags))
|
2012-04-26 14:30:42 +04:00
|
|
|
goto err;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
if (pb_restore_socket_opts(sk, ii->ie->opts))
|
2012-05-05 02:11:14 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
return sk;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close(sk);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-04-28 16:42:50 +04:00
|
|
|
int inet_bind(int sk, struct inet_sk_info *ii)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
struct sockaddr_in v4;
|
|
|
|
struct sockaddr_in6 v6;
|
|
|
|
} addr;
|
|
|
|
int addr_size;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
|
2012-04-28 16:42:50 +04:00
|
|
|
memzero(&addr, sizeof(addr));
|
2012-07-13 21:05:00 +04:00
|
|
|
if (ii->ie->family == AF_INET) {
|
2012-07-19 09:26:47 +04:00
|
|
|
BUG_ON(pb_repeated_size(ii->ie, src_addr) < sizeof(addr.v4.sin_addr.s_addr));
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
addr.v4.sin_family = ii->ie->family;
|
|
|
|
addr.v4.sin_port = htons(ii->ie->src_port);
|
2012-07-19 09:26:47 +04:00
|
|
|
memcpy(&addr.v4.sin_addr.s_addr, ii->ie->src_addr, sizeof(addr.v4.sin_addr.s_addr));
|
2012-04-28 16:42:50 +04:00
|
|
|
addr_size = sizeof(addr.v4);
|
2012-07-13 21:05:00 +04:00
|
|
|
} else if (ii->ie->family == AF_INET6) {
|
2012-07-19 09:26:47 +04:00
|
|
|
BUG_ON(pb_repeated_size(ii->ie, src_addr) < sizeof(addr.v6.sin6_addr.s6_addr));
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
addr.v6.sin6_family = ii->ie->family;
|
|
|
|
addr.v6.sin6_port = htons(ii->ie->src_port);
|
2012-07-19 09:26:47 +04:00
|
|
|
memcpy(&addr.v6.sin6_addr.s6_addr, ii->ie->src_addr, sizeof(addr.v6.sin6_addr.s6_addr));
|
2012-04-28 16:42:50 +04:00
|
|
|
addr_size = sizeof(addr.v6);
|
|
|
|
} else
|
|
|
|
BUG_ON(1);
|
|
|
|
|
|
|
|
if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
|
|
|
|
pr_perror("Can't bind inet socket");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int inet_connect(int sk, struct inet_sk_info *ii)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
struct sockaddr_in v4;
|
|
|
|
struct sockaddr_in6 v6;
|
|
|
|
} addr;
|
|
|
|
int addr_size;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
|
2012-04-28 16:42:50 +04:00
|
|
|
memzero(&addr, sizeof(addr));
|
2012-07-13 21:05:00 +04:00
|
|
|
if (ii->ie->family == AF_INET) {
|
2012-07-19 09:26:47 +04:00
|
|
|
BUG_ON(pb_repeated_size(ii->ie, dst_addr) < sizeof(addr.v4.sin_addr.s_addr));
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
addr.v4.sin_family = ii->ie->family;
|
|
|
|
addr.v4.sin_port = htons(ii->ie->dst_port);
|
2012-07-19 09:26:47 +04:00
|
|
|
memcpy(&addr.v4.sin_addr.s_addr, ii->ie->dst_addr, sizeof(addr.v4.sin_addr.s_addr));
|
2012-04-28 16:42:50 +04:00
|
|
|
addr_size = sizeof(addr.v4);
|
2012-07-13 21:05:00 +04:00
|
|
|
} else if (ii->ie->family == AF_INET6) {
|
2012-07-19 09:26:47 +04:00
|
|
|
BUG_ON(pb_repeated_size(ii->ie, dst_addr) < sizeof(addr.v6.sin6_addr.s6_addr));
|
|
|
|
|
2012-07-13 21:05:00 +04:00
|
|
|
addr.v6.sin6_family = ii->ie->family;
|
|
|
|
addr.v6.sin6_port = htons(ii->ie->dst_port);
|
2012-07-19 09:26:47 +04:00
|
|
|
memcpy(&addr.v6.sin6_addr.s6_addr, ii->ie->dst_addr, sizeof(addr.v6.sin6_addr.s6_addr));
|
2012-04-28 16:42:50 +04:00
|
|
|
addr_size = sizeof(addr.v6);
|
|
|
|
} else
|
|
|
|
BUG_ON(1);
|
|
|
|
|
|
|
|
if (connect(sk, (struct sockaddr *)&addr, addr_size) == -1) {
|
|
|
|
pr_perror("Can't connect inet socket back");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-26 14:30:42 +04:00
|
|
|
void show_inetsk(int fd, struct cr_options *o)
|
|
|
|
{
|
2012-07-19 09:26:47 +04:00
|
|
|
InetSkEntry *ie;
|
2012-04-26 14:30:42 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pr_img_head(CR_FD_INETSK);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
char src_addr[INET_ADDR_LEN] = "<unknown>";
|
|
|
|
char dst_addr[INET_ADDR_LEN] = "<unknown>";
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
ret = pb_read_eof(fd, &ie, inet_sk_entry);
|
2012-04-26 14:30:42 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
goto out;
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
if (inet_ntop(ie->family, (void *)ie->src_addr, src_addr,
|
2012-04-26 14:30:42 +04:00
|
|
|
INET_ADDR_LEN) == NULL) {
|
|
|
|
pr_perror("Failed to translate src address");
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
if (ie->state == TCP_ESTABLISHED) {
|
|
|
|
if (inet_ntop(ie->family, (void *)ie->dst_addr, dst_addr,
|
2012-04-26 14:30:42 +04:00
|
|
|
INET_ADDR_LEN) == NULL) {
|
|
|
|
pr_perror("Failed to translate dst address");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-25 13:09:00 +04:00
|
|
|
pr_msg("id %#x ino %#x family %s type %s proto %s state %s %s:%d <-> %s:%d flags 0x%2x\n",
|
2012-07-19 09:26:47 +04:00
|
|
|
ie->id, ie->ino, skfamily2s(ie->family), sktype2s(ie->type), skproto2s(ie->proto),
|
|
|
|
skstate2s(ie->state), src_addr, ie->src_port, dst_addr, ie->dst_port, ie->flags);
|
|
|
|
pr_msg("\t"), pb_show_fown_cont(ie->fown), pr_msg("\n");
|
|
|
|
pb_show_socket_opts(ie->opts);
|
2012-05-05 02:11:14 +04:00
|
|
|
|
2012-07-19 09:26:47 +04:00
|
|
|
inet_sk_entry__free_unpacked(ie, NULL);
|
2012-04-26 14:30:42 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (ret)
|
|
|
|
pr_info("\n");
|
|
|
|
pr_img_tail(CR_FD_INETSK);
|
|
|
|
}
|
|
|
|
|