xdrpp
RFC4506 XDR compiler and message library
rpcbind.cc
1 
2 #include <vector>
3 #include <xdrpp/rpcb_prot.hh>
4 #include <xdrpp/rpcbind.h>
5 #include <xdrpp/srpc.h>
6 
7 namespace xdr {
8 
9 using std::string;
10 
11 namespace {
12 
13 std::vector<rpcb> registered_services;
14 
15 void
16 run_cleanup()
17 {
18  try {
19  auto fd = tcp_connect(nullptr, "sunrpc");
20  srpc_client<xdr::RPCBVERS4> c{fd.get()};
21  for (const auto &arg : registered_services)
22  c.RPCBPROC_UNSET(arg);
23  }
24  catch (...) {}
25 }
26 
27 void
28 set_cleanup()
29 {
30  static struct once {
31  once() { atexit(run_cleanup); }
32  } o;
33 }
34 
35 } // namespace
36 
37 unique_sock
38 tcp_connect_rpc(const char *host, std::uint32_t prog, std::uint32_t vers,
39  int family)
40 {
41  unique_addrinfo ail = get_addrinfo(host, SOCK_STREAM, "sunrpc", family);
42 
43  for (const addrinfo *ai = ail.get(); ai; ai = ai->ai_next) {
44  try {
45  auto s = tcp_connect1(ai);
46  srpc_client<xdr::RPCBVERS4> c{s.get()};
47 
48  rpcb arg;
49  arg.r_prog = prog;
50  arg.r_vers = vers;
51  arg.r_netid = ai->ai_family == AF_INET6 ? "tcp6" : "tcp";
52  arg.r_addr = make_uaddr(s.get());
53  auto res = c.RPCBPROC_GETADDR(arg);
54 
55  int port = parse_uaddr_port(*res);
56  if (port == -1)
57  continue;
58 
59  switch (ai->ai_family) {
60  case AF_INET:
61  ((sockaddr_in *) ai->ai_addr)->sin_port = htons(port);
62  break;
63  case AF_INET6:
64  ((sockaddr_in6 *) ai->ai_addr)->sin6_port = htons(port);
65  break;
66  }
67  s.clear();
68  if ((s = tcp_connect1(ai)))
69  return s;
70  }
71  catch(const std::system_error &) {}
72  }
73  throw std::system_error(std::make_error_code(std::errc::connection_refused),
74  "Could not obtain port from rpcbind");
75 }
76 
77 int
78 parse_uaddr_port(const string &uaddr)
79 {
80  std::size_t low = uaddr.rfind('.');
81  if (low == string::npos || low == 0)
82  return -1;
83  std::size_t high = uaddr.rfind('.', low - 1);
84  if (high == string::npos)
85  return -1;
86 
87  try {
88  int hb = std::stoi(uaddr.substr(high+1));
89  int lb = std::stoi(uaddr.substr(low+1));
90  if (hb < 0 || hb > 255 || lb < 0 || lb > 255)
91  return -1;
92  return hb << 8 | lb;
93  }
94  catch (std::invalid_argument &) {
95  return -1;
96  }
97  catch (std::out_of_range &) {
98  return -1;
99  }
100 }
101 
102 string
103 make_uaddr(const sockaddr *sa, socklen_t salen)
104 {
105  string host, portstr;
106  get_numinfo(sa, salen, &host, &portstr);
107  unsigned port = std::stoul(portstr);
108  if (port == 0 || port >= 65536)
109  throw std::system_error(std::make_error_code(std::errc::invalid_argument),
110  "bad port number");
111  host += "." + std::to_string(port >> 8) + "." + std::to_string(port & 0xff);
112  return host;
113 }
114 
115 string
117 {
118  union {
119  struct sockaddr sa;
120  struct sockaddr_storage ss;
121  };
122  socklen_t salen{sizeof ss};
123  std::memset(&ss, 0, salen);
124  if (getsockname(s.fd_, &sa, &salen) == -1)
125  throw_sockerr("getsockname");
126  return make_uaddr(&sa, salen);
127 }
128 
129 void
130 rpcbind_register(const sockaddr *sa, socklen_t salen,
131  std::uint32_t prog, std::uint32_t vers)
132 {
133  set_cleanup();
134 
135  auto fd = tcp_connect(nullptr, "sunrpc", sa->sa_family);
136  srpc_client<xdr::RPCBVERS4> c{fd.get()};
137 
138  rpcb arg;
139  arg.r_prog = prog;
140  arg.r_vers = vers;
141  arg.r_netid = sa->sa_family == AF_INET6 ? "tcp6" : "tcp";
142  arg.r_addr = make_uaddr(sa, salen);
143  arg.r_owner = std::to_string(geteuid());
144  c.RPCBPROC_UNSET(arg);
145  auto res = c.RPCBPROC_SET(arg);
146  if (!*res)
147  throw std::system_error(std::make_error_code(std::errc::address_in_use),
148  "RPCBPROC_SET");
149  registered_services.push_back(arg);
150 }
151 
152 void
153 rpcbind_register(sock_t s, std::uint32_t prog, std::uint32_t vers)
154 {
155  union {
156  struct sockaddr sa;
157  struct sockaddr_storage ss;
158  };
159  socklen_t salen{sizeof ss};
160  std::memset(&ss, 0, salen);
161  if (getsockname(s.fd_, &sa, &salen) == -1)
162  throw_sockerr("getsockname");
163  rpcbind_register(&sa, salen, prog, vers);
164 }
165 
166 } // namespace xdr
167 
unique_sock tcp_connect(const addrinfo *ai)
Try connecting to every addrinfo in a list until one succeeds.
Definition: socket.cc:116
void throw_sockerr(const char *)
Throw a system_error exception for the last socket error.
Definition: socket_unix.cc:31
unique_sock tcp_connect1(const addrinfo *ai, bool ndelay)
Try connecting to the first addrinfo in a linked list.
Definition: socket.cc:102
Most of the xdrpp library is encapsulated in the xdr namespace.
Definition: arpc.cc:4
std::unique_ptr< addrinfo, delete_addrinfo > unique_addrinfo
Automatically garbage-collected addrinfo pointer.
Definition: socket.h:105
Simple synchronous RPC functions.
unique_addrinfo get_addrinfo(const char *host, int socktype, const char *service, int family)
Wrapper around getaddrinfo that returns a garbage-collected xdr::unique_addrinfo. ...
Definition: socket.cc:70
int parse_uaddr_port(const string &uaddr)
Extract the port number from an RFC1833 / RFC5665 universal network address (uaddr).
Definition: rpcbind.cc:78
Abstract away the type of a socket (for windows).
Definition: socket.h:28
Support for registering and (upon exit) unregistering with rpcbind.
string make_uaddr(const sockaddr *sa, socklen_t salen)
Create a uaddr for a local address or file descriptor.
Definition: rpcbind.cc:103
void rpcbind_register(const sockaddr *sa, socklen_t salen, std::uint32_t prog, std::uint32_t vers)
Register a service listening on sa with rpcbind.
Definition: rpcbind.cc:130
unique_sock tcp_connect_rpc(const char *host, std::uint32_t prog, std::uint32_t vers, int family)
Create a TCP connection to an RPC server on host, first querying rpcbind on host to determine the por...
Definition: rpcbind.cc:38
void get_numinfo(const sockaddr *sa, socklen_t salen, string *host, string *serv)
Return printable versions of numeric host and port number.
Definition: socket.cc:85
typename T::template _xdr_client< synchronous_client_base > srpc_client
Create an RPC client from an interface type and connected stream socket.
Definition: srpc.h:95