130fdc8d8SChris Lattner //===-- RNBSocket.cpp -------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner //
930fdc8d8SChris Lattner //  Created by Greg Clayton on 12/12/07.
1030fdc8d8SChris Lattner //
1130fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
1230fdc8d8SChris Lattner 
1330fdc8d8SChris Lattner #include "RNBSocket.h"
14b9c1b51eSKate Stone #include "DNBError.h"
15b9c1b51eSKate Stone #include "DNBLog.h"
1695bf0fd3SGreg Clayton #include <arpa/inet.h>
17*76e47d48SRaphael Isemann #include <cerrno>
1830fdc8d8SChris Lattner #include <fcntl.h>
1911827799SChris Bieneman #include <map>
2095bf0fd3SGreg Clayton #include <netdb.h>
2130fdc8d8SChris Lattner #include <netinet/in.h>
2230fdc8d8SChris Lattner #include <netinet/tcp.h>
2311827799SChris Bieneman #include <sys/event.h>
2430fdc8d8SChris Lattner #include <termios.h>
2511827799SChris Bieneman #include <vector>
2611827799SChris Bieneman 
2711827799SChris Bieneman #include "lldb/Host/SocketAddress.h"
2830fdc8d8SChris Lattner 
2942999a48SJason Molenda #ifdef WITH_LOCKDOWN
3030fdc8d8SChris Lattner #include "lockdown.h"
3130fdc8d8SChris Lattner #endif
3230fdc8d8SChris Lattner 
Listen(const char * listen_host,uint16_t port,PortBoundCallback callback,const void * callback_baton)33b9c1b51eSKate Stone rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port,
34b9c1b51eSKate Stone                             PortBoundCallback callback,
35b9c1b51eSKate Stone                             const void *callback_baton) {
36b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called",
37b9c1b51eSKate Stone   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
3830fdc8d8SChris Lattner   // Disconnect without saving errno
3930fdc8d8SChris Lattner   Disconnect(false);
4030fdc8d8SChris Lattner 
4130fdc8d8SChris Lattner   DNBError err;
4211827799SChris Bieneman   int queue_id = kqueue();
4311827799SChris Bieneman   if (queue_id < 0) {
4411827799SChris Bieneman     err.SetError(errno, DNBError::MachKernel);
4511827799SChris Bieneman     err.LogThreaded("error: failed to create kqueue.");
46d01a2fa3SChris Bieneman     return rnb_err;
47d01a2fa3SChris Bieneman   }
48d01a2fa3SChris Bieneman 
497dc58b23SChris Bieneman   bool any_addr = (strcmp(listen_host, "*") == 0);
507dc58b23SChris Bieneman 
517dc58b23SChris Bieneman   // If the user wants to allow connections from any address we should create
527dc58b23SChris Bieneman   // sockets on all families that can resolve localhost. This will allow us to
537dc58b23SChris Bieneman   // listen for IPv6 and IPv4 connections from all addresses if those interfaces
547dc58b23SChris Bieneman   // are available.
557dc58b23SChris Bieneman   const char *local_addr = any_addr ? "localhost" : listen_host;
567dc58b23SChris Bieneman 
5711827799SChris Bieneman   std::map<int, lldb_private::SocketAddress> sockets;
5811827799SChris Bieneman   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
597dc58b23SChris Bieneman       local_addr, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
60d01a2fa3SChris Bieneman 
6111827799SChris Bieneman   for (auto address : addresses) {
6211827799SChris Bieneman     int sock_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
6311827799SChris Bieneman     if (sock_fd == -1)
6411827799SChris Bieneman       continue;
65107e6942SPavel Labath 
6611827799SChris Bieneman     SetSocketOption(sock_fd, SOL_SOCKET, SO_REUSEADDR, 1);
6711827799SChris Bieneman 
687dc58b23SChris Bieneman     lldb_private::SocketAddress bind_address = address;
6911827799SChris Bieneman 
707dc58b23SChris Bieneman     if(any_addr || !bind_address.IsLocalhost())
717dc58b23SChris Bieneman       bind_address.SetToAnyAddress(bind_address.GetFamily(), port);
727dc58b23SChris Bieneman     else
737dc58b23SChris Bieneman       bind_address.SetPort(port);
747dc58b23SChris Bieneman 
757dc58b23SChris Bieneman     int error =
767dc58b23SChris Bieneman         ::bind(sock_fd, &bind_address.sockaddr(), bind_address.GetLength());
7711827799SChris Bieneman     if (error == -1) {
7811827799SChris Bieneman       ClosePort(sock_fd, false);
7911827799SChris Bieneman       continue;
80d01a2fa3SChris Bieneman     }
81fd23889eSGreg Clayton 
8211827799SChris Bieneman     error = ::listen(sock_fd, 5);
8311827799SChris Bieneman     if (error == -1) {
8411827799SChris Bieneman       ClosePort(sock_fd, false);
8511827799SChris Bieneman       continue;
8611827799SChris Bieneman     }
8711827799SChris Bieneman 
8811827799SChris Bieneman     // We were asked to listen on port zero which means we must now read the
8911827799SChris Bieneman     // actual port that was given to us as port zero is a special code for "find
9011827799SChris Bieneman     // an open port for me". This will only execute on the first socket created,
9111827799SChris Bieneman     // subesquent sockets will reuse this port number.
92107e6942SPavel Labath     if (port == 0) {
9311827799SChris Bieneman       socklen_t sa_len = address.GetLength();
9411827799SChris Bieneman       if (getsockname(sock_fd, &address.sockaddr(), &sa_len) == 0)
9511827799SChris Bieneman         port = address.GetPort();
96107e6942SPavel Labath     }
97107e6942SPavel Labath 
9811827799SChris Bieneman     sockets[sock_fd] = address;
9911827799SChris Bieneman   }
10011827799SChris Bieneman 
10111827799SChris Bieneman   if (sockets.size() == 0) {
10211827799SChris Bieneman     err.SetError(errno, DNBError::POSIX);
10311827799SChris Bieneman     err.LogThreaded("::listen or ::bind failed");
10411827799SChris Bieneman     return rnb_err;
10511827799SChris Bieneman   }
10611827799SChris Bieneman 
10711827799SChris Bieneman   if (callback)
10811827799SChris Bieneman     callback(callback_baton, port);
10911827799SChris Bieneman 
11011827799SChris Bieneman   std::vector<struct kevent> events;
11111827799SChris Bieneman   events.resize(sockets.size());
11211827799SChris Bieneman   int i = 0;
11311827799SChris Bieneman   for (auto socket : sockets) {
11411827799SChris Bieneman     EV_SET(&events[i++], socket.first, EVFILT_READ, EV_ADD, 0, 0, 0);
11511827799SChris Bieneman   }
116107e6942SPavel Labath 
117fd23889eSGreg Clayton   bool accept_connection = false;
118fd23889eSGreg Clayton 
119fd23889eSGreg Clayton   // Loop until we are happy with our connection
120b9c1b51eSKate Stone   while (!accept_connection) {
121fd23889eSGreg Clayton 
12211827799SChris Bieneman     struct kevent event_list[4];
12311827799SChris Bieneman     int num_events =
12411827799SChris Bieneman         kevent(queue_id, events.data(), events.size(), event_list, 4, NULL);
12511827799SChris Bieneman 
12611827799SChris Bieneman     if (num_events < 0) {
12711827799SChris Bieneman       err.SetError(errno, DNBError::MachKernel);
12811827799SChris Bieneman       err.LogThreaded("error: kevent() failed.");
12911827799SChris Bieneman     }
13011827799SChris Bieneman 
13111827799SChris Bieneman     for (int i = 0; i < num_events; ++i) {
13211827799SChris Bieneman       auto sock_fd = event_list[i].ident;
13311827799SChris Bieneman       auto socket_pair = sockets.find(sock_fd);
13411827799SChris Bieneman       if (socket_pair == sockets.end())
13511827799SChris Bieneman         continue;
13611827799SChris Bieneman 
13711827799SChris Bieneman       lldb_private::SocketAddress &addr_in = socket_pair->second;
13811827799SChris Bieneman       lldb_private::SocketAddress accept_addr;
13911827799SChris Bieneman       socklen_t sa_len = accept_addr.GetMaxLength();
14011827799SChris Bieneman       m_fd = ::accept(sock_fd, &accept_addr.sockaddr(), &sa_len);
14111827799SChris Bieneman 
14211827799SChris Bieneman       if (m_fd == -1) {
14330fdc8d8SChris Lattner         err.SetError(errno, DNBError::POSIX);
14411827799SChris Bieneman         err.LogThreaded("error: Socket accept failed.");
14511827799SChris Bieneman       }
14630fdc8d8SChris Lattner 
14711827799SChris Bieneman       if (addr_in.IsAnyAddr())
148107e6942SPavel Labath         accept_connection = true;
149107e6942SPavel Labath       else {
15011827799SChris Bieneman         if (accept_addr == addr_in)
151107e6942SPavel Labath           accept_connection = true;
15211827799SChris Bieneman         else {
153107e6942SPavel Labath           ::close(m_fd);
154107e6942SPavel Labath           m_fd = -1;
15511827799SChris Bieneman           ::fprintf(
15611827799SChris Bieneman               stderr,
15711827799SChris Bieneman               "error: rejecting incoming connection from %s (expecting %s)\n",
15811827799SChris Bieneman               accept_addr.GetIPAddress().c_str(),
15911827799SChris Bieneman               addr_in.GetIPAddress().c_str());
16011827799SChris Bieneman           DNBLogThreaded("error: rejecting connection from %s (expecting %s)\n",
16111827799SChris Bieneman                          accept_addr.GetIPAddress().c_str(),
16211827799SChris Bieneman                          addr_in.GetIPAddress().c_str());
1637dc58b23SChris Bieneman           err.Clear();
164d01a2fa3SChris Bieneman         }
165107e6942SPavel Labath       }
166d01a2fa3SChris Bieneman     }
16711827799SChris Bieneman     if (err.Fail())
16811827799SChris Bieneman       break;
16911827799SChris Bieneman   }
17011827799SChris Bieneman   for (auto socket : sockets) {
17111827799SChris Bieneman     int ListenFd = socket.first;
17211827799SChris Bieneman     ClosePort(ListenFd, false);
17311827799SChris Bieneman   }
1748b82f087SGreg Clayton 
17511827799SChris Bieneman   if (err.Fail())
17630fdc8d8SChris Lattner     return rnb_err;
17711827799SChris Bieneman 
17830fdc8d8SChris Lattner   // Keep our TCP packets coming without any delays.
1798b82f087SGreg Clayton   SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
18030fdc8d8SChris Lattner 
18130fdc8d8SChris Lattner   return rnb_success;
18230fdc8d8SChris Lattner }
18330fdc8d8SChris Lattner 
Connect(const char * host,uint16_t port)184b9c1b51eSKate Stone rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) {
18511827799SChris Bieneman   auto result = rnb_err;
18695bf0fd3SGreg Clayton   Disconnect(false);
18795bf0fd3SGreg Clayton 
18811827799SChris Bieneman   auto addresses = lldb_private::SocketAddress::GetAddressInfo(
18911827799SChris Bieneman       host, NULL, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP);
19011827799SChris Bieneman 
19111827799SChris Bieneman   for (auto address : addresses) {
19211827799SChris Bieneman     m_fd = ::socket(address.GetFamily(), SOCK_STREAM, IPPROTO_TCP);
1938b82f087SGreg Clayton     if (m_fd == -1)
19411827799SChris Bieneman       continue;
19595bf0fd3SGreg Clayton 
19695bf0fd3SGreg Clayton     // Enable local address reuse
1978b82f087SGreg Clayton     SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1);
19895bf0fd3SGreg Clayton 
19911827799SChris Bieneman     address.SetPort(port);
20095bf0fd3SGreg Clayton 
20111827799SChris Bieneman     if (-1 == ::connect(m_fd, &address.sockaddr(), address.GetLength())) {
20295bf0fd3SGreg Clayton       Disconnect(false);
20311827799SChris Bieneman       continue;
20495bf0fd3SGreg Clayton     }
205107e6942SPavel Labath     SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1);
20611827799SChris Bieneman 
20711827799SChris Bieneman     result = rnb_success;
20811827799SChris Bieneman     break;
20911827799SChris Bieneman   }
21011827799SChris Bieneman   return result;
21195bf0fd3SGreg Clayton }
21295bf0fd3SGreg Clayton 
useFD(int fd)213b9c1b51eSKate Stone rnb_err_t RNBSocket::useFD(int fd) {
21442999a48SJason Molenda   if (fd < 0) {
21542999a48SJason Molenda     DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in.");
21642999a48SJason Molenda     return rnb_err;
21742999a48SJason Molenda   }
21842999a48SJason Molenda 
21942999a48SJason Molenda   m_fd = fd;
22042999a48SJason Molenda   return rnb_success;
22142999a48SJason Molenda }
22242999a48SJason Molenda 
22342999a48SJason Molenda #ifdef WITH_LOCKDOWN
ConnectToService()224b9c1b51eSKate Stone rnb_err_t RNBSocket::ConnectToService() {
22530fdc8d8SChris Lattner   DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME);
22630fdc8d8SChris Lattner   // Disconnect from any previous connections
22730fdc8d8SChris Lattner   Disconnect(false);
228b9c1b51eSKate Stone   if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) {
229b9c1b51eSKate Stone     DNBLogThreadedIf(LOG_RNB_COMM,
230b9c1b51eSKate Stone                      "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed");
23194379541SJason Molenda     m_fd = -1;
23230fdc8d8SChris Lattner     return rnb_not_connected;
23330fdc8d8SChris Lattner   }
2347eaf54d8SJason Molenda   m_fd = ::lockdown_get_socket(m_ld_conn);
235b9c1b51eSKate Stone   if (m_fd == -1) {
2367eaf54d8SJason Molenda     DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed");
2377eaf54d8SJason Molenda     return rnb_not_connected;
2387eaf54d8SJason Molenda   }
2398b82f087SGreg Clayton   m_fd_from_lockdown = true;
24030fdc8d8SChris Lattner   return rnb_success;
24130fdc8d8SChris Lattner }
24230fdc8d8SChris Lattner #endif
24330fdc8d8SChris Lattner 
OpenFile(const char * path)244b9c1b51eSKate Stone rnb_err_t RNBSocket::OpenFile(const char *path) {
24530fdc8d8SChris Lattner   DNBError err;
2468b82f087SGreg Clayton   m_fd = open(path, O_RDWR);
247b9c1b51eSKate Stone   if (m_fd == -1) {
24830fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
24930fdc8d8SChris Lattner     err.LogThreaded("can't open file '%s'", path);
25030fdc8d8SChris Lattner     return rnb_not_connected;
251b9c1b51eSKate Stone   } else {
25230fdc8d8SChris Lattner     struct termios stdin_termios;
25330fdc8d8SChris Lattner 
254b9c1b51eSKate Stone     if (::tcgetattr(m_fd, &stdin_termios) == 0) {
25530fdc8d8SChris Lattner       stdin_termios.c_lflag &= ~ECHO;   // Turn off echoing
25630fdc8d8SChris Lattner       stdin_termios.c_lflag &= ~ICANON; // Get one char at a time
2578b82f087SGreg Clayton       ::tcsetattr(m_fd, TCSANOW, &stdin_termios);
25830fdc8d8SChris Lattner     }
25930fdc8d8SChris Lattner   }
26030fdc8d8SChris Lattner   return rnb_success;
26130fdc8d8SChris Lattner }
26230fdc8d8SChris Lattner 
SetSocketOption(int fd,int level,int option_name,int option_value)263b9c1b51eSKate Stone int RNBSocket::SetSocketOption(int fd, int level, int option_name,
264b9c1b51eSKate Stone                                int option_value) {
265b9c1b51eSKate Stone   return ::setsockopt(fd, level, option_name, &option_value,
266b9c1b51eSKate Stone                       sizeof(option_value));
26730fdc8d8SChris Lattner }
26830fdc8d8SChris Lattner 
Disconnect(bool save_errno)269b9c1b51eSKate Stone rnb_err_t RNBSocket::Disconnect(bool save_errno) {
27042999a48SJason Molenda #ifdef WITH_LOCKDOWN
271b9c1b51eSKate Stone   if (m_fd_from_lockdown) {
2728b82f087SGreg Clayton     m_fd_from_lockdown = false;
2737eaf54d8SJason Molenda     m_fd = -1;
2742d512bcaSJim Ingham     lockdown_disconnect(m_ld_conn);
2757eaf54d8SJason Molenda     return rnb_success;
2767eaf54d8SJason Molenda   }
27742999a48SJason Molenda #endif
2788b82f087SGreg Clayton   return ClosePort(m_fd, save_errno);
27930fdc8d8SChris Lattner }
28030fdc8d8SChris Lattner 
Read(std::string & p)281b9c1b51eSKate Stone rnb_err_t RNBSocket::Read(std::string &p) {
28230fdc8d8SChris Lattner   char buf[1024];
28330fdc8d8SChris Lattner   p.clear();
28430fdc8d8SChris Lattner 
28530fdc8d8SChris Lattner   // Note that BUF is on the stack so we must be careful to keep any
28630fdc8d8SChris Lattner   // writes to BUF from overflowing or we'll have security issues.
28730fdc8d8SChris Lattner 
2888b82f087SGreg Clayton   if (m_fd == -1)
28930fdc8d8SChris Lattner     return rnb_err;
29030fdc8d8SChris Lattner 
291b9c1b51eSKate Stone   // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()",
292b9c1b51eSKate Stone   // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__);
29330fdc8d8SChris Lattner   DNBError err;
294ee2ed525SGreg Clayton   ssize_t bytesread = read(m_fd, buf, sizeof(buf));
29530fdc8d8SChris Lattner   if (bytesread <= 0)
29630fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
29730fdc8d8SChris Lattner   else
29830fdc8d8SChris Lattner     p.append(buf, bytesread);
29930fdc8d8SChris Lattner 
30030fdc8d8SChris Lattner   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
301b9c1b51eSKate Stone     err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf),
302b9c1b51eSKate Stone                     (uint64_t)bytesread);
30330fdc8d8SChris Lattner 
304b9c1b51eSKate Stone   // Our port went away - we have to mark this so IsConnected will return the
305b9c1b51eSKate Stone   // truth.
306b9c1b51eSKate Stone   if (bytesread == 0) {
3078b82f087SGreg Clayton     m_fd = -1;
30830fdc8d8SChris Lattner     return rnb_not_connected;
309b9c1b51eSKate Stone   } else if (bytesread == -1) {
3108b82f087SGreg Clayton     m_fd = -1;
31130fdc8d8SChris Lattner     return rnb_err;
31230fdc8d8SChris Lattner   }
31330fdc8d8SChris Lattner   // Strip spaces from the end of the buffer
31430fdc8d8SChris Lattner   while (!p.empty() && isspace(p[p.size() - 1]))
31530fdc8d8SChris Lattner     p.erase(p.size() - 1);
31630fdc8d8SChris Lattner 
31730fdc8d8SChris Lattner   // Most data in the debugserver packets valid printable characters...
31830fdc8d8SChris Lattner   DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str());
31930fdc8d8SChris Lattner   return rnb_success;
32030fdc8d8SChris Lattner }
32130fdc8d8SChris Lattner 
Write(const void * buffer,size_t length)322b9c1b51eSKate Stone rnb_err_t RNBSocket::Write(const void *buffer, size_t length) {
3238b82f087SGreg Clayton   if (m_fd == -1)
32430fdc8d8SChris Lattner     return rnb_err;
32530fdc8d8SChris Lattner 
32630fdc8d8SChris Lattner   DNBError err;
327ee2ed525SGreg Clayton   ssize_t bytessent = write(m_fd, buffer, length);
32830fdc8d8SChris Lattner   if (bytessent < 0)
32930fdc8d8SChris Lattner     err.SetError(errno, DNBError::POSIX);
33030fdc8d8SChris Lattner 
33130fdc8d8SChris Lattner   if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM))
332b9c1b51eSKate Stone     err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i",
333b9c1b51eSKate Stone                     m_fd, buffer, length, (uint64_t)bytessent);
33430fdc8d8SChris Lattner 
33530fdc8d8SChris Lattner   if (bytessent < 0)
33630fdc8d8SChris Lattner     return rnb_err;
33730fdc8d8SChris Lattner 
338a026de05SBruce Mitchener   if ((size_t)bytessent != length)
33930fdc8d8SChris Lattner     return rnb_err;
34030fdc8d8SChris Lattner 
341b9c1b51eSKate Stone   DNBLogThreadedIf(
342b9c1b51eSKate Stone       LOG_RNB_PACKETS, "putpkt: %*s", (int)length,
34307d95614SVedant Kumar       (const char *)
344b9c1b51eSKate Stone           buffer); // All data is string based in debugserver, so this is safe
34507d95614SVedant Kumar   DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length,
34607d95614SVedant Kumar                    (const char *)buffer);
34730fdc8d8SChris Lattner 
34830fdc8d8SChris Lattner   return rnb_success;
34930fdc8d8SChris Lattner }
35030fdc8d8SChris Lattner 
ClosePort(int & fd,bool save_errno)351b9c1b51eSKate Stone rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) {
35230fdc8d8SChris Lattner   int close_err = 0;
353b9c1b51eSKate Stone   if (fd > 0) {
35430fdc8d8SChris Lattner     errno = 0;
35530fdc8d8SChris Lattner     close_err = close(fd);
35630fdc8d8SChris Lattner     fd = -1;
35730fdc8d8SChris Lattner   }
35830fdc8d8SChris Lattner   return close_err != 0 ? rnb_err : rnb_success;
35930fdc8d8SChris Lattner }
360