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