1 /***********************************************************************************************************************************
2 Server Test Harness
3 ***********************************************************************************************************************************/
4 #include "build.auto.h"
5 
6 #include <arpa/inet.h>
7 #include <netinet/in.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 #include <unistd.h>
11 
12 #include <openssl/conf.h>
13 #include <openssl/ssl.h>
14 
15 #include "common/crypto/common.h"
16 #include "common/error.h"
17 #include "common/io/socket/common.h"
18 #include "common/io/socket/session.h"
19 #include "common/io/tls/session.h"
20 #include "common/log.h"
21 #include "common/type/buffer.h"
22 #include "common/type/json.h"
23 #include "common/wait.h"
24 
25 #include "common/harnessDebug.h"
26 #include "common/harnessServer.h"
27 #include "common/harnessTest.h"
28 
29 /***********************************************************************************************************************************
30 Command enum
31 ***********************************************************************************************************************************/
32 typedef enum
33 {
34     hrnServerCmdAbort,
35     hrnServerCmdAccept,
36     hrnServerCmdClose,
37     hrnServerCmdDone,
38     hrnServerCmdExpect,
39     hrnServerCmdReply,
40     hrnServerCmdSleep,
41 } HrnServerCmd;
42 
43 /***********************************************************************************************************************************
44 Constants
45 ***********************************************************************************************************************************/
46 #define HRN_SERVER_HOST                                             "tls.test.pgbackrest.org"
47 #define HRN_SERVER_FAKE_CERT_PATH                                   "/etc/fake-cert"
48 #define HRN_SERVER_FAKE_KEY_FILE                                    HRN_SERVER_FAKE_CERT_PATH "/pgbackrest-test.key"
49 #define HRN_SERVER_FAKE_CERT_FILE                                   HRN_SERVER_FAKE_CERT_PATH "/pgbackrest-test.crt"
50 
51 /***********************************************************************************************************************************
52 Send commands to the server
53 ***********************************************************************************************************************************/
54 static void
hrnServerScriptCommand(IoWrite * write,HrnServerCmd cmd,const Variant * data)55 hrnServerScriptCommand(IoWrite *write, HrnServerCmd cmd, const Variant *data)
56 {
57     FUNCTION_HARNESS_BEGIN();
58         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
59         FUNCTION_HARNESS_PARAM(ENUM, cmd);
60         FUNCTION_HARNESS_PARAM(VARIANT, data);
61     FUNCTION_HARNESS_END();
62 
63     ASSERT(write != NULL);
64 
65     ioWriteStrLine(write, jsonFromUInt(cmd));
66     ioWriteStrLine(write, jsonFromVar(data));
67     ioWriteFlush(write);
68 
69     FUNCTION_HARNESS_RETURN_VOID();
70 }
71 
72 /**********************************************************************************************************************************/
hrnServerScriptBegin(IoWrite * write)73 IoWrite *hrnServerScriptBegin(IoWrite *write)
74 {
75     FUNCTION_HARNESS_BEGIN();
76         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
77     FUNCTION_HARNESS_END();
78 
79     ASSERT(write != NULL);
80 
81     FUNCTION_HARNESS_RETURN(IO_WRITE, write);
82 }
83 
hrnServerScriptEnd(IoWrite * write)84 void hrnServerScriptEnd(IoWrite *write)
85 {
86     FUNCTION_HARNESS_BEGIN();
87         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
88     FUNCTION_HARNESS_END();
89 
90     ASSERT(write != NULL);
91 
92     hrnServerScriptCommand(write, hrnServerCmdDone, NULL);
93 
94     FUNCTION_HARNESS_RETURN_VOID();
95 }
96 
97 /**********************************************************************************************************************************/
98 void
hrnServerScriptAbort(IoWrite * write)99 hrnServerScriptAbort(IoWrite *write)
100 {
101     FUNCTION_HARNESS_BEGIN();
102         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
103     FUNCTION_HARNESS_END();
104 
105     hrnServerScriptCommand(write, hrnServerCmdAbort, NULL);
106 
107     FUNCTION_HARNESS_RETURN_VOID();
108 }
109 
110 void
hrnServerScriptAccept(IoWrite * write)111 hrnServerScriptAccept(IoWrite *write)
112 {
113     FUNCTION_HARNESS_BEGIN();
114         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
115     FUNCTION_HARNESS_END();
116 
117     hrnServerScriptCommand(write, hrnServerCmdAccept, NULL);
118 
119     FUNCTION_HARNESS_RETURN_VOID();
120 }
121 
122 void
hrnServerScriptClose(IoWrite * write)123 hrnServerScriptClose(IoWrite *write)
124 {
125     FUNCTION_HARNESS_BEGIN();
126         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
127     FUNCTION_HARNESS_END();
128 
129     hrnServerScriptCommand(write, hrnServerCmdClose, NULL);
130 
131     FUNCTION_HARNESS_RETURN_VOID();
132 }
133 
134 void
hrnServerScriptExpect(IoWrite * write,const String * data)135 hrnServerScriptExpect(IoWrite *write, const String *data)
136 {
137     FUNCTION_HARNESS_BEGIN();
138         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
139         FUNCTION_HARNESS_PARAM(STRING, data);
140     FUNCTION_HARNESS_END();
141 
142     ASSERT(data != NULL);
143 
144     hrnServerScriptCommand(write, hrnServerCmdExpect, VARSTR(data));
145 
146     FUNCTION_HARNESS_RETURN_VOID();
147 }
148 
149 void
hrnServerScriptExpectZ(IoWrite * write,const char * data)150 hrnServerScriptExpectZ(IoWrite *write, const char *data)
151 {
152     FUNCTION_HARNESS_BEGIN();
153         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
154         FUNCTION_HARNESS_PARAM(STRINGZ, data);
155     FUNCTION_HARNESS_END();
156 
157     ASSERT(data != NULL);
158 
159     hrnServerScriptCommand(write, hrnServerCmdExpect, VARSTRZ(data));
160 
161     FUNCTION_HARNESS_RETURN_VOID();
162 }
163 
164 void
hrnServerScriptReply(IoWrite * write,const String * data)165 hrnServerScriptReply(IoWrite *write, const String *data)
166 {
167     FUNCTION_HARNESS_BEGIN();
168         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
169         FUNCTION_HARNESS_PARAM(STRING, data);
170     FUNCTION_HARNESS_END();
171 
172     ASSERT(data != NULL);
173 
174     hrnServerScriptCommand(write, hrnServerCmdReply, VARSTR(data));
175 
176     FUNCTION_HARNESS_RETURN_VOID();
177 }
178 
179 void
hrnServerScriptReplyZ(IoWrite * write,const char * data)180 hrnServerScriptReplyZ(IoWrite *write, const char *data)
181 {
182     FUNCTION_HARNESS_BEGIN();
183         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
184         FUNCTION_HARNESS_PARAM(STRINGZ, data);
185     FUNCTION_HARNESS_END();
186 
187     ASSERT(data != NULL);
188 
189     hrnServerScriptCommand(write, hrnServerCmdReply, VARSTRZ(data));
190 
191     FUNCTION_HARNESS_RETURN_VOID();
192 }
193 
194 void
hrnServerScriptSleep(IoWrite * write,TimeMSec sleepMs)195 hrnServerScriptSleep(IoWrite *write, TimeMSec sleepMs)
196 {
197     FUNCTION_HARNESS_BEGIN();
198         FUNCTION_HARNESS_PARAM(IO_WRITE, write);
199         FUNCTION_HARNESS_PARAM(TIME_MSEC, sleepMs);
200     FUNCTION_HARNESS_END();
201 
202     ASSERT(sleepMs > 0);
203 
204     hrnServerScriptCommand(write, hrnServerCmdSleep, VARUINT64(sleepMs));
205 
206     FUNCTION_HARNESS_RETURN_VOID();
207 }
208 
209 /**********************************************************************************************************************************/
hrnServerRun(IoRead * read,HrnServerProtocol protocol,HrnServerRunParam param)210 void hrnServerRun(IoRead *read, HrnServerProtocol protocol, HrnServerRunParam param)
211 {
212     FUNCTION_HARNESS_BEGIN();
213         FUNCTION_HARNESS_PARAM(IO_READ, read);
214         FUNCTION_HARNESS_PARAM(ENUM, protocol);
215         FUNCTION_HARNESS_PARAM(UINT, param.port);
216         FUNCTION_HARNESS_PARAM(STRING, param.certificate);
217         FUNCTION_HARNESS_PARAM(STRING, param.key);
218     FUNCTION_HARNESS_END();
219 
220     ASSERT(read != NULL);
221 
222     // Set port to index 0 if not specified
223     if (param.port == 0)
224         param.port = hrnServerPort(0);
225 
226     // Add test hosts
227     if (testContainer())
228     {
229         if (system("echo \"127.0.0.1 " HRN_SERVER_HOST "\" | sudo tee -a /etc/hosts > /dev/null") != 0)
230             THROW(AssertError, "unable to add test host to /etc/hosts");
231     }
232 
233     // Initialize ssl and create a context
234     SSL_CTX *serverContext = NULL;
235 
236     if (protocol == hrnServerProtocolTls)
237     {
238         ASSERT((param.certificate != NULL && param.key != NULL) || (param.certificate == NULL && param.key == NULL));
239 
240         // If certificate and key are not set then use defaults
241         if (param.certificate == NULL)
242         {
243             // If running in a container use the installed certificate
244             if (testContainer())
245             {
246                 param.certificate = strNewZ(HRN_SERVER_FAKE_CERT_FILE);
247                 param.key = strNewZ(HRN_SERVER_FAKE_KEY_FILE);
248             }
249             // Else use a certificate from the test path -- tests will need to disable verify
250             else
251             {
252                 param.certificate = strNewFmt("%s/" HRN_SERVER_CERT_PREFIX ".crt", hrnPathRepo());
253                 param.key = strNewFmt("%s/" HRN_SERVER_CERT_PREFIX ".key", hrnPathRepo());
254             }
255         }
256 
257         // Initialize TLS
258         cryptoInit();
259 
260         const SSL_METHOD *method = SSLv23_method();
261         cryptoError(method == NULL, "unable to load TLS method");
262 
263         serverContext = SSL_CTX_new(method);
264         cryptoError(serverContext == NULL, "unable to create TLS context");
265 
266         // Configure the context by setting key and cert
267         cryptoError(
268             SSL_CTX_use_certificate_file(serverContext, strZ(param.certificate), SSL_FILETYPE_PEM) <= 0,
269             "unable to load server certificate");
270         cryptoError(
271             SSL_CTX_use_PrivateKey_file(serverContext, strZ(param.key), SSL_FILETYPE_PEM) <= 0,
272             "unable to load server private key");
273     }
274 
275     // Create the socket
276     int serverSocket;
277 
278     struct sockaddr_in address;
279 
280     address.sin_family = AF_INET;
281     address.sin_port = htons((uint16_t)param.port);
282     address.sin_addr.s_addr = htonl(INADDR_ANY);
283 
284     if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
285         THROW_SYS_ERROR(AssertError, "unable to create socket");
286 
287     // Set the address as reusable so we can bind again in the same process for testing
288     int reuseAddr = 1;
289     setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
290 
291     // Bind the address.  It might take a bit to bind if another process was recently using it so retry a few times.
292     Wait *wait = waitNew(2000);
293     int result;
294 
295     do
296     {
297         result = bind(serverSocket, (struct sockaddr *)&address, sizeof(address));
298     }
299     while (result < 0 && waitMore(wait));
300 
301     if (result < 0)
302         THROW_SYS_ERROR(AssertError, "unable to bind socket");
303 
304     // Listen for client connections
305     if (listen(serverSocket, 1) < 0)
306         THROW_SYS_ERROR(AssertError, "unable to listen on socket");
307 
308     // Loop until no more commands
309     IoSession *serverSession = NULL;
310     bool done = false;
311 
312     do
313     {
314         HrnServerCmd cmd = jsonToUInt(ioReadLine(read));
315         const Variant *data = jsonToVar(ioReadLine(read));
316 
317         switch (cmd)
318         {
319             case hrnServerCmdAbort:
320             {
321                 // Only makes since to abort in TLS, otherwise it is just a close
322                 ASSERT(protocol == hrnServerProtocolTls);
323 
324                 ioSessionFree(serverSession);
325                 serverSession = NULL;
326 
327                 break;
328             }
329 
330             case hrnServerCmdAccept:
331             {
332                 // Accept the socket connection
333                 struct sockaddr_in addr;
334                 unsigned int len = sizeof(addr);
335 
336                 int testClientSocket = accept(serverSocket, (struct sockaddr *)&addr, &len);
337 
338                 if (testClientSocket < 0)
339                     THROW_SYS_ERROR(AssertError, "unable to accept socket");
340 
341                 // Create socket session
342                 sckOptionSet(testClientSocket);
343                 serverSession = sckSessionNew(ioSessionRoleServer, testClientSocket, STRDEF("localhost"), param.port, 5000);
344 
345                 // Start TLS if requested
346                 if (protocol == hrnServerProtocolTls)
347                 {
348                     SSL *testClientSSL = SSL_new(serverContext);
349                     serverSession = tlsSessionNew(testClientSSL, serverSession, 5000);
350                 }
351 
352                 break;
353             }
354 
355             case hrnServerCmdClose:
356             {
357                 if (serverSession == NULL)
358                     THROW(AssertError, "session is already closed");
359 
360                 ioSessionClose(serverSession);
361                 ioSessionFree(serverSession);
362                 serverSession = NULL;
363 
364                 break;
365             }
366 
367             case hrnServerCmdDone:
368                 done = true;
369                 break;
370 
371             case hrnServerCmdExpect:
372             {
373                 const String *expected = varStr(data);
374 
375                 // Read as much as possible
376                 Buffer *buffer = bufNew(strSize(expected));
377 
378                 TRY_BEGIN()
379                 {
380                     ioRead(ioSessionIoRead(serverSession), buffer);
381                 }
382                 CATCH(FileReadError)
383                 {
384                     // If nothing was read then throw the original error
385                     if (bufEmpty(buffer))
386                         THROW_FMT(AssertError, "server expected '%s' but got EOF", strZ(expected));
387                 }
388                 TRY_END();
389 
390                 // Treat any ? characters as wildcards so variable elements (e.g. auth hashes) can be ignored
391                 String *actual = strNewBuf(buffer);
392 
393                 for (unsigned int actualIdx = 0; actualIdx < strSize(actual); actualIdx++)
394                 {
395                     if (strZ(expected)[actualIdx] == '?')
396                         ((char *)strZ(actual))[actualIdx] = '?';
397                 }
398 
399                 // Error if actual does not match expected
400                 if (!strEq(actual, expected))
401                     THROW_FMT(AssertError, "server expected '%s' but got '%s'", strZ(expected), strZ(actual));
402 
403                 break;
404             }
405 
406             case hrnServerCmdReply:
407                 ioWrite(ioSessionIoWrite(serverSession), BUFSTR(varStr(data)));
408                 ioWriteFlush(ioSessionIoWrite(serverSession));
409                 break;
410 
411             case hrnServerCmdSleep:
412                 sleepMSec(varUInt64Force(data));
413                 break;
414         }
415     }
416     while (!done);
417 
418     // Free TLS context
419     if (protocol == hrnServerProtocolTls)
420         SSL_CTX_free(serverContext);
421 
422     FUNCTION_HARNESS_RETURN_VOID();
423 }
424 
425 /**********************************************************************************************************************************/
hrnServerHost(void)426 const String *hrnServerHost(void)
427 {
428     return strNewZ(testContainer() ? HRN_SERVER_HOST : "127.0.0.1");
429 }
430 
431 /**********************************************************************************************************************************/
hrnServerPort(unsigned int portIdx)432 unsigned int hrnServerPort(unsigned int portIdx)
433 {
434     ASSERT(portIdx < HRN_SERVER_PORT_MAX);
435 
436     return 44443 + (HRN_SERVER_PORT_MAX * testIdx()) + portIdx;
437 }
438