https_client.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "libnetdata/libnetdata.h"
  3. #include "https_client.h"
  4. #include "aclk_util.h"
  5. #include "daemon/global_statistics.h"
  6. static const char *http_req_type_to_str(http_req_type_t req) {
  7. switch (req) {
  8. case HTTP_REQ_GET:
  9. return "GET";
  10. case HTTP_REQ_POST:
  11. return "POST";
  12. case HTTP_REQ_CONNECT:
  13. return "CONNECT";
  14. default:
  15. return "unknown";
  16. }
  17. }
  18. #define TRANSFER_ENCODING_CHUNKED (-2)
  19. void http_parse_ctx_create(http_parse_ctx *ctx)
  20. {
  21. ctx->state = HTTP_PARSE_INITIAL;
  22. ctx->content_length = -1;
  23. ctx->http_code = 0;
  24. ctx->headers = c_rhash_new(0);
  25. ctx->flags = HTTP_PARSE_FLAGS_DEFAULT;
  26. }
  27. void http_parse_ctx_destroy(http_parse_ctx *ctx)
  28. {
  29. c_rhash_iter_t iter;
  30. const char *key;
  31. c_rhash_iter_t_initialize(&iter);
  32. while ( !c_rhash_iter_str_keys(ctx->headers, &iter, &key) ) {
  33. void *val;
  34. c_rhash_get_ptr_by_str(ctx->headers, key, &val);
  35. freez(val);
  36. }
  37. c_rhash_destroy(ctx->headers);
  38. }
  39. #define POLL_TO_MS 100
  40. #define HTTP_LINE_TERM "\x0D\x0A"
  41. #define RESP_PROTO "HTTP/1.1 "
  42. #define HTTP_KEYVAL_SEPARATOR ": "
  43. #define HTTP_HDR_BUFFER_SIZE 1024
  44. #define PORT_STR_MAX_BYTES 12
  45. static int process_http_hdr(http_parse_ctx *parse_ctx, const char *key, const char *val)
  46. {
  47. // currently we care only about specific headers
  48. // we can skip the rest
  49. if (parse_ctx->content_length < 0 && !strcmp("content-length", key)) {
  50. if (parse_ctx->content_length == TRANSFER_ENCODING_CHUNKED) {
  51. netdata_log_error("Content-length and transfer-encoding: chunked headers are mutually exclusive");
  52. return 1;
  53. }
  54. if (parse_ctx->content_length != -1) {
  55. netdata_log_error("Duplicate content-length header");
  56. return 1;
  57. }
  58. parse_ctx->content_length = str2u(val);
  59. if (parse_ctx->content_length < 0) {
  60. netdata_log_error("Invalid content-length %d", parse_ctx->content_length);
  61. return 1;
  62. }
  63. return 0;
  64. }
  65. if (!strcmp("transfer-encoding", key)) {
  66. if (!strcmp("chunked", val)) {
  67. if (parse_ctx->content_length != -1) {
  68. netdata_log_error("Content-length and transfer-encoding: chunked headers are mutually exclusive");
  69. return 1;
  70. }
  71. parse_ctx->content_length = TRANSFER_ENCODING_CHUNKED;
  72. }
  73. return 0;
  74. }
  75. char *val_cpy = strdupz(val);
  76. c_rhash_insert_str_ptr(parse_ctx->headers, key, val_cpy);
  77. return 0;
  78. }
  79. const char *get_http_header_by_name(http_parse_ctx *ctx, const char *name)
  80. {
  81. const char *ret;
  82. if (c_rhash_get_ptr_by_str(ctx->headers, name, (void**)&ret))
  83. return NULL;
  84. return ret;
  85. }
  86. static int parse_http_hdr(rbuf_t buf, http_parse_ctx *parse_ctx)
  87. {
  88. int idx, idx_end;
  89. char buf_key[HTTP_HDR_BUFFER_SIZE];
  90. char buf_val[HTTP_HDR_BUFFER_SIZE];
  91. char *ptr = buf_key;
  92. if (!rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx_end)) {
  93. netdata_log_error("CRLF expected");
  94. return 1;
  95. }
  96. char *separator = rbuf_find_bytes(buf, HTTP_KEYVAL_SEPARATOR, strlen(HTTP_KEYVAL_SEPARATOR), &idx);
  97. if (!separator) {
  98. netdata_log_error("Missing Key/Value separator");
  99. return 1;
  100. }
  101. if (idx >= HTTP_HDR_BUFFER_SIZE) {
  102. netdata_log_error("Key name is too long");
  103. return 1;
  104. }
  105. rbuf_pop(buf, buf_key, idx);
  106. buf_key[idx] = 0;
  107. rbuf_bump_tail(buf, strlen(HTTP_KEYVAL_SEPARATOR));
  108. idx_end -= strlen(HTTP_KEYVAL_SEPARATOR) + idx;
  109. if (idx_end >= HTTP_HDR_BUFFER_SIZE) {
  110. netdata_log_error("Value of key \"%s\" too long", buf_key);
  111. return 1;
  112. }
  113. rbuf_pop(buf, buf_val, idx_end);
  114. buf_val[idx_end] = 0;
  115. for (ptr = buf_key; *ptr; ptr++)
  116. *ptr = tolower(*ptr);
  117. if (process_http_hdr(parse_ctx, buf_key, buf_val))
  118. return 1;
  119. return 0;
  120. }
  121. static inline void chunked_response_buffer_grow_by(http_parse_ctx *parse_ctx, size_t size)
  122. {
  123. if (unlikely(parse_ctx->chunked_response_size == 0)) {
  124. parse_ctx->chunked_response = mallocz(size);
  125. parse_ctx->chunked_response_size = size;
  126. return;
  127. }
  128. parse_ctx->chunked_response = reallocz((void *)parse_ctx->chunked_response, parse_ctx->chunked_response_size + size);
  129. parse_ctx->chunked_response_size += size;
  130. }
  131. static int process_chunked_content(rbuf_t buf, http_parse_ctx *parse_ctx)
  132. {
  133. int idx;
  134. size_t bytes_to_copy;
  135. do {
  136. switch (parse_ctx->chunked_content_state) {
  137. case CHUNKED_CONTENT_CHUNK_SIZE:
  138. if (!rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx)) {
  139. if (rbuf_bytes_available(buf) >= rbuf_get_capacity(buf))
  140. return HTTP_PARSE_ERROR;
  141. return HTTP_PARSE_NEED_MORE_DATA;
  142. }
  143. if (idx == 0) {
  144. parse_ctx->chunked_content_state = CHUNKED_CONTENT_FINAL_CRLF;
  145. continue;
  146. }
  147. if (idx >= HTTP_HDR_BUFFER_SIZE) {
  148. netdata_log_error("Chunk size is too long");
  149. return HTTP_PARSE_ERROR;
  150. }
  151. char buf_size[HTTP_HDR_BUFFER_SIZE];
  152. rbuf_pop(buf, buf_size, idx);
  153. buf_size[idx] = 0;
  154. long chunk_size = strtol(buf_size, NULL, 16);
  155. if (chunk_size < 0 || chunk_size == LONG_MAX) {
  156. netdata_log_error("Chunk size out of range");
  157. return HTTP_PARSE_ERROR;
  158. }
  159. parse_ctx->chunk_size = chunk_size;
  160. if (parse_ctx->chunk_size == 0) {
  161. if (errno == EINVAL) {
  162. netdata_log_error("Invalid chunk size");
  163. return HTTP_PARSE_ERROR;
  164. }
  165. parse_ctx->chunked_content_state = CHUNKED_CONTENT_CHUNK_END_CRLF;
  166. continue;
  167. }
  168. parse_ctx->chunk_got = 0;
  169. chunked_response_buffer_grow_by(parse_ctx, parse_ctx->chunk_size);
  170. rbuf_bump_tail(buf, strlen(HTTP_LINE_TERM));
  171. parse_ctx->chunked_content_state = CHUNKED_CONTENT_CHUNK_DATA;
  172. // fallthrough
  173. case CHUNKED_CONTENT_CHUNK_DATA:
  174. if (!(bytes_to_copy = rbuf_bytes_available(buf)))
  175. return HTTP_PARSE_NEED_MORE_DATA;
  176. if (bytes_to_copy > parse_ctx->chunk_size - parse_ctx->chunk_got)
  177. bytes_to_copy = parse_ctx->chunk_size - parse_ctx->chunk_got;
  178. rbuf_pop(buf, parse_ctx->chunked_response + parse_ctx->chunked_response_written, bytes_to_copy);
  179. parse_ctx->chunk_got += bytes_to_copy;
  180. parse_ctx->chunked_response_written += bytes_to_copy;
  181. if (parse_ctx->chunk_got != parse_ctx->chunk_size)
  182. continue;
  183. parse_ctx->chunked_content_state = CHUNKED_CONTENT_CHUNK_END_CRLF;
  184. // fallthrough
  185. case CHUNKED_CONTENT_FINAL_CRLF:
  186. case CHUNKED_CONTENT_CHUNK_END_CRLF:
  187. if (rbuf_bytes_available(buf) < strlen(HTTP_LINE_TERM))
  188. return HTTP_PARSE_NEED_MORE_DATA;
  189. char buf_crlf[strlen(HTTP_LINE_TERM)];
  190. rbuf_pop(buf, buf_crlf, strlen(HTTP_LINE_TERM));
  191. if (memcmp(buf_crlf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM))) {
  192. netdata_log_error("CRLF expected");
  193. return HTTP_PARSE_ERROR;
  194. }
  195. if (parse_ctx->chunked_content_state == CHUNKED_CONTENT_FINAL_CRLF) {
  196. if (parse_ctx->chunked_response_size != parse_ctx->chunked_response_written)
  197. netdata_log_error("Chunked response size mismatch");
  198. chunked_response_buffer_grow_by(parse_ctx, 1);
  199. parse_ctx->chunked_response[parse_ctx->chunked_response_written] = 0;
  200. return HTTP_PARSE_SUCCESS;
  201. }
  202. if (parse_ctx->chunk_size == 0) {
  203. parse_ctx->chunked_content_state = CHUNKED_CONTENT_FINAL_CRLF;
  204. continue;
  205. }
  206. parse_ctx->chunked_content_state = CHUNKED_CONTENT_CHUNK_SIZE;
  207. continue;
  208. }
  209. } while(1);
  210. }
  211. http_parse_rc parse_http_response(rbuf_t buf, http_parse_ctx *parse_ctx)
  212. {
  213. int idx;
  214. char rc[4];
  215. do {
  216. if (parse_ctx->state != HTTP_PARSE_CONTENT && !rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx))
  217. return HTTP_PARSE_NEED_MORE_DATA;
  218. switch (parse_ctx->state) {
  219. case HTTP_PARSE_INITIAL:
  220. if (rbuf_memcmp_n(buf, RESP_PROTO, strlen(RESP_PROTO))) {
  221. netdata_log_error("Expected response to start with \"%s\"", RESP_PROTO);
  222. return HTTP_PARSE_ERROR;
  223. }
  224. rbuf_bump_tail(buf, strlen(RESP_PROTO));
  225. if (rbuf_pop(buf, rc, 4) != 4) {
  226. netdata_log_error("Expected HTTP status code");
  227. return HTTP_PARSE_ERROR;
  228. }
  229. if (rc[3] != ' ') {
  230. netdata_log_error("Expected space after HTTP return code");
  231. return HTTP_PARSE_ERROR;
  232. }
  233. rc[3] = 0;
  234. parse_ctx->http_code = atoi(rc);
  235. if (parse_ctx->http_code < 100 || parse_ctx->http_code >= 600) {
  236. netdata_log_error("HTTP code not in range 100 to 599");
  237. return HTTP_PARSE_ERROR;
  238. }
  239. rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx);
  240. rbuf_bump_tail(buf, idx + strlen(HTTP_LINE_TERM));
  241. parse_ctx->state = HTTP_PARSE_HEADERS;
  242. break;
  243. case HTTP_PARSE_HEADERS:
  244. if (!idx) {
  245. parse_ctx->state = HTTP_PARSE_CONTENT;
  246. rbuf_bump_tail(buf, strlen(HTTP_LINE_TERM));
  247. break;
  248. }
  249. if (parse_http_hdr(buf, parse_ctx))
  250. return HTTP_PARSE_ERROR;
  251. rbuf_find_bytes(buf, HTTP_LINE_TERM, strlen(HTTP_LINE_TERM), &idx);
  252. rbuf_bump_tail(buf, idx + strlen(HTTP_LINE_TERM));
  253. break;
  254. case HTTP_PARSE_CONTENT:
  255. // replies like CONNECT etc. do not have content
  256. if (parse_ctx->content_length == TRANSFER_ENCODING_CHUNKED)
  257. return process_chunked_content(buf, parse_ctx);
  258. if (parse_ctx->content_length < 0)
  259. return HTTP_PARSE_SUCCESS;
  260. if (parse_ctx->flags & HTTP_PARSE_FLAG_DONT_WAIT_FOR_CONTENT)
  261. return HTTP_PARSE_SUCCESS;
  262. if (rbuf_bytes_available(buf) >= (size_t)parse_ctx->content_length)
  263. return HTTP_PARSE_SUCCESS;
  264. return HTTP_PARSE_NEED_MORE_DATA;
  265. }
  266. } while(1);
  267. }
  268. typedef struct https_req_ctx {
  269. https_req_t *request;
  270. int sock;
  271. rbuf_t buf_rx;
  272. struct pollfd poll_fd;
  273. SSL_CTX *ssl_ctx;
  274. SSL *ssl;
  275. size_t written;
  276. http_parse_ctx parse_ctx;
  277. time_t req_start_time;
  278. } https_req_ctx_t;
  279. static int https_req_check_timedout(https_req_ctx_t *ctx) {
  280. if (now_realtime_sec() > ctx->req_start_time + ctx->request->timeout_s) {
  281. netdata_log_error("request timed out");
  282. return 1;
  283. }
  284. return 0;
  285. }
  286. static char *_ssl_err_tos(int err)
  287. {
  288. switch(err){
  289. case SSL_ERROR_SSL:
  290. return "SSL_ERROR_SSL";
  291. case SSL_ERROR_WANT_READ:
  292. return "SSL_ERROR_WANT_READ";
  293. case SSL_ERROR_WANT_WRITE:
  294. return "SSL_ERROR_WANT_WRITE";
  295. case SSL_ERROR_NONE:
  296. return "SSL_ERROR_NONE";
  297. case SSL_ERROR_ZERO_RETURN:
  298. return "SSL_ERROR_ZERO_RETURN";
  299. case SSL_ERROR_WANT_CONNECT:
  300. return "SSL_ERROR_WANT_CONNECT";
  301. case SSL_ERROR_WANT_ACCEPT:
  302. return "SSL_ERROR_WANT_ACCEPT";
  303. }
  304. return "Unknown!!!";
  305. }
  306. static int socket_write_all(https_req_ctx_t *ctx, char *data, size_t data_len) {
  307. ctx->written = 0;
  308. ctx->poll_fd.events = POLLOUT;
  309. do {
  310. int ret = poll(&ctx->poll_fd, 1, POLL_TO_MS);
  311. if (ret < 0) {
  312. netdata_log_error("poll error");
  313. return 1;
  314. }
  315. if (ret == 0) {
  316. if (https_req_check_timedout(ctx)) {
  317. netdata_log_error("Poll timed out");
  318. return 2;
  319. }
  320. continue;
  321. }
  322. ret = write(ctx->sock, &data[ctx->written], data_len - ctx->written);
  323. if (ret > 0) {
  324. ctx->written += ret;
  325. } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
  326. netdata_log_error("Error writing to socket");
  327. return 3;
  328. }
  329. } while (ctx->written < data_len);
  330. return 0;
  331. }
  332. static int ssl_write_all(https_req_ctx_t *ctx, char *data, size_t data_len) {
  333. ctx->written = 0;
  334. ctx->poll_fd.events |= POLLOUT;
  335. do {
  336. int ret = poll(&ctx->poll_fd, 1, POLL_TO_MS);
  337. if (ret < 0) {
  338. netdata_log_error("poll error");
  339. return 1;
  340. }
  341. if (ret == 0) {
  342. if (https_req_check_timedout(ctx)) {
  343. netdata_log_error("Poll timed out");
  344. return 2;
  345. }
  346. continue;
  347. }
  348. ctx->poll_fd.events = 0;
  349. ret = SSL_write(ctx->ssl, &data[ctx->written], data_len - ctx->written);
  350. if (ret > 0) {
  351. ctx->written += ret;
  352. } else {
  353. ret = SSL_get_error(ctx->ssl, ret);
  354. switch (ret) {
  355. case SSL_ERROR_WANT_READ:
  356. ctx->poll_fd.events |= POLLIN;
  357. break;
  358. case SSL_ERROR_WANT_WRITE:
  359. ctx->poll_fd.events |= POLLOUT;
  360. break;
  361. default:
  362. netdata_log_error("SSL_write Err: %s", _ssl_err_tos(ret));
  363. return 3;
  364. }
  365. }
  366. } while (ctx->written < data_len);
  367. return 0;
  368. }
  369. static inline int https_client_write_all(https_req_ctx_t *ctx, char *data, size_t data_len) {
  370. if (ctx->ssl_ctx)
  371. return ssl_write_all(ctx, data, data_len);
  372. return socket_write_all(ctx, data, data_len);
  373. }
  374. static int read_parse_response(https_req_ctx_t *ctx) {
  375. int ret;
  376. char *ptr;
  377. size_t size;
  378. ctx->poll_fd.events = POLLIN;
  379. do {
  380. ret = poll(&ctx->poll_fd, 1, POLL_TO_MS);
  381. if (ret < 0) {
  382. netdata_log_error("poll error");
  383. return 1;
  384. }
  385. if (ret == 0) {
  386. if (https_req_check_timedout(ctx)) {
  387. netdata_log_error("Poll timed out");
  388. return 2;
  389. }
  390. if (!ctx->ssl_ctx)
  391. continue;
  392. }
  393. ctx->poll_fd.events = 0;
  394. do {
  395. ptr = rbuf_get_linear_insert_range(ctx->buf_rx, &size);
  396. if (ctx->ssl_ctx)
  397. ret = SSL_read(ctx->ssl, ptr, size);
  398. else
  399. ret = read(ctx->sock, ptr, size);
  400. if (ret > 0) {
  401. rbuf_bump_head(ctx->buf_rx, ret);
  402. } else {
  403. if (ctx->ssl_ctx) {
  404. ret = SSL_get_error(ctx->ssl, ret);
  405. switch (ret) {
  406. case SSL_ERROR_WANT_READ:
  407. ctx->poll_fd.events |= POLLIN;
  408. break;
  409. case SSL_ERROR_WANT_WRITE:
  410. ctx->poll_fd.events |= POLLOUT;
  411. break;
  412. default:
  413. netdata_log_error("SSL_read Err: %s", _ssl_err_tos(ret));
  414. return 3;
  415. }
  416. } else {
  417. if (errno != EAGAIN && errno != EWOULDBLOCK) {
  418. netdata_log_error("write error");
  419. return 3;
  420. }
  421. ctx->poll_fd.events |= POLLIN;
  422. }
  423. }
  424. } while (ctx->poll_fd.events == 0 && rbuf_bytes_free(ctx->buf_rx) > 0);
  425. } while (!(ret = parse_http_response(ctx->buf_rx, &ctx->parse_ctx)));
  426. if (ret != HTTP_PARSE_SUCCESS) {
  427. netdata_log_error("Error parsing HTTP response");
  428. return 1;
  429. }
  430. return 0;
  431. }
  432. #define TX_BUFFER_SIZE 8192
  433. #define RX_BUFFER_SIZE (TX_BUFFER_SIZE*2)
  434. static int handle_http_request(https_req_ctx_t *ctx) {
  435. BUFFER *hdr = buffer_create(TX_BUFFER_SIZE, &netdata_buffers_statistics.buffers_aclk);
  436. int rc = 0;
  437. http_parse_ctx_create(&ctx->parse_ctx);
  438. // Prepare data to send
  439. switch (ctx->request->request_type) {
  440. case HTTP_REQ_CONNECT:
  441. buffer_strcat(hdr, "CONNECT ");
  442. break;
  443. case HTTP_REQ_GET:
  444. buffer_strcat(hdr, "GET ");
  445. break;
  446. case HTTP_REQ_POST:
  447. buffer_strcat(hdr, "POST ");
  448. break;
  449. default:
  450. netdata_log_error("Unknown HTTPS request type!");
  451. rc = 1;
  452. goto err_exit;
  453. }
  454. if (ctx->request->request_type == HTTP_REQ_CONNECT) {
  455. buffer_strcat(hdr, ctx->request->host);
  456. buffer_sprintf(hdr, ":%d", ctx->request->port);
  457. } else {
  458. buffer_strcat(hdr, ctx->request->url);
  459. }
  460. buffer_strcat(hdr, HTTP_1_1 HTTP_ENDL);
  461. //TODO Headers!
  462. if (ctx->request->request_type != HTTP_REQ_CONNECT) {
  463. buffer_sprintf(hdr, "Host: %s\x0D\x0A", ctx->request->host);
  464. }
  465. buffer_strcat(hdr, "User-Agent: Netdata/rocks newhttpclient\x0D\x0A");
  466. if (ctx->request->request_type == HTTP_REQ_POST && ctx->request->payload && ctx->request->payload_size) {
  467. buffer_sprintf(hdr, "Content-Length: %zu\x0D\x0A", ctx->request->payload_size);
  468. }
  469. if (ctx->request->proxy_username) {
  470. size_t creds_plain_len = strlen(ctx->request->proxy_username) + strlen(ctx->request->proxy_password) + 1 /* ':' */;
  471. char *creds_plain = callocz(1, creds_plain_len + 1);
  472. char *ptr = creds_plain;
  473. strcpy(ptr, ctx->request->proxy_username);
  474. ptr += strlen(ctx->request->proxy_username);
  475. *ptr++ = ':';
  476. strcpy(ptr, ctx->request->proxy_password);
  477. int creds_base64_len = (((4 * creds_plain_len / 3) + 3) & ~3);
  478. // OpenSSL encoder puts newline every 64 output bytes
  479. // we remove those but during encoding we need that space in the buffer
  480. creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n");
  481. char *creds_base64 = callocz(1, creds_base64_len + 1);
  482. base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len);
  483. buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64);
  484. freez(creds_plain);
  485. }
  486. buffer_strcat(hdr, "\x0D\x0A");
  487. // Send the request
  488. if (https_client_write_all(ctx, hdr->buffer, hdr->len)) {
  489. netdata_log_error("Couldn't write HTTP request header into SSL connection");
  490. rc = 2;
  491. goto err_exit;
  492. }
  493. if (ctx->request->request_type == HTTP_REQ_POST && ctx->request->payload && ctx->request->payload_size) {
  494. if (https_client_write_all(ctx, ctx->request->payload, ctx->request->payload_size)) {
  495. netdata_log_error("Couldn't write payload into SSL connection");
  496. rc = 3;
  497. goto err_exit;
  498. }
  499. }
  500. // Read The Response
  501. if (read_parse_response(ctx)) {
  502. netdata_log_error("Error reading or parsing response from server");
  503. if (ctx->parse_ctx.chunked_response)
  504. freez(ctx->parse_ctx.chunked_response);
  505. rc = 4;
  506. goto err_exit;
  507. }
  508. err_exit:
  509. buffer_free(hdr);
  510. return rc;
  511. }
  512. static int cert_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
  513. {
  514. X509 *err_cert;
  515. int err, depth;
  516. char *err_str;
  517. if (!preverify_ok) {
  518. err = X509_STORE_CTX_get_error(ctx);
  519. depth = X509_STORE_CTX_get_error_depth(ctx);
  520. err_cert = X509_STORE_CTX_get_current_cert(ctx);
  521. err_str = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
  522. netdata_log_error("Cert Chain verify error:num=%d:%s:depth=%d:%s", err,
  523. X509_verify_cert_error_string(err), depth, err_str);
  524. free(err_str);
  525. }
  526. #ifdef ACLK_SSL_ALLOW_SELF_SIGNED
  527. if (!preverify_ok && err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
  528. {
  529. preverify_ok = 1;
  530. netdata_log_error("Self Signed Certificate Accepted as the agent was built with ACLK_SSL_ALLOW_SELF_SIGNED");
  531. }
  532. #endif
  533. return preverify_ok;
  534. }
  535. int https_request(https_req_t *request, https_req_response_t *response) {
  536. int rc = 1, ret;
  537. char connect_port_str[PORT_STR_MAX_BYTES];
  538. const char *connect_host = request->proxy_host ? request->proxy_host : request->host;
  539. int connect_port = request->proxy_host ? request->proxy_port : request->port;
  540. struct timeval timeout = { .tv_sec = request->timeout_s, .tv_usec = 0 };
  541. https_req_ctx_t *ctx = callocz(1, sizeof(https_req_ctx_t));
  542. ctx->req_start_time = now_realtime_sec();
  543. ctx->buf_rx = rbuf_create(RX_BUFFER_SIZE);
  544. if (!ctx->buf_rx) {
  545. netdata_log_error("Couldn't allocate buffer for RX data");
  546. goto exit_req_ctx;
  547. }
  548. snprintfz(connect_port_str, PORT_STR_MAX_BYTES, "%d", connect_port);
  549. ctx->sock = connect_to_this_ip46(IPPROTO_TCP, SOCK_STREAM, connect_host, 0, connect_port_str, &timeout);
  550. if (ctx->sock < 0) {
  551. netdata_log_error("Error connecting TCP socket to \"%s\"", connect_host);
  552. goto exit_buf_rx;
  553. }
  554. if (fcntl(ctx->sock, F_SETFL, fcntl(ctx->sock, F_GETFL, 0) | O_NONBLOCK) == -1) {
  555. netdata_log_error("Error setting O_NONBLOCK to TCP socket.");
  556. goto exit_sock;
  557. }
  558. ctx->poll_fd.fd = ctx->sock;
  559. // Do the CONNECT if proxy is used
  560. if (request->proxy_host) {
  561. https_req_t req = HTTPS_REQ_T_INITIALIZER;
  562. req.request_type = HTTP_REQ_CONNECT;
  563. req.timeout_s = request->timeout_s;
  564. req.host = request->host;
  565. req.port = request->port;
  566. req.url = request->url;
  567. req.proxy_username = request->proxy_username;
  568. req.proxy_password = request->proxy_password;
  569. ctx->request = &req;
  570. if (handle_http_request(ctx)) {
  571. netdata_log_error("Failed to CONNECT with proxy");
  572. http_parse_ctx_destroy(&ctx->parse_ctx);
  573. goto exit_sock;
  574. }
  575. if (ctx->parse_ctx.http_code != 200) {
  576. netdata_log_error("Proxy didn't return 200 OK (got %d)", ctx->parse_ctx.http_code);
  577. http_parse_ctx_destroy(&ctx->parse_ctx);
  578. goto exit_sock;
  579. }
  580. http_parse_ctx_destroy(&ctx->parse_ctx);
  581. netdata_log_info("Proxy accepted CONNECT upgrade");
  582. }
  583. ctx->request = request;
  584. ctx->ssl_ctx = netdata_ssl_create_client_ctx(0);
  585. if (ctx->ssl_ctx==NULL) {
  586. netdata_log_error("Cannot allocate SSL context");
  587. goto exit_sock;
  588. }
  589. if (!SSL_CTX_set_default_verify_paths(ctx->ssl_ctx)) {
  590. netdata_log_error("Error setting default verify paths");
  591. goto exit_CTX;
  592. }
  593. SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, cert_verify_callback);
  594. ctx->ssl = SSL_new(ctx->ssl_ctx);
  595. if (ctx->ssl==NULL) {
  596. netdata_log_error("Cannot allocate SSL");
  597. goto exit_CTX;
  598. }
  599. if (!SSL_set_tlsext_host_name(ctx->ssl, connect_host)) {
  600. netdata_log_error("Error setting TLS SNI host");
  601. goto exit_CTX;
  602. }
  603. SSL_set_fd(ctx->ssl, ctx->sock);
  604. ret = SSL_connect(ctx->ssl);
  605. if (ret != -1 && ret != 1) {
  606. netdata_log_error("SSL could not connect");
  607. goto exit_SSL;
  608. }
  609. if (ret == -1) {
  610. // expected as underlying socket is non blocking!
  611. // consult SSL_connect documentation for details
  612. int ec = SSL_get_error(ctx->ssl, ret);
  613. if (ec != SSL_ERROR_WANT_READ && ec != SSL_ERROR_WANT_WRITE) {
  614. netdata_log_error("Failed to start SSL connection");
  615. goto exit_SSL;
  616. }
  617. }
  618. // The actual request here
  619. if (handle_http_request(ctx)) {
  620. netdata_log_error("Couldn't process request");
  621. http_parse_ctx_destroy(&ctx->parse_ctx);
  622. goto exit_SSL;
  623. }
  624. http_parse_ctx_destroy(&ctx->parse_ctx);
  625. response->http_code = ctx->parse_ctx.http_code;
  626. if (ctx->parse_ctx.content_length == TRANSFER_ENCODING_CHUNKED) {
  627. response->payload_size = ctx->parse_ctx.chunked_response_size;
  628. response->payload = ctx->parse_ctx.chunked_response;
  629. }
  630. if (ctx->parse_ctx.content_length > 0) {
  631. response->payload_size = ctx->parse_ctx.content_length;
  632. response->payload = mallocz(response->payload_size + 1);
  633. ret = rbuf_pop(ctx->buf_rx, response->payload, response->payload_size);
  634. if (ret != (int)response->payload_size) {
  635. netdata_log_error("Payload size doesn't match remaining data on the buffer!");
  636. response->payload_size = ret;
  637. }
  638. // normally we take payload as it is and copy it
  639. // but for convenience in cases where payload is sth. like
  640. // json we add terminating zero so that user of the data
  641. // doesn't have to convert to C string (0 terminated)
  642. // other uses still have correct payload_size and can copy
  643. // only exact data without affixed 0x00
  644. ((char*)response->payload)[response->payload_size] = 0; // mallocz(response->payload_size + 1);
  645. }
  646. netdata_log_info("HTTPS \"%s\" request to \"%s\" finished with HTTP code: %d", http_req_type_to_str(ctx->request->request_type), ctx->request->host, response->http_code);
  647. rc = 0;
  648. exit_SSL:
  649. SSL_free(ctx->ssl);
  650. exit_CTX:
  651. SSL_CTX_free(ctx->ssl_ctx);
  652. exit_sock:
  653. close(ctx->sock);
  654. exit_buf_rx:
  655. rbuf_free(ctx->buf_rx);
  656. exit_req_ctx:
  657. freez(ctx);
  658. return rc;
  659. }
  660. void https_req_response_free(https_req_response_t *res) {
  661. freez(res->payload);
  662. }
  663. static inline char *UNUSED_FUNCTION(min_non_null)(char *a, char *b) {
  664. if (!a)
  665. return b;
  666. if (!b)
  667. return a;
  668. return (a < b ? a : b);
  669. }
  670. #define URI_PROTO_SEPARATOR "://"
  671. #define URL_PARSER_LOG_PREFIX "url_parser "
  672. static int parse_host_port(url_t *url) {
  673. char *ptr = strrchr(url->host, ':');
  674. if (ptr) {
  675. size_t port_len = strlen(ptr + 1);
  676. if (!port_len) {
  677. netdata_log_error(URL_PARSER_LOG_PREFIX ": specified but no port number");
  678. return 1;
  679. }
  680. if (port_len > 5 /* MAX port length is 5digit long in decimal */) {
  681. netdata_log_error(URL_PARSER_LOG_PREFIX "port # is too long");
  682. return 1;
  683. }
  684. *ptr = 0;
  685. if (!strlen(url->host)) {
  686. netdata_log_error(URL_PARSER_LOG_PREFIX "host empty after removing port");
  687. return 1;
  688. }
  689. url->port = atoi (ptr + 1);
  690. }
  691. return 0;
  692. }
  693. static inline void port_by_proto(url_t *url) {
  694. if (url->port)
  695. return;
  696. if (!url->proto)
  697. return;
  698. if (!strcmp(url->proto, "http")) {
  699. url->port = 80;
  700. return;
  701. }
  702. if (!strcmp(url->proto, "https")) {
  703. url->port = 443;
  704. return;
  705. }
  706. }
  707. #define STRDUPZ_2PTR(dest, start, end) do { \
  708. dest = mallocz(1 + end - start); \
  709. memcpy(dest, start, end - start); \
  710. dest[end - start] = 0; \
  711. } while(0)
  712. int url_parse(const char *url, url_t *parsed) {
  713. const char *start = url;
  714. const char *end = strstr(url, URI_PROTO_SEPARATOR);
  715. if (end) {
  716. if (end == start) {
  717. netdata_log_error(URL_PARSER_LOG_PREFIX "found " URI_PROTO_SEPARATOR " without protocol specified");
  718. return 1;
  719. }
  720. STRDUPZ_2PTR(parsed->proto, start, end);
  721. start = end + strlen(URI_PROTO_SEPARATOR);
  722. }
  723. end = strchr(start, '/');
  724. if (!end)
  725. end = start + strlen(start);
  726. if (start == end) {
  727. netdata_log_error(URL_PARSER_LOG_PREFIX "Host empty");
  728. return 1;
  729. }
  730. STRDUPZ_2PTR(parsed->host, start, end);
  731. if (parse_host_port(parsed))
  732. return 1;
  733. if (!*end) {
  734. parsed->path = strdupz("/");
  735. port_by_proto(parsed);
  736. return 0;
  737. }
  738. parsed->path = strdupz(end);
  739. port_by_proto(parsed);
  740. return 0;
  741. }
  742. void url_t_destroy(url_t *url) {
  743. freez(url->host);
  744. freez(url->path);
  745. freez(url->proto);
  746. }