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