LCOV - code coverage report
Current view: top level - crtools - sk-inet.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 210 250 84.0 %
Date: 2012-12-28 Functions: 19 20 95.0 %
Branches: 101 170 59.4 %

           Branch data     Line data    Source code
       1                 :            : #include <sys/types.h>
       2                 :            : #include <sys/socket.h>
       3                 :            : #include <linux/netlink.h>
       4                 :            : #include <linux/rtnetlink.h>
       5                 :            : #include <sys/mman.h>
       6                 :            : #include <unistd.h>
       7                 :            : #include <netinet/tcp.h>
       8                 :            : #include <arpa/inet.h>
       9                 :            : #include <string.h>
      10                 :            : #include <stdlib.h>
      11                 :            : 
      12                 :            : #include "types.h"
      13                 :            : #include "libnetlink.h"
      14                 :            : #include "crtools.h"
      15                 :            : #include "inet_diag.h"
      16                 :            : #include "files.h"
      17                 :            : #include "image.h"
      18                 :            : #include "log.h"
      19                 :            : #include "util.h"
      20                 :            : #include "sockets.h"
      21                 :            : #include "sk-inet.h"
      22                 :            : 
      23                 :            : #define PB_ALEN_INET    1
      24                 :            : #define PB_ALEN_INET6   4
      25                 :            : 
      26                 :            : static LIST_HEAD(inet_ports);
      27                 :            : 
      28                 :            : struct inet_port {
      29                 :            :         int port;
      30                 :            :         int type;
      31                 :            :         futex_t users;
      32                 :            :         struct list_head list;
      33                 :            : };
      34                 :            : 
      35                 :         76 : static struct inet_port *port_add(int type, int port)
      36                 :            : {
      37                 :            :         struct inet_port *e;
      38                 :            : 
      39         [ +  + ]:         88 :         list_for_each_entry(e, &inet_ports, list)
      40 [ +  - ][ +  + ]:         28 :                 if (e->type == type && e->port == port) {
      41                 :         16 :                         futex_inc(&e->users);
      42                 :         16 :                         return e;
      43                 :            :                 }
      44                 :            : 
      45                 :         60 :         e = shmalloc(sizeof(*e));
      46         [ -  + ]:         60 :         if (e == NULL) {
      47                 :          0 :                 pr_err("Not enough memory\n");
      48                 :          0 :                 return NULL;
      49                 :            :         }
      50                 :            : 
      51                 :         60 :         e->port = port;
      52                 :         60 :         e->type = type;
      53                 :         60 :         futex_init(&e->users);
      54                 :         60 :         futex_inc(&e->users);
      55                 :            : 
      56                 :         60 :         list_add(&e->list, &inet_ports);
      57                 :            : 
      58                 :         76 :         return e;
      59                 :            : }
      60                 :            : 
      61                 :       2078 : static void show_one_inet(const char *act, const struct inet_sk_desc *sk)
      62                 :            : {
      63                 :       2078 :         char src_addr[INET_ADDR_LEN] = "<unknown>";
      64                 :            : 
      65         [ -  + ]:       2078 :         if (inet_ntop(sk->sd.family, (void *)sk->src_addr, src_addr,
      66                 :            :                       INET_ADDR_LEN) == NULL) {
      67                 :          0 :                 pr_perror("Failed to translate address");
      68                 :            :         }
      69                 :            : 
      70                 :       2078 :         pr_debug("\t%s: ino 0x%8x family %4d type %4d port %8d "
      71                 :            :                 "state %2d src_addr %s\n",
      72                 :            :                 act, sk->sd.ino, sk->sd.family, sk->type, sk->src_port,
      73                 :            :                 sk->state, src_addr);
      74                 :       2078 : }
      75                 :            : 
      76                 :         76 : static void show_one_inet_img(const char *act, const InetSkEntry *e)
      77                 :            : {
      78                 :         76 :         char src_addr[INET_ADDR_LEN] = "<unknown>";
      79                 :            : 
      80         [ -  + ]:         76 :         if (inet_ntop(e->family, (void *)e->src_addr, src_addr,
      81                 :            :                       INET_ADDR_LEN) == NULL) {
      82                 :          0 :                 pr_perror("Failed to translate address");
      83                 :            :         }
      84                 :            : 
      85                 :         76 :         pr_debug("\t%s: family %d type %d proto %d port %d "
      86                 :            :                 "state %d src_addr %s\n",
      87                 :            :                 act, e->family, e->type, e->proto, e->src_port,
      88                 :            :                 e->state, src_addr);
      89                 :         76 : }
      90                 :            : 
      91                 :         38 : static int can_dump_inet_sk(const struct inet_sk_desc *sk)
      92                 :            : {
      93         [ -  + ]:         38 :         if (sk->sd.family != AF_INET && sk->sd.family != AF_INET6) {
      94                 :          0 :                 pr_err("Only IPv4/6 sockets for now\n");
      95                 :          0 :                 return 0;
      96                 :            :         }
      97                 :            : 
      98         [ -  + ]:         38 :         if (sk->shutdown) {
      99                 :          0 :                 pr_err("Can't dump shutdown inet socket\n");
     100                 :          0 :                 return 0;
     101                 :            :         }
     102                 :            : 
     103         [ +  + ]:         38 :         if (sk->type == SOCK_DGRAM) {
     104         [ -  + ]:         14 :                 if (sk->wqlen != 0) {
     105                 :          0 :                         pr_err("Can't dump corked dgram socket\n");
     106                 :          0 :                         return 0;
     107                 :            :                 }
     108                 :            : 
     109         [ -  + ]:         14 :                 if (sk->rqlen)
     110                 :          0 :                         pr_warn("Read queue is dropped for socket %x\n",
     111                 :            :                                         sk->sd.ino);
     112                 :            : 
     113                 :            :                 return 1;
     114                 :            :         }
     115                 :            : 
     116         [ -  + ]:         24 :         if (sk->type != SOCK_STREAM) {
     117                 :          0 :                 pr_err("Only stream and dgram inet sockets for now\n");
     118                 :          0 :                 return 0;
     119                 :            :         }
     120                 :            : 
     121   [ +  +  -  + ]:         24 :         switch (sk->state) {
     122                 :            :         case TCP_LISTEN:
     123         [ -  + ]:         10 :                 if (sk->rqlen != 0) {
     124                 :            :                         /*
     125                 :            :                          * Currently the ICONS nla reports the conn
     126                 :            :                          * requests for listen sockets. Need to pick
     127                 :            :                          * those up and fix the connect job respectively
     128                 :            :                          */
     129                 :          0 :                         pr_err("In-flight connection (l)\n");
     130                 :          0 :                         return 0;
     131                 :            :                 }
     132                 :            :                 break;
     133                 :            :         case TCP_ESTABLISHED:
     134         [ -  + ]:          8 :                 if (!opts.tcp_established_ok) {
     135                 :          0 :                         pr_err("Connected TCP socket, consider using %s option.\n",
     136                 :            :                                         SK_EST_PARAM);
     137                 :          0 :                         return 0;
     138                 :            :                 }
     139                 :            :                 break;
     140                 :            :         case TCP_CLOSE:
     141                 :            :                 /* Trivial case, we just need to create a socket on restore */
     142                 :            :                 break;
     143                 :            :         default:
     144                 :          0 :                 pr_err("Unknown state %d\n", sk->state);
     145                 :          0 :                 return 0;
     146                 :            :         }
     147                 :            : 
     148                 :            :         /* Make sure it's a proto we support */
     149         [ -  + ]:         24 :         switch (sk->proto) {
     150                 :            :         case IPPROTO_IP:
     151                 :            :         case IPPROTO_TCP:
     152                 :            :         case IPPROTO_UDP:
     153                 :            :         case IPPROTO_UDPLITE:
     154                 :            :                 break;
     155                 :            :         default:
     156                 :          0 :                 pr_err("Unsupported socket proto %d\n", sk->proto);
     157                 :         38 :                 return 0;
     158                 :            :         }
     159                 :            : 
     160                 :            :         return 1;
     161                 :            : }
     162                 :            : 
     163                 :          8 : static struct inet_sk_desc *gen_uncon_sk(int lfd, const struct fd_parms *p)
     164                 :            : {
     165                 :            :         struct inet_sk_desc *sk;
     166                 :            :         char address;
     167                 :            :         socklen_t aux;
     168                 :            :         int ret;
     169                 :            : 
     170         [ -  + ]:          8 :         sk = xzalloc(sizeof(*sk));
     171         [ +  - ]:          8 :         if (!sk)
     172                 :            :                 goto err;
     173                 :            : 
     174                 :            :         /* It should has no peer name */
     175                 :          8 :         aux = sizeof(address);
     176                 :          8 :         ret = getsockopt(lfd, SOL_SOCKET, SO_PEERNAME, &address, &aux);
     177         [ +  - ]:          8 :         if (ret < 0) {
     178         [ -  + ]:          8 :                 if (errno != ENOTCONN) {
     179                 :          0 :                         pr_perror("Unexpected error returned from unconnected socket");
     180                 :            :                         goto err;
     181                 :            :                 }
     182         [ #  # ]:          0 :         } else if (ret == 0) {
     183                 :          0 :                 pr_err("Name resolved on unconnected socket\n");
     184                 :            :                 goto err;
     185                 :            :         }
     186                 :            : 
     187                 :          8 :         sk->sd.ino = p->stat.st_ino;
     188                 :            : 
     189                 :          8 :         ret  = do_dump_opt(lfd, SOL_SOCKET, SO_DOMAIN, &sk->sd.family, sizeof(sk->sd.family));
     190                 :          8 :         ret |= do_dump_opt(lfd, SOL_SOCKET, SO_TYPE, &sk->type, sizeof(sk->type));
     191                 :          8 :         ret |= do_dump_opt(lfd, SOL_SOCKET, SO_PROTOCOL, &sk->proto, sizeof(sk->proto));
     192         [ +  - ]:          8 :         if (ret)
     193                 :            :                 goto err;
     194                 :            : 
     195         [ +  + ]:          8 :         if (sk->proto == IPPROTO_TCP) {
     196                 :            :                 struct tcp_info info;
     197                 :            : 
     198                 :          6 :                 aux = sizeof(info);
     199                 :          6 :                 ret = getsockopt(lfd, SOL_TCP, TCP_INFO, &info, &aux);
     200         [ -  + ]:          6 :                 if (ret) {
     201                 :          0 :                         pr_perror("Failt to obtain TCP_INFO");
     202                 :            :                         goto err;
     203                 :            :                 }
     204                 :            : 
     205         [ -  + ]:          6 :                 if (info.tcpi_state != TCP_CLOSE) {
     206                 :          0 :                         pr_err("Socket state %d obtained but expected %d\n",
     207                 :            :                                info.tcpi_state, TCP_CLOSE);
     208                 :            :                         goto err;
     209                 :            :                 }
     210                 :            : 
     211                 :          6 :                 sk->wqlen = info.tcpi_backoff;
     212                 :            :         }
     213                 :            : 
     214                 :          8 :         sk->state = TCP_CLOSE;
     215                 :            : 
     216                 :          8 :         sk_collect_one(sk->sd.ino, sk->sd.family, &sk->sd);
     217                 :            : 
     218                 :            :         return sk;
     219                 :            : err:
     220         [ #  # ]:          8 :         xfree(sk);
     221                 :            :         return NULL;
     222                 :            : }
     223                 :            : 
     224                 :         38 : static int do_dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p, int family)
     225                 :            : {
     226                 :            :         struct inet_sk_desc *sk;
     227                 :         38 :         InetSkEntry ie = INET_SK_ENTRY__INIT;
     228                 :         38 :         SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
     229                 :         38 :         int ret = -1;
     230                 :            : 
     231                 :         38 :         sk = (struct inet_sk_desc *)lookup_socket(p->stat.st_ino, family);
     232         [ +  + ]:         38 :         if (!sk) {
     233                 :          8 :                 sk = gen_uncon_sk(lfd, p);
     234         [ +  - ]:          8 :                 if (!sk)
     235                 :            :                         goto err;
     236                 :            :         }
     237                 :            : 
     238         [ +  - ]:         38 :         if (!can_dump_inet_sk(sk))
     239                 :            :                 goto err;
     240                 :            : 
     241         [ -  + ]:         38 :         BUG_ON(sk->sd.already_dumped);
     242                 :            : 
     243                 :         38 :         ie.id           = id;
     244                 :         38 :         ie.ino          = sk->sd.ino;
     245                 :         38 :         ie.family       = family;
     246                 :         38 :         ie.type         = sk->type;
     247                 :         38 :         ie.proto        = sk->proto;
     248                 :         38 :         ie.state        = sk->state;
     249                 :         38 :         ie.src_port     = sk->src_port;
     250                 :         38 :         ie.dst_port     = sk->dst_port;
     251                 :         38 :         ie.backlog      = sk->wqlen;
     252                 :         38 :         ie.flags        = p->flags;
     253                 :            : 
     254                 :         38 :         ie.fown         = (FownEntry *)&p->fown;
     255                 :         38 :         ie.opts         = &skopts;
     256                 :            : 
     257                 :         38 :         ie.n_src_addr = PB_ALEN_INET;
     258                 :         38 :         ie.n_dst_addr = PB_ALEN_INET;
     259         [ +  + ]:         38 :         if (ie.family == AF_INET6) {
     260                 :            :                 int val;
     261                 :            : 
     262                 :         13 :                 ie.n_src_addr = PB_ALEN_INET6;
     263                 :         13 :                 ie.n_dst_addr = PB_ALEN_INET6;
     264                 :            : 
     265                 :         13 :                 ret = dump_opt(lfd, SOL_IPV6, IPV6_V6ONLY, &val);
     266         [ +  - ]:         13 :                 if (ret < 0)
     267                 :            :                         goto err;
     268                 :            : 
     269                 :         13 :                 ie.v6only = val ? true : false;
     270                 :         13 :                 ie.has_v6only = true;
     271                 :            :         }
     272                 :            : 
     273         [ -  + ]:         38 :         ie.src_addr = xmalloc(pb_repeated_size(&ie, src_addr));
     274         [ -  + ]:         38 :         ie.dst_addr = xmalloc(pb_repeated_size(&ie, dst_addr));
     275                 :            : 
     276 [ +  - ][ +  - ]:         38 :         if (!ie.src_addr || !ie.dst_addr)
     277                 :            :                 goto err;
     278                 :            : 
     279                 :         38 :         memcpy(ie.src_addr, sk->src_addr, pb_repeated_size(&ie, src_addr));
     280                 :         38 :         memcpy(ie.dst_addr, sk->dst_addr, pb_repeated_size(&ie, dst_addr));
     281                 :            : 
     282         [ +  - ]:         38 :         if (dump_socket_opts(lfd, &skopts))
     283                 :            :                 goto err;
     284                 :            : 
     285         [ +  - ]:         38 :         if (pb_write_one(fdset_fd(glob_fdset, CR_FD_INETSK), &ie, PB_INETSK))
     286                 :            :                 goto err;
     287                 :            : 
     288                 :         38 :         pr_info("Dumping inet socket at %d\n", p->fd);
     289                 :         38 :         show_one_inet("Dumping", sk);
     290                 :         38 :         show_one_inet_img("Dumped", &ie);
     291                 :         38 :         sk->sd.already_dumped = 1;
     292                 :            : 
     293         [ +  + ]:         38 :         switch (sk->proto) {
     294                 :            :         case IPPROTO_TCP:
     295                 :         24 :                 ret = dump_one_tcp(lfd, sk);
     296                 :         24 :                 break;
     297                 :            :         default:
     298                 :            :                 ret = 0;
     299                 :            :                 break;
     300                 :            :         }
     301                 :            : err:
     302                 :         38 :         release_skopts(&skopts);
     303         [ +  - ]:         38 :         xfree(ie.src_addr);
     304         [ +  - ]:         38 :         xfree(ie.dst_addr);
     305                 :         38 :         return ret;
     306                 :            : }
     307                 :            : 
     308                 :         25 : static int dump_one_inet_fd(int lfd, u32 id, const struct fd_parms *p)
     309                 :            : {
     310                 :         25 :         return do_dump_one_inet_fd(lfd, id, p, PF_INET);
     311                 :            : }
     312                 :            : 
     313                 :            : static const struct fdtype_ops inet_dump_ops = {
     314                 :            :         .type           = FD_TYPES__INETSK,
     315                 :            :         .dump           = dump_one_inet_fd,
     316                 :            : };
     317                 :            : 
     318                 :         25 : int dump_one_inet(struct fd_parms *p, int lfd, const struct cr_fdset *set)
     319                 :            : {
     320                 :         25 :         return do_dump_gen_file(p, lfd, &inet_dump_ops, set);
     321                 :            : }
     322                 :            : 
     323                 :         13 : static int dump_one_inet6_fd(int lfd, u32 id, const struct fd_parms *p)
     324                 :            : {
     325                 :         13 :         return do_dump_one_inet_fd(lfd, id, p, PF_INET6);
     326                 :            : }
     327                 :            : 
     328                 :            : static const struct fdtype_ops inet6_dump_ops = {
     329                 :            :         .type           = FD_TYPES__INETSK,
     330                 :            :         .dump           = dump_one_inet6_fd,
     331                 :            : };
     332                 :            : 
     333                 :         13 : int dump_one_inet6(struct fd_parms *p, int lfd, const struct cr_fdset *set)
     334                 :            : {
     335                 :         13 :         return do_dump_gen_file(p, lfd, &inet6_dump_ops, set);
     336                 :            : }
     337                 :            : 
     338                 :       2040 : int inet_collect_one(struct nlmsghdr *h, int family, int type, int proto)
     339                 :            : {
     340                 :            :         struct inet_sk_desc *d;
     341                 :       2040 :         struct inet_diag_msg *m = NLMSG_DATA(h);
     342                 :            :         struct rtattr *tb[INET_DIAG_MAX+1];
     343                 :            :         int ret;
     344                 :            : 
     345                 :       2040 :         parse_rtattr(tb, INET_DIAG_MAX, (struct rtattr *)(m + 1),
     346                 :       2040 :                      h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
     347                 :            : 
     348         [ -  + ]:       2040 :         d = xzalloc(sizeof(*d));
     349         [ +  - ]:       2040 :         if (!d)
     350                 :            :                 return -1;
     351                 :            : 
     352                 :       2040 :         d->type = type;
     353                 :       2040 :         d->proto = proto;
     354         [ -  + ]:       2040 :         d->src_port = ntohs(m->id.idiag_sport);
     355         [ -  + ]:       2040 :         d->dst_port = ntohs(m->id.idiag_dport);
     356                 :       2040 :         d->state = m->idiag_state;
     357                 :       2040 :         d->rqlen = m->idiag_rqueue;
     358                 :       2040 :         d->wqlen = m->idiag_wqueue;
     359                 :       2040 :         memcpy(d->src_addr, m->id.idiag_src, sizeof(u32) * 4);
     360                 :       2040 :         memcpy(d->dst_addr, m->id.idiag_dst, sizeof(u32) * 4);
     361                 :            : 
     362         [ +  - ]:       2040 :         if (tb[INET_DIAG_SHUTDOWN])
     363                 :       2040 :                 d->shutdown = *(u8 *)RTA_DATA(tb[INET_DIAG_SHUTDOWN]);
     364                 :            :         else
     365         [ #  # ]:          0 :                 pr_err_once("Can't check shutdown state of inet socket\n");
     366                 :            : 
     367                 :       2040 :         ret = sk_collect_one(m->idiag_inode, family, &d->sd);
     368                 :            : 
     369                 :       2040 :         show_one_inet("Collected", d);
     370                 :            : 
     371                 :            :         return ret;
     372                 :            : }
     373                 :            : 
     374                 :            : static int open_inet_sk(struct file_desc *d);
     375                 :            : static int post_open_inet_sk(struct file_desc *d, int sk);
     376                 :            : 
     377                 :            : static struct file_desc_ops inet_desc_ops = {
     378                 :            :         .type = FD_TYPES__INETSK,
     379                 :            :         .open = open_inet_sk,
     380                 :            :         .post_open = post_open_inet_sk,
     381                 :            : };
     382                 :            : 
     383                 :            : static inline int tcp_connection(InetSkEntry *ie)
     384                 :            : {
     385                 :        180 :         return (ie->proto == IPPROTO_TCP) && (ie->state == TCP_ESTABLISHED);
     386                 :            : }
     387                 :            : 
     388                 :         76 : static int collect_one_inetsk(void *o, ProtobufCMessage *base)
     389                 :            : {
     390                 :         76 :         struct inet_sk_info *ii = o;
     391                 :            : 
     392                 :         76 :         ii->ie = pb_msg(base, InetSkEntry);
     393                 :         76 :         file_desc_add(&ii->d, ii->ie->id, &inet_desc_ops);
     394         [ +  + ]:         76 :         if (tcp_connection(ii->ie))
     395                 :         16 :                 tcp_locked_conn_add(ii);
     396                 :            : 
     397                 :            :         /*
     398                 :            :          * A socket can reuse addr only if all previous sockets allow that,
     399                 :            :          * so a value of SO_REUSEADDR can be restored after restoring all
     400                 :            :          * sockets.
     401                 :            :          */
     402                 :         76 :         ii->port = port_add(ii->ie->type, ii->ie->src_port);
     403         [ +  - ]:         76 :         if (ii->port == NULL)
     404                 :            :                 return -1;
     405                 :            : 
     406                 :         76 :         return 0;
     407                 :            : }
     408                 :            : 
     409                 :        380 : int collect_inet_sockets(void)
     410                 :            : {
     411                 :        380 :         return collect_image(CR_FD_INETSK, PB_INETSK,
     412                 :            :                         sizeof(struct inet_sk_info), collect_one_inetsk);
     413                 :            : }
     414                 :            : 
     415                 :         38 : static int inet_validate_address(InetSkEntry *ie)
     416                 :            : {
     417 [ +  + ][ +  - ]:         38 :         if ((ie->family == AF_INET) &&
     418                 :            :                         /* v0.1 had 4 in ipv4 addr len */
     419         [ -  + ]:         25 :                         (ie->n_src_addr >= PB_ALEN_INET) &&
     420                 :         25 :                         (ie->n_dst_addr >= PB_ALEN_INET))
     421                 :            :                 return 0;
     422                 :            : 
     423 [ +  - ][ +  - ]:         13 :         if ((ie->family == AF_INET6) &&
     424         [ -  + ]:         13 :                         (ie->n_src_addr == PB_ALEN_INET6) &&
     425                 :         13 :                         (ie->n_dst_addr == PB_ALEN_INET6))
     426                 :            :                 return 0;
     427                 :            : 
     428                 :          0 :         pr_err("Addr len mismatch f %d ss %lu ds %lu\n", ie->family,
     429                 :            :                         pb_repeated_size(ie, src_addr),
     430                 :            :                         pb_repeated_size(ie, dst_addr));
     431                 :            : 
     432                 :         38 :         return -1;
     433                 :            : }
     434                 :            : 
     435                 :         38 : static int post_open_inet_sk(struct file_desc *d, int sk)
     436                 :            : {
     437                 :            :         struct inet_sk_info *ii;
     438                 :            :         int val;
     439                 :            : 
     440                 :         38 :         ii = container_of(d, struct inet_sk_info, d);
     441                 :            : 
     442                 :            :         /* SO_REUSEADDR is set for all sockets */
     443 [ +  + ][ +  + ]:         38 :         if (!tcp_connection(ii->ie) && ii->ie->opts->reuseaddr)
     444                 :            :                 return 0;
     445                 :            : 
     446                 :         28 :         futex_wait_until(&ii->port->users, 0);
     447                 :            : 
     448                 :            :         /* Disabling repair mode drops SO_REUSEADDR */
     449         [ +  + ]:         28 :         if (tcp_connection(ii->ie))
     450                 :          8 :                 tcp_repair_off(sk);
     451                 :            : 
     452                 :         28 :         val = ii->ie->opts->reuseaddr;
     453         [ +  - ]:         38 :         if (restore_opt(sk, SOL_SOCKET, SO_REUSEADDR, &val))
     454                 :            :                 return -1;
     455                 :            : 
     456                 :            :         return 0;
     457                 :            : }
     458                 :            : 
     459                 :         38 : static int open_inet_sk(struct file_desc *d)
     460                 :            : {
     461                 :            :         struct inet_sk_info *ii;
     462                 :            :         InetSkEntry *ie;
     463                 :         38 :         int sk, yes = 1;
     464                 :            : 
     465                 :         38 :         ii = container_of(d, struct inet_sk_info, d);
     466                 :         38 :         ie = ii->ie;
     467                 :            : 
     468                 :         38 :         show_one_inet_img("Restore", ie);
     469                 :            : 
     470         [ -  + ]:         38 :         if (ie->family != AF_INET && ie->family != AF_INET6) {
     471                 :          0 :                 pr_err("Unsupported socket family: %d\n", ie->family);
     472                 :            :                 return -1;
     473                 :            :         }
     474                 :            : 
     475         [ -  + ]:         38 :         if ((ie->type != SOCK_STREAM) && (ie->type != SOCK_DGRAM)) {
     476                 :          0 :                 pr_err("Unsupported socket type: %d\n", ie->type);
     477                 :            :                 return -1;
     478                 :            :         }
     479                 :            : 
     480         [ +  - ]:         38 :         if (inet_validate_address(ie))
     481                 :            :                 return -1;
     482                 :            : 
     483                 :         38 :         sk = socket(ie->family, ie->type, ie->proto);
     484         [ -  + ]:         38 :         if (sk < 0) {
     485                 :          0 :                 pr_perror("Can't create unix socket");
     486                 :            :                 return -1;
     487                 :            :         }
     488                 :            : 
     489         [ +  + ]:         38 :         if (ie->v6only) {
     490         [ +  - ]:          4 :                 if (restore_opt(sk, SOL_IPV6, IPV6_V6ONLY, &yes) == -1)
     491                 :            :                         return -1;
     492                 :            :         }
     493                 :            : 
     494                 :            :         /*
     495                 :            :          * Set SO_REUSEADDR, because some sockets can be bound to one addr.
     496                 :            :          * The origin value of SO_REUSEADDR will be restored in post_open.
     497                 :            :          */
     498         [ +  - ]:         38 :         if (restore_opt(sk, SOL_SOCKET, SO_REUSEADDR, &yes))
     499                 :            :                 return -1;
     500                 :            : 
     501         [ +  + ]:         38 :         if (tcp_connection(ie)) {
     502         [ -  + ]:          8 :                 if (!opts.tcp_established_ok) {
     503                 :          0 :                         pr_err("Connected TCP socket in image\n");
     504                 :          0 :                         goto err;
     505                 :            :                 }
     506                 :            : 
     507         [ +  - ]:          8 :                 if (restore_one_tcp(sk, ii))
     508                 :            :                         goto err;
     509                 :            : 
     510                 :            :                 goto done;
     511                 :            :         }
     512                 :            : 
     513                 :            :         /*
     514                 :            :          * Listen sockets are easiest ones -- simply
     515                 :            :          * bind() and listen(), and that's all.
     516                 :            :          */
     517                 :            : 
     518         [ +  + ]:         30 :         if (ie->src_port) {
     519         [ +  - ]:         22 :                 if (inet_bind(sk, ii))
     520                 :            :                         goto err;
     521                 :            :         }
     522                 :            : 
     523         [ +  + ]:         30 :         if (ie->state == TCP_LISTEN) {
     524         [ -  + ]:         10 :                 if (ie->proto != IPPROTO_TCP) {
     525                 :          0 :                         pr_err("Wrong socket in listen state %d\n", ie->proto);
     526                 :          0 :                         goto err;
     527                 :            :                 }
     528                 :            : 
     529         [ -  + ]:         10 :                 if (listen(sk, ie->backlog) == -1) {
     530                 :          0 :                         pr_perror("Can't listen on a socket");
     531                 :          0 :                         goto err;
     532                 :            :                 }
     533                 :            :         }
     534                 :            : 
     535   [ +  +  +  - ]:         36 :         if (ie->state == TCP_ESTABLISHED &&
     536                 :          6 :                         inet_connect(sk, ii))
     537                 :            :                 goto err;
     538                 :            : done:
     539                 :         38 :         futex_dec(&ii->port->users);
     540                 :            : 
     541         [ +  - ]:         38 :         if (rst_file_params(sk, ie->fown, ie->flags))
     542                 :            :                 goto err;
     543                 :            : 
     544         [ +  - ]:         38 :         if (restore_socket_opts(sk, ie->opts))
     545                 :            :                 return -1;
     546                 :            : 
     547                 :            :         return sk;
     548                 :            : 
     549                 :            : err:
     550                 :         38 :         close(sk);
     551                 :            :         return -1;
     552                 :            : }
     553                 :            : 
     554                 :            : union sockaddr_inet {
     555                 :            :         struct sockaddr_in v4;
     556                 :            :         struct sockaddr_in6 v6;
     557                 :            : };
     558                 :            : 
     559                 :         44 : static int restore_sockaddr(union sockaddr_inet *sa,
     560                 :            :                 int family, uint32_t pb_port, uint32_t *pb_addr)
     561                 :            : {
     562                 :            :         BUILD_BUG_ON(sizeof(sa->v4.sin_addr.s_addr) > PB_ALEN_INET * sizeof(uint32_t));
     563                 :            :         BUILD_BUG_ON(sizeof(sa->v6.sin6_addr.s6_addr) > PB_ALEN_INET6 * sizeof(uint32_t));
     564                 :            : 
     565                 :         44 :         memzero(sa, sizeof(*sa));
     566                 :            : 
     567         [ +  + ]:         44 :         if (family == AF_INET) {
     568                 :         25 :                 sa->v4.sin_family = AF_INET;
     569         [ -  + ]:         25 :                 sa->v4.sin_port = htons(pb_port);
     570                 :         25 :                 memcpy(&sa->v4.sin_addr.s_addr, pb_addr, sizeof(sa->v4.sin_addr.s_addr));
     571                 :         25 :                 return sizeof(sa->v4);
     572                 :            :         }
     573                 :            : 
     574         [ +  - ]:         19 :         if (family == AF_INET6) {
     575                 :         19 :                 sa->v6.sin6_family = AF_INET6;
     576         [ -  + ]:         19 :                 sa->v6.sin6_port = htons(pb_port);
     577                 :         19 :                 memcpy(sa->v6.sin6_addr.s6_addr, pb_addr, sizeof(sa->v6.sin6_addr.s6_addr));
     578                 :         19 :                 return sizeof(sa->v6);
     579                 :            :         }
     580                 :            : 
     581                 :          0 :         BUG();
     582                 :         44 :         return -1;
     583                 :            : }
     584                 :            : 
     585                 :         30 : int inet_bind(int sk, struct inet_sk_info *ii)
     586                 :            : {
     587                 :            :         union sockaddr_inet addr;
     588                 :            :         int addr_size;
     589                 :            : 
     590                 :         30 :         addr_size = restore_sockaddr(&addr, ii->ie->family,
     591                 :         30 :                         ii->ie->src_port, ii->ie->src_addr);
     592                 :            : 
     593         [ -  + ]:         30 :         if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
     594                 :         30 :                 pr_perror("Can't bind inet socket");
     595                 :            :                 return -1;
     596                 :            :         }
     597                 :            : 
     598                 :            :         return 0;
     599                 :            : }
     600                 :            : 
     601                 :         14 : int inet_connect(int sk, struct inet_sk_info *ii)
     602                 :            : {
     603                 :            :         union sockaddr_inet addr;
     604                 :            :         int addr_size;
     605                 :            : 
     606                 :         14 :         addr_size = restore_sockaddr(&addr, ii->ie->family,
     607                 :         14 :                         ii->ie->dst_port, ii->ie->dst_addr);
     608                 :            : 
     609         [ -  + ]:         14 :         if (connect(sk, (struct sockaddr *)&addr, addr_size) == -1) {
     610                 :         14 :                 pr_perror("Can't connect inet socket back");
     611                 :            :                 return -1;
     612                 :            :         }
     613                 :            : 
     614                 :            :         return 0;
     615                 :            : }
     616                 :            : 
     617                 :          0 : void show_inetsk(int fd, struct cr_options *o)
     618                 :            : {
     619                 :          0 :         pb_show_plain_pretty(fd, PB_INETSK, "1:%#x 2:%#x 3:%d 4:%d 5:%d 6:%d 7:%d 8:%d 9:%2x 11:A 12:A");
     620                 :          0 : }

Generated by: LCOV version 1.9