1 //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  Created by Greg Clayton on 12/12/07.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "RNBSocket.h"
14 #include "DNBError.h"
15 #include "DNBLog.h"
16 #include <arpa/inet.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <map>
20 #include <netdb.h>
21 #include <netinet/in.h>
22 #include <netinet/tcp.h>
23 #include <sys/event.h>
24 #include <termios.h>
25 #include <vector>
26 
27 #include "lldb/Host/SocketAddress.h"
28 
29 #ifdef WITH_LOCKDOWN
30 #include "lockdown.h"
31 #endif
32 
33 /* Once we have a RNBSocket object with a port # specified,
34    this function is called to wait for an incoming connection.
35    This function blocks while waiting for that connection.  */
36 
ResolveIPV4HostName(const char * hostname,in_addr_t & addr)37 bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) {
38   if (hostname == NULL || hostname[0] == '\0' ||
39       strcmp(hostname, "localhost") == 0 ||
40       strcmp(hostname, "127.0.0.1") == 0) {
41     addr = htonl(INADDR_LOOPBACK);
42     return true;
43   } else if (strcmp(hostname, "*") == 0) {
44     addr = htonl(INADDR_ANY);
45     return true;
46   } else {
47     // See if an IP address was specified as numbers
48     int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr);
49 
50     if (inet_pton_result == 1)
51       return true;
52 
53     struct hostent *host_entry = gethostbyname(hostname);
54     if (host_entry) {
55       std::string ip_str(
56           ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
57       inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr);
58       if (inet_pton_result == 1)
59         return true;
60     }
61   }
62   return false;
63 }
64 
Listen(const char * listen_host,uint16_t port,PortBoundCallback callback,const void * callback_baton)65 rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port,
66                             PortBoundCallback callback,
67                             const void *callback_baton) {
68   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called",
69   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
70   // Disconnect without saving errno
71   Disconnect(false);
72 
73   DNBError err;
74   int queue_id = kqueue();
75   if (queue_id < 0) {
76     err.SetError(errno, DNBError::MachKernel);
77     err.LogThreaded("error: failed to create kqueue.");
78     return rnb_err;
79   }
80 
81   bool any_addr = (strcmp(listen_host, "*") == 0);
82 
83   // If the user wants to allow connections from any address we should create
84   // sockets on all families that can resolve localhost. This will allow us to
85   // listen for IPv6 and IPv4 connections from all addresses if those interfaces
86   // are available.
87   const char *local_addr = any_addr ? "localhost" : listen_host;
88 
89   std::map<int, lldb_private::SocketAddress> sockets;
90   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
91       local_addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
92 
93   for (auto address : addresses) {
94     int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
95     if (sock_fd == -1)
96       continue;
97 
98     SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
99 
100     lldb_private::SocketAddress bind_address = address;
101 
102     if(any_addr || !bind_address.IsLocalhost())
103       bind_address.SetToAnyAddress(bind_address.GetFamily(), port);
104     else
105       bind_address.SetPort(port);
106 
107     int error =
108         ::bind(sock_fd, &bind_address.sockaddr(), bind_address.GetLength());
109     if (error == -1) {
110       ClosePort(sock_fd, false);
111       continue;
112     }
113 
114     error = ::listen(sock_fd, 5);
115     if (error == -1) {
116       ClosePort(sock_fd, false);
117       continue;
118     }
119 
120     // We were asked to listen on port zero which means we must now read the
121     // actual port that was given to us as port zero is a special code for "find
122     // an open port for me". This will only execute on the first socket created,
123     // subesquent sockets will reuse this port number.
124     if (port == 0) {
125       socklen_t sa_len = address.GetLength();
126       if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
127         port = address.GetPort();
128     }
129 
130     sockets[sock_fd] = address;
131   }
132 
133   if (sockets.size() == 0) {
134     err.SetError(errno, DNBError::POSIX);
135     err.LogThreaded("::listen or ::bind failed");
136     return rnb_err;
137   }
138 
139   if (callback)
140     callback(callback_baton, port);
141 
142   std::vector<struct kevent> events;
143   events.resize(sockets.size());
144   int i = 0;
145   for (auto socket : sockets) {
146     EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0);
147   }
148 
149   bool accept_connection = false;
150 
151   // Loop until we are happy with our connection
152   while (!accept_connection) {
153 
154     struct kevent event_list[4];
155     int num_events =
156         kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
157 
158     if (num_events < 0) {
159       err.SetError(errno, DNBError::MachKernel);
160       err.LogThreaded("error: kevent() failed.");
161     }
162 
163     for (int i = 0; i < num_events; ++i) {
164       auto sock_fd = event_list[i].ident;
165       auto socket_pair = sockets.find(sock_fd);
166       if (socket_pair == sockets.end())
167         continue;
168 
169       lldb_private::SocketAddress &addr_in = socket_pair->second;
170       lldb_private::SocketAddress accept_addr;
171       socklen_t sa_len = accept_addr.GetMaxLength();
172       m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len);
173 
174       if (m_fd == -1) {
175         err.SetError(errno, DNBError::POSIX);
176         err.LogThreaded("error: Socket accept failed.");
177       }
178 
179       if (addr_in.IsAnyAddr())
180         accept_connection = true;
181       else {
182         if (accept_addr == addr_in)
183           accept_connection = true;
184         else {
185           ::close(m_fd);
186           m_fd = -1;
187           ::fprintf(
188               stderr,
189               "error: rejecting incoming connection from %s (expecting %s)\n",
190               accept_addr.GetIPAddress().c_str(),
191               addr_in.GetIPAddress().c_str());
192           DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
193                          accept_addr.GetIPAddress().c_str(),
194                          addr_in.GetIPAddress().c_str());
195           err.Clear();
196         }
197       }
198     }
199     if (err.Fail())
200       break;
201   }
202   for (auto socket : sockets) {
203     int ListenFd = socket.first;
204     ClosePort(ListenFd, false);
205   }
206 
207   if (err.Fail())
208     return rnb_err;
209 
210   // Keep our TCP packets coming without any delays.
211   SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
212 
213   return rnb_success;
214 }
215 
Connect(const char * host,uint16_t port)216 rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
217   auto result = rnb_err;
218   Disconnect(false);
219 
220   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
221       host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
222 
223   for (auto address : addresses) {
224     m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
225     if (m_fd == -1)
226       continue;
227 
228     // Enable local address reuse
229     SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
230 
231     address.SetPort(port);
232 
233     if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
234       Disconnect(false);
235       continue;
236     }
237     SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
238 
239     result = rnb_success;
240     break;
241   }
242   return result;
243 }
244 
useFD(int fd)245 rnb_err_t RNBSocket::useFD(int fd) {
246   if (fd < 0) {
247     DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
248     return rnb_err;
249   }
250 
251   m_fd = fd;
252   return rnb_success;
253 }
254 
255 #ifdef WITH_LOCKDOWN
ConnectToService()256 rnb_err_t RNBSocket::ConnectToService() {
257   DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
258   // Disconnect from any previous connections
259   Disconnect(false);
260   if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) {
261     DNBLogThreadedIf(LOG_RNB_COMM,
262                      "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
263     m_fd = -1;
264     return rnb_not_connected;
265   }
266   m_fd = ::lockdown_get_socket(m_ld_conn);
267   if (m_fd == -1) {
268     DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
269     return rnb_not_connected;
270   }
271   m_fd_from_lockdown = true;
272   return rnb_success;
273 }
274 #endif
275 
OpenFile(const char * path)276 rnb_err_t RNBSocket::OpenFile(const char *path) {
277   DNBError err;
278   m_fd = open(path, O_RDWR);
279   if (m_fd == -1) {
280     err.SetError(errno, DNBError::POSIX);
281     err.LogThreaded("can't open file '%s'", path);
282     return rnb_not_connected;
283   } else {
284     struct termios stdin_termios;
285 
286     if (::tcgetattr(m_fd, &stdin_termios) == 0) {
287       stdin_termios.c_lflag &= ~ECHO;   // Turn off echoing
288       stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
289       ::tcsetattr(m_fd, TCSANOW, &stdin_termios);
290     }
291   }
292   return rnb_success;
293 }
294 
SetSocketOption(int fd,int level,int option_name,int option_value)295 int RNBSocket::SetSocketOption(int fd, int level, int option_name,
296                                int option_value) {
297   return ::setsockopt(fd, level, option_name, &option_value,
298                       sizeof(option_value));
299 }
300 
Disconnect(bool save_errno)301 rnb_err_t RNBSocket::Disconnect(bool save_errno) {
302 #ifdef WITH_LOCKDOWN
303   if (m_fd_from_lockdown) {
304     m_fd_from_lockdown = false;
305     m_fd = -1;
306     lockdown_disconnect(m_ld_conn);
307     return rnb_success;
308   }
309 #endif
310   return ClosePort(m_fd, save_errno);
311 }
312 
Read(std::string & p)313 rnb_err_t RNBSocket::Read(std::string &p) {
314   char buf[1024];
315   p.clear();
316 
317   // Note that BUF is on the stack so we must be careful to keep any
318   // writes to BUF from overflowing or we'll have security issues.
319 
320   if (m_fd == -1)
321     return rnb_err;
322 
323   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()",
324   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
325   DNBError err;
326   ssize_t bytesread = read(m_fd, buf, sizeof(buf));
327   if (bytesread <= 0)
328     err.SetError(errno, DNBError::POSIX);
329   else
330     p.append(buf, bytesread);
331 
332   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
333     err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf),
334                     (uint64_t)bytesread);
335 
336   // Our port went away - we have to mark this so IsConnected will return the
337   // truth.
338   if (bytesread == 0) {
339     m_fd = -1;
340     return rnb_not_connected;
341   } else if (bytesread == -1) {
342     m_fd = -1;
343     return rnb_err;
344   }
345   // Strip spaces from the end of the buffer
346   while (!p.empty() && isspace(p[p.size() - 1]))
347     p.erase(p.size() - 1);
348 
349   // Most data in the debugserver packets valid printable characters...
350   DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
351   return rnb_success;
352 }
353 
Write(const void * buffer,size_t length)354 rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
355   if (m_fd == -1)
356     return rnb_err;
357 
358   DNBError err;
359   ssize_t bytessent = write(m_fd, buffer, length);
360   if (bytessent < 0)
361     err.SetError(errno, DNBError::POSIX);
362 
363   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
364     err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i",
365                     m_fd, buffer, length, (uint64_t)bytessent);
366 
367   if (bytessent < 0)
368     return rnb_err;
369 
370   if ((size_t)bytessent != length)
371     return rnb_err;
372 
373   DNBLogThreadedIf(
374       LOG_RNB_PACKETS, "putpkt: %*s", (int)length,
375       (const char *)
376           buffer); // All data is string based in debugserver, so this is safe
377   DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length,
378                    (const char *)buffer);
379 
380   return rnb_success;
381 }
382 
ClosePort(int & fd,bool save_errno)383 rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) {
384   int close_err = 0;
385   if (fd > 0) {
386     errno = 0;
387     close_err = close(fd);
388     fd = -1;
389   }
390   return close_err != 0 ? rnb_err : rnb_success;
391 }
392