summaryrefslogtreecommitdiff
path: root/proto/rpki/transport.c
blob: 26609764731af6f5dc128d5fcb391078da8c1ef1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 *	BIRD -- The Resource Public Key Infrastructure (RPKI) to Router Protocol
 *
 *	(c) 2015 CZ.NIC
 *	(c) 2015 Pavel Tvrdik <pawel.tvrdik@gmail.com>
 *
 *	This file was a part of RTRlib: http://rpki.realmv6.org/
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include <sys/socket.h>
#include <netdb.h>

#include "rpki.h"
#include "transport.h"
#include "sysdep/unix/unix.h"

/**
 * rpki_hostname_autoresolv - auto-resolve an IP address from a hostname
 * @host: domain name of host, e.g. "rpki-validator.realmv6.org"
 * @err_msg: error message returned in case of errors
 *
 * This function resolves an IP address from a hostname.
 * Returns &ip_addr structure with IP address or |IPA_NONE|.
 */
static ip_addr
rpki_hostname_autoresolv(const char *host, const char **err_msg)
{
  struct addrinfo *res;
  struct addrinfo hints = {
      .ai_family = AF_UNSPEC,
      .ai_socktype = SOCK_STREAM,
      .ai_flags = AI_ADDRCONFIG,
  };

  *err_msg = NULL;

  if (!host)
    return IPA_NONE;

  int err_code = getaddrinfo(host, NULL, &hints, &res);
  if (err_code != 0)
  {
    *err_msg = gai_strerror(err_code);
    return IPA_NONE;
  }

  ip_addr addr = IPA_NONE;
  uint unused;

  sockaddr_read((sockaddr *) res->ai_addr, res->ai_family, &addr, NULL, &unused);

  freeaddrinfo(res);
  return addr;
}

/**
 * rpki_tr_open - prepare and open a socket connection
 * @tr: initialized transport socket
 *
 * Prepare and open a socket connection specified by @tr that must be initialized before.
 * This function ends with a calling the sk_open() function.
 * Returns RPKI_TR_SUCCESS or RPKI_TR_ERROR.
 */
int
rpki_tr_open(struct rpki_tr_sock *tr)
{
  struct rpki_cache *cache = tr->cache;
  struct rpki_config *cf = (void *) cache->p->p.cf;

  ASSERT(tr->sk == NULL);
  tr->sk = sk_new(cache->pool);
  sock *sk = tr->sk;

  /* sk->type -1 is invalid value, a correct value MUST be set in the specific transport layer in open_fp() hook */
  sk->type = -1;

  sk->tx_hook = rpki_connected_hook;
  sk->err_hook = rpki_err_hook;
  sk->data = cache;
  sk->daddr = cf->ip;
  sk->dport = cf->port;
  sk->host = cf->hostname;
  sk->rbsize = RPKI_RX_BUFFER_SIZE;
  sk->tbsize = RPKI_TX_BUFFER_SIZE;
  sk->tos = IP_PREC_INTERNET_CONTROL;
  sk->flags |= SKF_THREAD;
  sk->loop = cache->p->p.loop;

  if (ipa_zero(sk->daddr) && sk->host)
  {
    const char *err_msg;

    sk->daddr = rpki_hostname_autoresolv(sk->host, &err_msg);
    if (ipa_zero(sk->daddr))
    {
      log(L_ERR "%s: Cannot resolve hostname '%s': %s",
	  cache->p->p.name, sk->host, err_msg);
      return RPKI_TR_ERROR;
    }
  }

  return tr->open_fp(tr);
}

/**
 * rpki_tr_close - close socket and prepare it for possible next open
 * @tr: successfully opened transport socket
 *
 * Close socket and free resources.
 */
void
rpki_tr_close(struct rpki_tr_sock *tr)
{
  if (tr->ident)
  {
    mb_free((char *) tr->ident);
    tr->ident = NULL;
  }

  if (tr->sk)
  {
    sk_stop(tr->sk);
    rfree(tr->sk);
    tr->sk = NULL;
  }
}

/**
 * rpki_tr_ident - Returns a string identifier for the rpki transport socket
 * @tr: successfully opened transport socket
 *
 * Returns a \0 terminated string identifier for the socket endpoint, e.g. "<host>:<port>".
 * Memory is allocated inside @tr structure.
 */
inline const char *
rpki_tr_ident(struct rpki_tr_sock *tr)
{
  return tr->ident_fp(tr);
}