Example #1
0
File: stud.c Project: gyepisam/stud
/* Write some previously-buffered backend data upstream on the
 * secure socket using OpenSSL */
static void client_write(struct ev_loop *loop, ev_io *w, int revents) {
    (void) revents;
    int t;
    int sz;
    proxystate *ps = (proxystate *)w->data;
    assert(!ringbuffer_is_empty(&ps->ring_up));
    char * next = ringbuffer_read_next(&ps->ring_up, &sz);
    t = SSL_write(ps->ssl, next, sz);
    if (t > 0) {
        if (t == sz) {
            ringbuffer_read_pop(&ps->ring_up);
            safe_enable_io(ps, &ps->ev_r_down); // can be re-enabled b/c we've popped
            if (ringbuffer_is_empty(&ps->ring_up)) {
                if (ps->want_shutdown) {
                    shutdown_proxy(ps, SHUTDOWN_HARD);
                    return;
                }
                ev_io_stop(loop, &ps->ev_w_up);
            }
        }
        else {
            ringbuffer_read_skip(&ps->ring_up, t);
        }
    }
    else {
        int err = SSL_get_error(ps->ssl, t);
        if (err == SSL_ERROR_WANT_READ) {
            start_handshake(ps, err);
        }
        else if (err == SSL_ERROR_WANT_WRITE) {} /* incomplete SSL data */
        else
            handle_fatal_ssl_error(ps, err);
    }
}
Example #2
0
File: stud.c Project: gyepisam/stud
/* Write some data, previously received on the secure upstream socket,
 * out of the downstream buffer and onto the backend socket */
static void back_write(struct ev_loop *loop, ev_io *w, int revents) {
    (void) revents;
    int t;
    proxystate *ps = (proxystate *)w->data;
    int fd = w->fd;
    int sz;

    assert(!ringbuffer_is_empty(&ps->ring_down));

    char *next = ringbuffer_read_next(&ps->ring_down, &sz);
    t = send(fd, next, sz, MSG_NOSIGNAL);

    if (t > 0) {
        if (t == sz) {
            ringbuffer_read_pop(&ps->ring_down);
            safe_enable_io(ps, &ps->ev_r_up);
            if (ringbuffer_is_empty(&ps->ring_down)) {
                if (ps->want_shutdown) {
                    shutdown_proxy(ps, SHUTDOWN_HARD);
                    return; // dealloc'd
                }
                ev_io_stop(loop, &ps->ev_w_down);
            }
        }
        else {
            ringbuffer_read_skip(&ps->ring_down, t);
        }
    }
    else {
        assert(t == -1);
        handle_socket_errno(ps);
    }
}
Example #3
0
bud_client_error_t bud_client_http_xforward(bud_client_t* client) {
  char* out;
  size_t avail;
  size_t off;
  char xforward[256];
  int r;

  out = ringbuffer_read_next(&client->backend.output, &avail);

  /* Not enough data yet */
  if (avail <= client->xforward.skip)
    goto done;

  /* Find first CRLF */
  for (off = client->xforward.skip; off < avail; off++) {
    static char* crlf = "\r\n";
    char cur;

    cur = out[off];

    /* Reset on mismatch */
    if (cur != crlf[client->xforward.crlf]) {
      client->xforward.crlf = 0;
      continue;
    }

    /* Move forward */
    if (++client->xforward.crlf == 2) {
      off++;
      break;
    }
  }
  client->xforward.skip = off;
  if (!bud_client_xforward_done(client))
    goto done;

  /* Format header */
  r = snprintf(xforward,
               sizeof(xforward),
               "X-Forwarded-For: %s\r\n",
               client->host);

  /* Shift data and insert xforward header */
  r = ringbuffer_insert(&client->backend.output,
                        client->xforward.skip,
                        xforward,
                        (size_t) r);
  if (r != 0) {
    return bud_client_error(bud_error(kBudErrClientXForwardInsert),
                            &client->backend);
  }

done:
  return bud_client_ok(&client->backend);
}
Example #4
0
bud_client_error_t bud_client_backend_in(bud_client_t* client) {
  size_t size;
  int written;
  int err;
  bud_client_error_t cerr;

  written = 0;
  while (!ringbuffer_is_empty(&client->backend.input)) {
    char* data;

    data = ringbuffer_read_next(&client->backend.input, &size);
    written = SSL_write(client->ssl, data, size);
    DBG(&client->frontend, "SSL_write() => %d", written);
    DBG(&client->frontend,
        "frontend.output => %d",
        ringbuffer_size(&client->frontend.output));
    if (written < 0)
      break;

    ASSERT(written == (int) size, "SSL_write() did unexpected partial write");
    ringbuffer_read_skip(&client->backend.input, written);

    /* info_cb() has closed front-end */
    if (client->frontend.close != kBudProgressNone)
      return bud_client_ok(&client->backend);
  }

  cerr = bud_client_throttle(client,
                             &client->frontend,
                             &client->frontend.output);
  if (!bud_is_ok(cerr.err) && cerr.err.code != kBudErrClientThrottle)
    return cerr;

  if (written >= 0)
    return bud_client_ok(&client->backend);

  err = SSL_get_error(client->ssl, written);
  if (err == SSL_ERROR_WANT_READ ||
      err == SSL_ERROR_WANT_WRITE ||
      err == SSL_ERROR_WANT_X509_LOOKUP) {
    return bud_client_ok(&client->backend);
  }

  return bud_client_error(bud_error_num(kBudErrClientSSLWrite, err),
                          &client->backend);
}
Example #5
0
File: test.c Project: Acconut/bud
int main() {
  int i;
  int j;
  int r;
  int after;
  ssize_t len;
  char* ptr;

  data = malloc(TEST_DATA_SIZE);
  assert(data != NULL);
  ringbuffer_init(&rb);

  /* Fill test data */
  for (i = 0; i < TEST_DATA_SIZE; i++)
    data[i] = (i * i) % 137;

  /* Fill ringbuffer */
  i = 0;
  after = 0;
  while (i < TEST_DATA_SIZE - TEST_INSERT_LEN) {
    if (after)
      len = TEST_DATA_SIZE - i - TEST_INSERT_LEN;
    else
      len = TEST_INSERT_OFF - i;

    ptr = ringbuffer_write_ptr(&rb, &len);
    ASSERT(ptr != NULL);

    /* Always make progress */
    ASSERT(len > 0);

    if (after)
      memcpy(ptr, data + i + TEST_INSERT_LEN, len);
    else
      memcpy(ptr, data + i, len);

    i += len;
    r = ringbuffer_write_append(&rb, len);
    ASSERT(r == 0);

    if (i == TEST_INSERT_OFF)
      after = 1;
  }
  ASSERT(ringbuffer_size(&rb) == TEST_DATA_SIZE - TEST_INSERT_LEN);

  /* Insert stuff */
  ringbuffer_insert(&rb,
                    TEST_INSERT_OFF,
                    data + TEST_INSERT_OFF,
                    TEST_INSERT_LEN);

  /* Read from it */
  i = 0;
  while (i < TEST_DATA_SIZE) {
    len = TEST_DATA_SIZE - i;
    ptr = ringbuffer_read_next(&rb, &len);
    ASSERT(ptr != NULL);

    /* Always make progress */
    ASSERT(len > 0);

    for (j = 0; j < len; j++)
      ASSERT(ptr[j] == data[i + j]);

    ringbuffer_read_skip(&rb, len);
    i += len;
  }

  /* Destroy it */
  ringbuffer_destroy(&rb);

  return 0;
}
Example #6
0
bud_client_error_t bud_client_parse_hello(bud_client_t* client) {
  bud_config_t* config;
  bud_error_t err;
  char* data;
  size_t size;

  /* Already running, ignore */
  if (client->hello_parse != kBudProgressNone)
    return bud_client_ok(&client->frontend);

  if (ringbuffer_is_empty(&client->frontend.input))
    return bud_client_ok(&client->frontend);

  config = client->config;
  data = ringbuffer_read_next(&client->frontend.input, &size);
  err = bud_parse_client_hello(data, (size_t) size, &client->hello);

  /* Parser need more data, wait for it */
  if (err.code == kBudErrParserNeedMore)
    return bud_client_ok(&client->frontend);

  if (!bud_is_ok(err)) {
    NOTICE(&client->frontend,
           "failed to parse hello: \"%s\"",
           bud_error_to_str(err));
    goto fatal;
  }

  /* Parse success, perform SNI lookup */
  if (config->sni.enabled && client->hello.servername_len != 0) {
    client->sni_req = bud_http_get(config->sni.pool,
                                   config->sni.url,
                                   client->hello.servername,
                                   client->hello.servername_len,
                                   bud_client_sni_cb,
                                   &err);
    client->sni_req->data = client;
    if (!bud_is_ok(err)) {
      NOTICE(&client->frontend,
             "failed to request SNI: \"%s\"",
             bud_error_to_str(err));
      goto fatal;
    }

    client->hello_parse = kBudProgressRunning;
  /* Perform OCSP stapling request */
  } else if (config->stapling.enabled && client->hello.ocsp_request != 0) {
    err = bud_client_ocsp_stapling(client);
    if (!bud_is_ok(err))
      goto fatal;
  }

  if (client->hello_parse != kBudProgressNone)
    return bud_client_ok(&client->frontend);

  client->hello_parse = kBudProgressDone;
  return bud_client_cycle(client);

fatal:
  client->hello_parse = kBudProgressDone;
  return bud_client_error(err, &client->frontend);
}