Beispiel #1
0
int forwarder_shutdown(forwarder_t *f)
{
  forwarder_t *f_peer = f->f_peer;
  su_sockaddr_t *su = f->f_dest;
  char buf[SU_ADDRSIZE];

  SU_DEBUG_3(("forwarder_shutdown: shutdown from %s:%u\n",
	      su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
	      ntohs(su->su_port)));

  if (su_root_unregister(f->f_pr->pr_root, f->f_wait, forwarder_recv, f) < 0) {
    SU_DEBUG_1(("%s: su_root_unregister failed\n", __func__));
  }

  if (shutdown(f->f_socket, 0) < 0) {
    SU_DEBUG_1(("shutdown(0): %s\n", su_strerror(su_errno())));
  }
  f_peer->f_shutdown = 1;
  if (!f_peer->f_buf) {
    if (shutdown(f_peer->f_socket, 1) < 0) {
      SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
    }
    if (f->f_shutdown) {
      forwarder_close(f);
    }
  }
  return 0;
}
Beispiel #2
0
ssize_t tls_read(tls_t *tls)
{
  ssize_t ret;

  if (tls == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (0)
    SU_DEBUG_1(("tls_read(%p) called on %s (events %u)\n", (void *)tls,
	    tls->type ? "master" : "slave",
	    tls->read_events));

  if (tls->read_buffer_len)
    return (ssize_t)tls->read_buffer_len;

  tls->read_events = SU_WAIT_IN;

  ret = SSL_read(tls->con, tls->read_buffer, tls_buffer_size);
  if (ret <= 0)
    return tls_error(tls, ret, "tls_read: SSL_read", NULL, 0);

  return (ssize_t)(tls->read_buffer_len = ret);
}
Beispiel #3
0
/** Connection is complete. */
int forwarder_connected(proxy_t *pr, su_wait_t *w, forwarder_t *f)
{
  int events, error;
  forwarder_t *f_peer;

  events = su_wait_events(w, f->f_socket);

  error = su_soerror(f->f_socket);

  if (error) {
    SU_DEBUG_1(("connect: %s\n", su_strerror(error)));
    forwarder_destroy(f);
    return 0;
  }

  su_root_unregister(pr->pr_root, f->f_wait + 1, forwarder_connected, f);

  /* Wait for data, forward it to peer */
  assert(f->f_peer);
  f_peer = f->f_peer;
  su_root_register(pr->pr_root, f->f_wait, forwarder_recv, f, 0);
  su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);

  return 0;
}
/**Set mask for a registered event. @internal
 *
 * The function su_devpoll_port_eventmask() sets the mask describing events
 * that can signal the registered callback.
 *
 * @param port   pointer to port object
 * @param index  registration index
 * @param socket socket
 * @param events new event mask
 *
 * @retval 0 when successful,
 * @retval -1 upon an error.  */
int su_devpoll_port_eventmask(su_port_t *self, int index, int socket, int events)
{
  struct su_devpoll *ser;
  struct pollfd w[2];

  if (index <= 0 || index > self->sup_max_index)
    return su_seterrno(EBADF);

  ser = self->sup_indices[index];
  if (!ser->ser_cb)
    return su_seterrno(EBADF);

  ser->ser_wait->events = events;

  w[0].fd = socket;
  w[0].events = POLLREMOVE;
  w[0].revents = 0;
  w[1].fd = socket;
  w[1].events = events & ~POLLREMOVE;
  w[1].revents = 0;

  if (write(self->sup_devpoll, w, (sizeof w)) == -1) {
    SU_DEBUG_1(("su_devpoll_port_eventmask(%p): %d: %s\n", (void *)self,
		socket, su_strerror(su_errno())));
    return -1;
  }

  return 0;
}
Beispiel #5
0
static forwarder_t *forwarder_create_listener(proxy_t *pr, su_addrinfo_t *ai)
{
  forwarder_t *f;
  su_socket_t s;

  if (ai->ai_socktype != SOCK_STREAM &&
      ai->ai_socktype != SOCK_DGRAM)
    return NULL;

  f = forwarder_create(pr);

  if (f) {
    s = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (s != INVALID_SOCKET) {
      f->f_socket = s;
      su_setblocking(s, 0);
      su_setreuseaddr(s, 1);
      if (bind(s, ai->ai_addr, ai->ai_addrlen) >= 0) {
	if (ai->ai_socktype == SOCK_STREAM ?
	    forwarder_init_stream(f) >= 0 :
	    forwarder_init_dgram(f) >= 0)
	  return f;
      }
      else {
	SU_DEBUG_1(("%s: bind: %s\n", __func__, su_strerror(su_errno())));
      }
    }
  }

  forwarder_destroy(f);

  return NULL;
}
Beispiel #6
0
/** Receive from stream.
 *
 * @retval -1 error
 * @retval 0  end-of-stream
 * @retval 1  normal receive
 * @retval 2  incomplete recv, recv again
 *
 */
int tport_recv_stream_ws(tport_t *self)
{
  msg_t *msg;
  ssize_t n, N, veclen, i, m;
  int err;
  msg_iovec_t iovec[msg_n_fragments] = {{ 0 }};
  tport_ws_t *wstp = (tport_ws_t *)self;
  uint8_t *data;
  ws_opcode_t oc;

  if (wstp->ws_initialized < 0) {
	  return -1;
  }

  N = ws_read_frame(&wstp->ws, &oc, &data);

  if (N == -2) {
	  return 2;
  }

  if ((N == -1000) || (N == 0)) {
	  if (self->tp_msg) {
		  msg_recv_commit(self->tp_msg, 0, 1);
	  }
	  return 0;    /* End of stream */
  }
  if (N < 0) {
	  err = errno = EHOSTDOWN;
	  SU_DEBUG_1(("%s(%p): su_getmsgsize(): %s (%d)\n", __func__, (void *)self,
				  su_strerror(err), err));
	  return 0;
  }

  veclen = tport_recv_iovec(self, &self->tp_msg, iovec, N, 0);
  if (veclen < 0)
    return -1;

  msg = self->tp_msg;

  msg_set_address(msg, self->tp_addr, self->tp_addrlen);

  for (i = 0, n = 0; i < veclen; i++) {
    m = iovec[i].mv_len; assert(N >= n + m);
    memcpy(iovec[i].mv_base, data + n, m);
    n += m;
  }

  assert(N == n);

  /* Write the received data to the message dump file */
  if (self->tp_master->mr_dump_file)
	  tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from");

  /* Mark buffer as used */
  msg_recv_commit(msg, N, 0);

  return 1;
}
Beispiel #7
0
static void tport_ws_deinit_secondary(tport_t *self)
{
	tport_ws_t *wstp = (tport_ws_t *)self;

	if (wstp->ws_initialized == 1) {
		SU_DEBUG_1(("%p destroy ws%s transport %p.\n", (void *) self, wstp->ws_secure ? "s" : "", (void *) &wstp->ws));
		ws_destroy(&wstp->ws);
		wstp->ws_initialized = -1;
	}
}
Beispiel #8
0
static int nta_agent_message_callback(nta_agent_magic_t *context,
                               nta_agent_t *agent,
                               msg_t *msg,
                               sip_t *sip)
{
    int error;
    luasofia_nta_agent_t* u_nta_agent = (luasofia_nta_agent_t*) context;
    lua_State *L = u_nta_agent->L;

    SU_DEBUG_9(("nta_agent_message_callback: context[%p] agent[%p] msg[%p] sip[%p]\n",
                context, agent, msg, sip));

    /* put nta_agent userdatum at stack and check if it is ok. */
    luasofia_userdata_table_get(L, agent);
    luaL_checkudata(L, -1, NTA_AGENT_MTABLE);

    /* put callback function at stack */
    lua_rawgeti(L, LUA_REGISTRYINDEX, u_nta_agent->callback_ref);
    if (lua_isnil(L, -1)) {
        lua_pop(L, 2);
        SU_DEBUG_1(("nta_agent_message_callback: callback function not found!\n"));
        return -1; //error, lets not return 0 (should always return 0).
    }

    // Lets pass the nta_agent userdata as the first parameter of the callback.
    lua_pushvalue(L, -2);
    lua_pushlightuserdata(L, msg);
    lua_pushlightuserdata(L, sip);

    SU_DEBUG_9(("nta_agent_message_callback: calling lua callback\n"));
    if ((error = lua_pcall(L, 3, 0, 0)) != 0) {
        if (error == LUA_ERRMEM)
            SU_DEBUG_0(("nta_agent_message_callback: memory allocation error! error[%s]\n", lua_tostring(L, -1)));
        else
            SU_DEBUG_1(("nta_agent_message_callback: error on calling callback! error[%s]\n", lua_tostring(L, -1)));
        lua_pop(L, 1);
    }

    lua_pop(L, 1);
    return 0;
}
Beispiel #9
0
static
ssize_t readfile(su_home_t *home,
                 FILE *f,
                 void **contents,
                 int add_trailing_lf)
{
    /* Read in whole (binary!) file */
    char *buffer = NULL;
    long size;
    size_t len;

    /* Read whole file in */
    if (fseek(f, 0, SEEK_END) < 0 ||
            (size = ftell(f)) < 0 ||
            fseek(f, 0, SEEK_SET) < 0 ||
            (long)(len = (size_t)size) != size ||
            size + 2 > SSIZE_MAX) {
        SU_DEBUG_1(("%s: unable to determine file size (%s)\n",
                    __func__, strerror(errno)));
        return -1;
    }

    if (!(buffer = su_alloc(home, len + 2)) ||
            fread(buffer, 1, len, f) != len) {
        SU_DEBUG_1(("%s: unable to read file (%s)\n", __func__, strerror(errno)));
        if (buffer)
            su_free(home, buffer);
        return -1;
    }

    if (add_trailing_lf) {
        /* Make sure that the buffer has trailing newline */
        if (len == 0 || buffer[len - 1] != '\n')
            buffer[len++] = '\n';
    }

    buffer[len] = '\0';
    *contents = buffer;

    return (ssize_t)len;
}
Beispiel #10
0
int forwarder_stream_peer(proxy_t *pr, forwarder_t *f_peer)
{
  forwarder_t *f;
  su_addrinfo_t *ai;

  assert(f_peer);

  f = forwarder_create(pr);
  if (!f) {
    SU_DEBUG_1(("%s: cannot allocate peer\n", __func__));
    goto error;
  }

  for (ai = pr->pr_addrinfo; ai; ai = ai->ai_next) {
    if (ai->ai_socktype == SOCK_STREAM)
      break;
  }

  if (!ai) {
    SU_DEBUG_1(("%s: no matching destination\n", __func__));
    goto error;
  }

  f->f_socket = su_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  if (f->f_socket == INVALID_SOCKET) {
    SU_DEBUG_1(("%s: socket: %s\n", __func__, su_strerror(su_errno())));
    goto error;
  }

  if (su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) ||
      su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
    SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
    goto error;
  }

  /* Asynchronous connect */
  su_setblocking(f->f_socket, 0);
  su_seterrno(0);
  connect(f->f_socket, ai->ai_addr, ai->ai_addrlen);
  memcpy(f->f_dest, ai->ai_addr, ai->ai_addrlen);

  if (su_errno() != EINPROGRESS) {
    SU_DEBUG_1(("%s: connect: %s\n", __func__, su_strerror(su_errno())));
    goto error;
  }

  if (su_root_register(pr->pr_root, f->f_wait + 1,
		       forwarder_connected, f, 0) == -1) {
    SU_DEBUG_1(("%s: cannot register\n", __func__));
    goto error;
  }

  f->f_peer = f_peer;
  f_peer->f_peer = f;
  return 0;

 error:
  forwarder_destroy(f);
  return SOCKET_ERROR;
}
/* This version can help tuning... */
void su_base_port_run_tune(su_port_t *self)
{
  int i;
  int timers = 0, messages = 0, events = 0;
  su_duration_t tout = 0, tout2 = 0;
  su_time_t started = su_now(), woken = started, bedtime = woken;

  assert(su_port_own_thread(self));

  for (self->sup_running = 1; self->sup_running;) {
    tout = self->sup_max_defer;

    timers = 0, messages = 0;

    if (self->sup_prepoll)
      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);

    if (self->sup_head)
      messages = self->sup_vtable->su_port_getmsgs(self);

    if (self->sup_timers || self->sup_deferrable) {
      su_time_t now = su_now();
      timers =
	su_timer_expire(&self->sup_timers, &tout, now) +
	su_timer_expire(&self->sup_deferrable, &tout2, now);
    }

    if (!self->sup_running)
      break;

    if (self->sup_head)      /* if there are messages do a quick wait */
      tout = 0;

    bedtime = su_now();

    events = self->sup_vtable->su_port_wait_events(self, tout);

    woken = su_now();

    if (messages || timers || events)
      SU_DEBUG_1(("su_port_run(%p): %.6f: %u messages %u timers %u "
		  "events slept %.6f/%.3f\n",
		  self, su_time_diff(woken, started), messages, timers, events,
		  su_time_diff(woken, bedtime), tout * 1e-3));

    if (!self->sup_running)
      break;
  }
}
Beispiel #12
0
ssize_t tls_write(tls_t *tls, void *buf, size_t size)
{
  ssize_t ret;

  if (0)
    SU_DEBUG_1(("tls_write(%p, %p, "MOD_ZU") called on %s\n",
	    (void *)tls, buf, size,
	    tls && tls->type == tls_slave ? "master" : "slave"));

  if (tls == NULL || buf == NULL) {
    errno = EINVAL;
    return -1;
  }

  if (tls->write_buffer) {
    assert(buf == tls->write_buffer);
    assert(size >= tls->write_buffer_len);
    assert(tls->write_events == 0);

    if (tls->write_events ||
	buf != tls->write_buffer ||
	size < tls->write_buffer_len) {
      errno = EIO;
      return -1;
    }

    ret = tls->write_buffer_len;

    tls->write_buffer = NULL;
    tls->write_buffer_len = 0;

    return ret;
  }

  if (size == 0)
    return 0;

  tls->write_events = 0;

  ret = SSL_write(tls->con, buf, size);
  if (ret < 0)
    return tls_error(tls, ret, "tls_write: SSL_write", buf, size);

  return ret;
}
Beispiel #13
0
/** Receive data, forward it to peer */
int forwarder_recv(proxy_t *pr, su_wait_t *w, forwarder_t *f)
{
  buffer_t b[1];
  int n, events;

  events = su_wait_events(w, f->f_socket);

  n = recv(f->f_socket, b->b_data, sizeof(b->b_data), 0);

  if (n > 0) {
    b->b_sent = 0; b->b_used = n;
    if (f->f_peer->f_buf) {
      forwarder_append(f, b);
      return 0;
    }
    if (forwarder_send(pr, f->f_peer, b) >= 0) {
      if (b->b_sent < b->b_used) {
	su_root_unregister(pr->pr_root, w, forwarder_recv, f);
	su_root_register(pr->pr_root, f->f_peer->f_wait + 1,
			 forwarder_empty, f->f_peer, 0);
	forwarder_append(f, b);
      }
      return 0;
    }
    else {
      /* Error when sending */
    }
  }
  if (n < 0) {
    int error = su_errno();
    SU_DEBUG_1(("recv: %s\n", su_strerror(error)));

    if (error == EINTR || error == EAGAIN || error == EWOULDBLOCK) {
      return 0;
    }
    /* XXX */
    forwarder_destroy(f);
  }

  /* shutdown */
  forwarder_shutdown(f);

  return 0;
}
Beispiel #14
0
/** Empty forwarder buffers */
int forwarder_empty(proxy_t *pr, su_wait_t *w, forwarder_t *f)
{
  buffer_t *b;
  int n, events;

  events = su_wait_events(w, f->f_socket);

  while ((b = f->f_buf)) {
    n = forwarder_send(f->f_pr, f, b);
    if (n == 0) {
      if ((f->f_buf = b->b_next))
	b->b_next->b_prev = &f->f_buf;
      su_free(f->f_pr->pr_home, b);
      continue;
    }
    else if (n < 0) {
      /* XXX */
    }
    break;
  }

  if (!f->f_buf) {
    forwarder_t *f_peer = f->f_peer;

    su_root_unregister(pr->pr_root, w, forwarder_empty, f);

    if (!f->f_shutdown) {
      /* Buffer is empty - start receiving */
      su_root_register(pr->pr_root, f_peer->f_wait, forwarder_recv, f_peer, 0);
    }
    else {
      if (shutdown(f->f_socket, 1) < 0) {
	SU_DEBUG_1(("shutdown(1): %s\n", su_strerror(su_errno())));
      }
      if (f_peer->f_shutdown) {
	forwarder_close(f);
      }
    }
  }

  return 0;
}
Beispiel #15
0
/** Destroy a root object.
 *
 *  Stop and free an instance of su_root_t
 *
 * @param self     pointer to a root object.
 */
void su_root_destroy(su_root_t *self)
{
    su_port_t *port;
    int unregistered, reset;

    if (!self)
        return;

    assert(SU_ROOT_OWN_THREAD(self));

    self->sur_deiniting = 1;

    if (self->sur_deinit) {
        su_root_deinit_f deinit = self->sur_deinit;
        su_root_magic_t *magic = self->sur_magic;
        self->sur_deinit = NULL;
        deinit(self, magic);
    }

    port = self->sur_port;
    assert(port);

    unregistered = su_port_unregister_all(port, self);
    reset = su_timer_reset_all(su_task_timers(self->sur_task), self->sur_task);

    if (su_task_deferrable(self->sur_task))
        reset += su_timer_reset_all(su_task_deferrable(self->sur_task),
                                    self->sur_task);

    if (unregistered || reset)
        SU_DEBUG_1(("su_root_destroy: "
                    "%u registered waits, %u timers\n",
                    unregistered, reset));

    SU_TASK_ZAP(self->sur_parent, su_root_destroy);

    su_free(su_port_home(port), self);

    su_port_decref(port, "su_root_destroy");
}
Beispiel #16
0
/** Accept a connection. */
int forwarder_accept(proxy_t *pr, su_wait_t *w, forwarder_t *f0)
{
  forwarder_t *f;
  su_sockaddr_t *su;
  socklen_t  sulen;
  int events;

  events = su_wait_events(w, f0->f_socket);

  f = forwarder_create(pr);

  if (f) {
    su = f->f_dest;
    sulen = sizeof(f->f_dest);
    f->f_socket = accept(f0->f_socket, &su->su_sa, &sulen);
    f->f_upstream = 1;
    if (f->f_socket != INVALID_SOCKET) {
      char buf[SU_ADDRSIZE];

      SU_DEBUG_3(("accept: connection from %s:%u\n",
		  su_inet_ntop(su->su_family, SU_ADDR(su), buf, sizeof(buf)),
		  ntohs(su->su_port)));

      if (!su_wait_create(f->f_wait, f->f_socket, SU_WAIT_IN) &&
	  !su_wait_create(f->f_wait + 1, f->f_socket, SU_WAIT_OUT)) {
	if (forwarder_stream_peer(pr, f) != SOCKET_ERROR) {
	  /* success */
	  return 0;
	}
      }
      else {
	SU_DEBUG_1(("%s: cannot create wait objects\n", __func__));
      }
    }
  }

  forwarder_destroy(f);

  return 0;
}
Beispiel #17
0
int forwarder_send(proxy_t *pr, forwarder_t *f, buffer_t *b)
{
  int n, error;

  do {
    n = send(f->f_socket, b->b_data + b->b_sent, b->b_used - b->b_sent, 0);

    if (n < 0) {
      error = su_errno();
      if (error == EINTR)
	continue;
      SU_DEBUG_1(("send: %s\n", su_strerror(error)));
      if (error != EAGAIN && error != EWOULDBLOCK)
	return -error;
    }
    else {
      f->f_sent += n;
    }
  }
  while (n > 0 && (b->b_sent += n) < b->b_used);

  return b->b_used - b->b_sent;
}
/** Deregister a su_wait_t object. */
static int su_devpoll_port_deregister0(su_port_t *self, int i, int destroy_wait)
{
  struct su_devpoll **indices = self->sup_indices;
  struct su_devpoll *ser;
  struct pollfd pollfd[1];

  ser = self->sup_indices[i];
  if (ser == NULL || ser->ser_cb == NULL) {
    su_seterrno(ENOENT);
    return -1;
  }

  assert(ser->ser_id == i);
  assert(self->sup_devpoll_by_socket[ser->ser_wait->fd] == ser);

  pollfd->fd = ser->ser_wait->fd;
  pollfd->events = POLLREMOVE;
  pollfd->revents = 0;

  if (write(self->sup_devpoll, pollfd, sizeof pollfd) == -1) {
    SU_DEBUG_1(("su_devpoll_port(%p): POLLREMOVE %d: %s\n", (void *)self,
		ser->ser_wait->fd, su_strerror(su_errno())));
  }

  if (destroy_wait)
    su_wait_destroy(ser->ser_wait);

  memset(ser, 0, sizeof *ser);
  ser->ser_id = i;
  ser->ser_next = indices[0], indices[0] = ser;
  self->sup_devpoll_by_socket[pollfd->fd] = NULL;

  self->sup_n_registrations--;
  self->sup_registers++;

  return i;
}
Beispiel #19
0
static
int tls_init_context(tls_t *tls, tls_issues_t const *ti)
{
  int verify;
  static int random_loaded;

  ONCE_INIT(tls_init_once);

  if (!random_loaded) {
    random_loaded = 1;

    if (ti->randFile &&
	!RAND_load_file(ti->randFile, 1024 * 1024)) {
      if (ti->configured > 1) {
	SU_DEBUG_3(("%s: cannot open randFile %s\n",
		   "tls_init_context", ti->randFile));
	tls_log_errors(3, "tls_init_context", 0);
      }
      /* errno = EIO; */
      /* return -1; */
    }
  }

#if HAVE_SIGPIPE
  /* Avoid possible SIGPIPE when sending close_notify */
  signal(SIGPIPE, SIG_IGN);
#endif

  if (tls->ctx == NULL)
    if (!(tls->ctx = SSL_CTX_new((SSL_METHOD*)SSLv23_method()))) {
      tls_log_errors(1, "SSL_CTX_new() failed", 0);
      errno = EIO;
      return -1;
    }
  if (!(ti->version & TPTLS_VERSION_SSLv2))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv2);
  if (!(ti->version & TPTLS_VERSION_SSLv3))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_SSLv3);
  if (!(ti->version & TPTLS_VERSION_TLSv1))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1);
  if (!(ti->version & TPTLS_VERSION_TLSv1_1))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1_1);
  if (!(ti->version & TPTLS_VERSION_TLSv1_2))
    SSL_CTX_set_options(tls->ctx, SSL_OP_NO_TLSv1_2);
  SSL_CTX_sess_set_remove_cb(tls->ctx, NULL);
  SSL_CTX_set_timeout(tls->ctx, ti->timeout);

  /* Set callback if we have a passphrase */
  if (ti->passphrase != NULL) {
    SSL_CTX_set_default_passwd_cb(tls->ctx, passwd_cb);
    SSL_CTX_set_default_passwd_cb_userdata(tls->ctx, (void *)ti);
  }

  if (!SSL_CTX_use_certificate_file(tls->ctx,
				    ti->cert,
				    SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid local certificate: %s\n",
		 "tls_init_context", ti->cert));
      tls_log_errors(3, "tls_init_context", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_use_PrivateKey_file(tls->ctx,
                                   ti->key,
                                   SSL_FILETYPE_PEM)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: invalid private key: %s\n",
		 "tls_init_context", ti->key));
      tls_log_errors(3, "tls_init_context(key)", 0);
#if require_client_certificate
      errno = EIO;
      return -1;
#endif
    }
  }

  if (!SSL_CTX_check_private_key(tls->ctx)) {
    if (ti->configured > 0) {
      SU_DEBUG_1(("%s: private key does not match the certificate public key\n",
		  "tls_init_context"));
    }
#if require_client_certificate
    errno = EIO;
    return -1;
#endif
  }

  if (!SSL_CTX_load_verify_locations(tls->ctx,
                                     ti->CAfile,
                                     ti->CApath)) {
    SU_DEBUG_1(("%s: error loading CA list: %s\n",
		 "tls_init_context", ti->CAfile));
    if (ti->configured > 0)
      tls_log_errors(3, "tls_init_context(CA)", 0);
    errno = EIO;
    return -1;
  }

  /* corresponds to (enum tport_tls_verify_policy) */
  tls->verify_incoming = (ti->policy & 0x1) ? 1 : 0;
  tls->verify_outgoing = (ti->policy & 0x2) ? 1 : 0;
  tls->verify_subj_in  = (ti->policy & 0x4) ? tls->verify_incoming : 0;
  tls->verify_subj_out = (ti->policy & 0x8) ? tls->verify_outgoing : 0;
  tls->verify_date     = (ti->verify_date)  ? 1 : 0;

  if (tls->verify_incoming)
    verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  else
    verify = SSL_VERIFY_NONE;

  SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth);
  SSL_CTX_set_verify(tls->ctx, verify, tls_verify_cb);

  if (tls_init_ecdh_curve(tls) == 0) {
    SU_DEBUG_3(("%s\n", "tls: initialized ECDH"));
  } else {
    SU_DEBUG_3(("%s\n", "tls: failed to initialize ECDH"));
  }

  if (!SSL_CTX_set_cipher_list(tls->ctx, ti->ciphers)) {
    SU_DEBUG_1(("%s: error setting cipher list\n", "tls_init_context"));
    tls_log_errors(3, "tls_init_context", 0);
    errno = EIO;
    return -1;
  }

  return 0;
}
Beispiel #20
0
/** Build a list of local IPv4 addresses and append it to *rresult. */
static
int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  su_localinfo_t *tbf = NULL, **lli = &tbf;
  su_localinfo_t *li = NULL, *li_first = NULL;
  su_sockaddr_t *su;
  int error = ELI_NOADDRESS;
  char *canonname = NULL;
  su_socket_t s;

#if SU_HAVE_IN6
  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;
#else
  int const su_xtra = 0;
#endif

  struct ifconf ifc;
  int numifs;
  char *buffer;
  struct ifreq *ifr, *ifr_next;

#if HAVE_OPEN_C
    su_sockaddr_t *sa;
    socklen_t salen = sizeof(*sa);
#endif

  s = su_socket(AF_INET, SOCK_DGRAM, 0);
  if (s == -1) {
    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
		su_strerror(su_errno())));
    return ELI_SYSTEM;
  }

# if HAVE_IFNUM
  /* Get the list of known IP address from the kernel */
  if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) {
    /* can't get number of interfaces -- fall back */
    SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }

  SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n",
	      numifs));

  if (numifs < 0)
# endif
    /* Default to 64 interfaces. Enough? */
    numifs = 64;

  if (numifs == 0)
    return 0;

  /*
   * Allocate memory for SIOCGIFCONF ioctl buffer. This memory block is also
   * used as li_first, first localinfo struct that is returned, so it can be
   * freed by freelocalinfo() without any complications.
   */
  ifc.ifc_len = numifs * sizeof (struct ifreq);
  buffer = malloc(sizeof(su_localinfo_t) + ifc.ifc_len + su_xtra);
  if (!buffer) {
    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
    error = ELI_MEMORY;
    goto err;
  }

  li_first = (su_localinfo_t *)buffer;
  memset(li_first, 0, sizeof(su_localinfo_t) + su_xtra);
  ifc.ifc_buf = buffer + sizeof(su_localinfo_t) + su_xtra;
#if HAVE_OPEN_C
  if (ioctl(s, SIOCGIFACTIVECONF, (char *)&ifc) < 0) {
    SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }
#else
  if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
    SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }
#endif

  buffer = ifc.ifc_buf + ifc.ifc_len;

  for (ifr = ifc.ifc_req;
       (void *)ifr < (void *)buffer;
       ifr = ifr_next) {
    struct ifreq ifreq[1];
    int scope, if_index, flags = 0, gni_flags = 0;
    char *if_name;
#if SU_HAVE_IN6
    su_sockaddr_t su2[1];
#endif

#if SA_LEN
    if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
      ifr_next = (struct ifreq *)
	(ifr->ifr_addr.sa_len + (char *)(&ifr->ifr_addr));
    else
#else
      ifr_next = ifr + 1;
#endif

    if_name = ifr->ifr_name;

#if defined(SIOCGIFINDEX)
    ifreq[0] = *ifr;
    if (ioctl(s, SIOCGIFINDEX, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
#if HAVE_IFR_INDEX
    if_index = ifreq->ifr_index;
#elif HAVE_IFR_IFINDEX
    if_index = ifreq->ifr_ifindex;
#else
#error Unknown index field in struct ifreq
#endif

#else
#warning su_localinfo() cannot map interface name to number
    if_index = 0;
#endif

    SU_DEBUG_9(("su_localinfo: if %s with index %d\n", if_name, if_index));


#if HAVE_OPEN_C
    su_close(s);

    li = calloc(1, sizeof(su_localinfo_t));
    sa = calloc(1, sizeof(su_sockaddr_t));

    if (su_get_local_ip_addr(sa) < 0)
      goto err;

    li->li_family = sa->su_family;
    li->li_scope = LI_SCOPE_GLOBAL /* scope */;
    li->li_index = if_index;
    li->li_addrlen = su_sockaddr_size(sa);
    li->li_addr = sa;

    if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
      goto err;

    if (canonname) {
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	    li->li_flags |= LI_NUMERIC;
    }
    else
      li->li_flags = 0;

    li->li_canonname = canonname;

    canonname = NULL;

    *rresult = li;

    return 0;
#endif

#if defined(SIOCGIFFLAGS)
    ifreq[0] = *ifr;
    if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
    /* Do not include interfaces that are down unless explicitly asked */
    if ((ifreq->ifr_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0) {
      SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n",
		  if_name, if_index));
      continue;
    }
#elif defined(SIOCGIFACTIVECONF)
/* Handled above in SIOCGIFACTIVECONF vs. SIOCGIFCONF*/
#else
#error su_localinfo() cannot determine interface status
#endif

#if 0
    *ifreq = *ifr;
    ifreq->ifr_addr.sa_family = AF_INET;
    if (ioctl(s, SIOCGIFADDR, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
    ifr->ifr_addr = ifreq->ifr_addr;
#endif

    su = (su_sockaddr_t *)&ifr->ifr_addr;

    if (SU_HAS_INADDR_ANY(su))
      continue;

    scope = li_scope4(su->su_sin.sin_addr.s_addr);

    if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	(hints->li_ifname && strcmp(hints->li_ifname, if_name) != 0) ||
	(hints->li_index && hints->li_index != if_index))
      continue;

#if SU_HAVE_IN6
    if (su_xtra) {
      /* Map IPv4 address to IPv6 address */
      memset(su2, 0, sizeof(*su2));
      su2->su_family = AF_INET6;
      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
      su = su2;
    }
#endif

    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
      gni_flags = NI_NUMERICHOST;

    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
      goto err;
    else if (error > 0)
      continue;

    if (canonname)
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	flags |= LI_NUMERIC;

    if (li_first)
      li = li_first;      /* Use li_first with all ifr structs to be freed */
    else if (!(li = calloc(1, (sizeof *li) + su_xtra))) {
      error = ELI_MEMORY;
      goto err;
    }
    if (!tbf) tbf = li;
    *lli = li; lli = &li->li_next;

    if (su_xtra)
      su = (su_sockaddr_t *)memcpy(li + 1, su, su_xtra);

    li->li_flags = flags;
    li->li_family = su->su_family;
    li->li_scope = scope;
    li->li_index = if_index;
    li->li_addrlen = su_sockaddr_size(su);
    li->li_addr = su;
    li->li_canonname = canonname;
    li->li_ifname = if_name;

    canonname = NULL;
    li_first = NULL;
  }

  if (canonname) free(canonname);
  if (li_first) free(li_first);
  su_close(s);

  if (tbf) *rresult = tbf;
  return 0;

err:
  if (canonname) free(canonname);
  if (li_first) free(li_first);
  su_freelocalinfo(tbf);
  su_close(s);

  return error;
}
Beispiel #21
0
/** Build a list of local IPv4 addresses and append it to *rresult. */
static
int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  su_localinfo_t *li = NULL;
  su_sockaddr_t *su;
  int error = ELI_NOADDRESS;
  char *canonname = NULL;
  su_socket_t s;

#if SU_HAVE_IN6
  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;
#else
  int const su_xtra = 0;
#endif

  struct ifconf ifc;
  int numifs;
  char *buffer;
  struct ifreq *ifr, *ifr_next;

  su_sockaddr_t *sa;
  socklen_t salen = sizeof(*sa);
  int scope = 0, gni_flags = 0;

  s = su_socket(AF_INET, SOCK_DGRAM, 0);
  if (s == -1) {
    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
		su_strerror(su_errno())));
    return ELI_SYSTEM;
  }


  li = calloc(1, (sizeof *li) + (sizeof *sa));
  sa = (void *)(li + 1);

  error = getsockname(s, (struct sockaddr *) sa, &salen);
  if (error < 0 && errno == SOCKET_ERROR) {
    SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
                su_strerror(su_errno())));
  }

  error = bind(s, (struct sockaddr *) sa, salen);

  if (error < 0) {
    SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
                su_strerror(su_errno())));
    goto err;
  }

  su_close(s);

  scope = li_scope4(sa->su_sin.sin_addr.s_addr);

  if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
    gni_flags = NI_NUMERICHOST;

  if (su_xtra) {
    /* Map IPv4 address to IPv6 address */
    memset(sa, 0, sizeof(*sa));
    sa->su_family = AF_INET6;
    ((int32_t*)&sa->su_sin6.sin6_addr)[3] = sa->su_sin.sin_addr.s_addr;
      ((int32_t*)&sa->su_sin6.sin6_addr)[2] = htonl(0xffff);
  }

  li->li_family = sa->su_family;
  li->li_scope = scope;
  li->li_index = 0;
  li->li_addrlen = su_sockaddr_size(sa);
  li->li_addr = sa;

  if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
    goto err;

  if (canonname) {
    if (strchr(canonname, ':') ||
       strspn(canonname, "0123456789.") == strlen(canonname))
	  li->li_flags |= LI_NUMERIC;
  }
  else
    li->li_flags = 0;

  li->li_canonname = canonname;

  canonname = NULL;

  *rresult = li;
  return 0;

err:
  if (canonname) free(canonname);
  if (li) free(li);
  su_close(s);

  return error;
}
Beispiel #22
0
static
int localinfo0(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  /* This is Windows IPv4 code */
  short family = AF_INET;
  su_socket_t s;
  union {
    SOCKET_ADDRESS_LIST sal[1];
#if HAVE_INTERFACE_INFO_EX
    INTERFACE_INFO_EX   ii[1];
#else
    INTERFACE_INFO      ii[1];
#endif
    char buffer[2048];
  } b = {{ 1 }};
  DWORD salen = sizeof(b);
  int i, error = -1;
#if SU_HAVE_IN6
  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
#endif
  su_localinfo_t *li, *head = NULL, **next = &head;
  char *canonname = NULL, *if_name = NULL;

  *rresult = NULL;

  s = su_socket(family, SOCK_DGRAM, 0);
  if (s == INVALID_SOCKET) {
    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "su_socket",
		            su_strerror(su_errno())));
    return -1;
  }

  /* get the list of known IP address (NT5 and up) */
  if (WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0,
               &b, sizeof(b), &salen, NULL, NULL) == SOCKET_ERROR) {
    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "SIO_ADDRESS_LIST_QUERY",
		su_strerror(su_errno())));
    error = -1; goto err;
  }
  if (b.sal->iAddressCount < 1) {
    SU_DEBUG_1(("su_getlocalinfo: no local addresses\n"));
    error = -1; goto err;
  }

  for (i = 0; i < b.sal->iAddressCount; i++) {
    su_sockaddr_t *su = (su_sockaddr_t *)b.sal->Address[i].lpSockaddr;
#if SU_HAVE_IN6
    socklen_t sulen = v4_mapped ? sizeof(*su) : b.sal->Address[i].iSockaddrLength;
    su_sockaddr_t su2[1];
#else
    socklen_t sulen = b.sal->Address[i].iSockaddrLength;
#endif
    int scope, flags = 0, gni_flags = 0;

    scope = li_scope4(su->su_sin.sin_addr.s_addr);

    if (hints->li_scope && (hints->li_scope & scope) == 0)
      continue;

    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
      gni_flags = NI_NUMERICHOST;

    if (!(li = calloc(1, sizeof(*li) + sulen))) {
      SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
      error = -1; goto err;
    }
    *next = li, next = &li->li_next;

#if SU_HAVE_IN6
    if (v4_mapped) {
      /* Map IPv4 address to IPv6 address */
      memset(su2, 0, sizeof(*su2));
      su2->su_family = AF_INET6;
      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
      su = su2;
    }
#endif

    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
      goto err;
    else if (error > 0)
      continue;

    if (canonname)
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	flags |= LI_NUMERIC;

    li->li_flags = flags;
    li->li_family = su->su_family;
    li->li_scope = scope;
    li->li_index = i;
    li->li_addrlen = su_sockaddr_size(su);
    li->li_addr = su;
    li->li_canonname = canonname, canonname = NULL;
    if (hints->li_flags & LI_IFNAME)
      li->li_ifname = if_name;
    li->li_addr = (su_sockaddr_t *)(li + 1);
    li->li_addrlen = sulen;
    memcpy(li->li_addr, su, sulen);
  }

  *rresult = head;
  su_close(s);

  return 0;

err:
  if (canonname) free(canonname);
  su_freelocalinfo(head);
  su_close(s);

  return error;
}
Beispiel #23
0
static
int win_localinfo(su_localinfo_t const hints[1], su_localinfo_t **rresult)
{
  /* This is Windows XP code, for both IPv6 and IPv4. */
  ULONG iaa_size = 2048;
  IP_ADAPTER_ADDRESSES *iaa0, *iaa;
  int error, loopback_seen = 0;
  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
  char *canonname = NULL;
  su_localinfo_t *li, **next;
  int flags = GAA_FLAG_SKIP_MULTICAST;
  *rresult = NULL; next = rresult;

  iaa0 = malloc((size_t)iaa_size);
  if (!iaa0) {
    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
    error = ELI_MEMORY;
    goto err;
  }
  error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
  if (error == ERROR_BUFFER_OVERFLOW) {
    if ((iaa0 = realloc(iaa0, iaa_size)))
      error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
  }
  if (error) {
    char const *empty = "";
    LPTSTR msg = empty;

    if (error == ERROR_NO_DATA) {
      error = ELI_NOADDRESS;
      goto err;
    }

    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
	               FORMAT_MESSAGE_FROM_SYSTEM |
	               FORMAT_MESSAGE_IGNORE_INSERTS,
	  	       NULL,
	  	       error,
		       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		       msg, 0, NULL))
      msg = empty;

    SU_DEBUG_1(("su_localinfo: GetAdaptersAddresses: %s (%d)\n", msg, error));
    if (msg != empty) LocalFree((LPVOID)msg);
    error = ELI_SYSTEM;
    goto err;
  }

  for (iaa = iaa0; iaa; iaa = iaa->Next) {
    IP_ADAPTER_UNICAST_ADDRESS *ua;
    IP_ADAPTER_UNICAST_ADDRESS lua[1];
    int if_index = iaa->IfIndex;
    size_t ifnamelen = 0;
    char ifname[16];

    for (ua = iaa->FirstUnicastAddress; ;ua = ua->Next) {
      su_sockaddr_t *su;
      socklen_t sulen;
      su_sockaddr_t su2[1];
      int scope, flags = 0, gni_flags = 0;

      if (ua == NULL) {
	/* There is no loopback interface in windows */
	if (!loopback_seen && iaa->Next == NULL) {
	  struct sockaddr_in loopback_sin = { AF_INET, 0, {{ 127, 0, 0, 1 }}};

	  lua->Address.lpSockaddr = (struct sockaddr *)&loopback_sin;
	  lua->Address.iSockaddrLength = sizeof(loopback_sin);
	  lua->Next = NULL;

	  iaa->IfType = IF_TYPE_SOFTWARE_LOOPBACK;
	  if_index = 1;

	  ua = lua;
	}
	else
	  break;
      }

      su = (su_sockaddr_t *)ua->Address.lpSockaddr;
      sulen = ua->Address.iSockaddrLength;

      if (su->su_family == AF_INET) {
	scope = li_scope4(su->su_sin.sin_addr.s_addr);
	if (v4_mapped)
	  sulen = sizeof(su->su_sin6);
	if (scope == LI_SCOPE_HOST)
	  loopback_seen = 1;
      }
      else if (su->su_family == AF_INET6) {
	if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
	  continue;
	scope = li_scope6(&su->su_sin6.sin6_addr);
      }
      else
	continue;

      if (hints->li_flags & LI_IFNAME) {
	snprintf(ifname, sizeof(ifname), "%s%u",
		 ws2ifname(iaa->IfType), if_index);
	ifnamelen = strlen(ifname) + 1;
      }

      if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	  (hints->li_family && hints->li_family != su->su_family) ||
	  /* (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0) || */
	  (hints->li_index && hints->li_index != if_index))
	continue;

      if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
	gni_flags = NI_NUMERICHOST;

      if (v4_mapped && su->su_family == AF_INET) {
	/* Map IPv4 address to IPv6 address */
	memset(su2, 0, sizeof(*su2));
	su2->su_family = AF_INET6;
	((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
	((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
	su = su2;
      }

      if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
	goto err;
      else if (error > 0)
	continue;

      if (canonname)
	if (strchr(canonname, ':') ||
	    strspn(canonname, "0123456789.") == strlen(canonname))
	  flags |= LI_NUMERIC;

      if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
	SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
	error = ELI_MEMORY; goto err;
      }
      *next = li, next = &li->li_next;

      li->li_flags = flags;
      li->li_family = su->su_family;
      li->li_scope = scope;
      li->li_index = if_index;
      li->li_addrlen = sulen;
      li->li_addr = memcpy(li + 1, su, sulen);
      li->li_canonname = canonname;
      if (ifnamelen) {
	li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
	/* WideCharToMultiByte(CP_ACP, 0,
			    ifname, -1, (char *)(li + 1) + sulen, ifnamelen,
			    NULL, NULL); */
      }

      canonname = NULL;
    }
  }

  if (iaa0) free(iaa0);
  return 0;

err:
  if (iaa0) free(iaa0);
  if (canonname) free(canonname);
  su_freelocalinfo(*rresult), *rresult = NULL;
  return error;
}
Beispiel #24
0
static
int bsd_localinfo(su_localinfo_t const hints[1],
		  su_localinfo_t **return_result)
{
  struct ifaddrs *ifa, *results;
  int error = 0;
#if SU_HAVE_IN6
  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
#endif
  char *canonname = NULL;

  if (getifaddrs(&results) < 0) {
    if (errno == ENOMEM)
      return ELI_MEMORY;
    else
      return ELI_SYSTEM;
  }

  for (ifa = results; ifa; ifa = ifa->ifa_next) {
    su_localinfo_t *li;
    su_sockaddr_t *su;
#if SU_HAVE_IN6
    su_sockaddr_t su2[1];
#endif
    socklen_t sulen;
    int scope, flags = 0, gni_flags = 0, if_index = 0;
    char const *ifname = 0;
    size_t ifnamelen = 0;

    /* no ip address from if that is down */
    if ((ifa->ifa_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0)
      continue;

    su = (su_sockaddr_t *)ifa->ifa_addr;

    if (!su)
      continue;

    if (su->su_family == AF_INET) {
      sulen = sizeof(su->su_sin);
      scope = li_scope4(su->su_sin.sin_addr.s_addr);
#if SU_HAVE_IN6
      if (v4_mapped)
	sulen = sizeof(su->su_sin6);
#endif
    }
#if SU_HAVE_IN6
    else if (su->su_family == AF_INET6) {
      if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
	continue;
      sulen = sizeof(su->su_sin6);
      scope = li_scope6(&su->su_sin6.sin6_addr);
    }
#endif
    else
      continue;

    if (hints->li_flags & LI_IFNAME) {
      ifname = ifa->ifa_name;
      if (ifname)
	ifnamelen = strlen(ifname) + 1;
    }

    if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	(hints->li_family && hints->li_family != su->su_family) ||
	(hints->li_ifname && (!ifname || strcmp(hints->li_ifname, ifname))) ||
	(hints->li_index && hints->li_index != if_index))
      continue;

    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
      gni_flags = NI_NUMERICHOST;

#if SU_HAVE_IN6
    if (v4_mapped && su->su_family == AF_INET) {
      /* Map IPv4 address to IPv6 address */
      memset(su2, 0, sizeof(*su2));
      su2->su_family = AF_INET6;
      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
      su = su2;
    }
#endif

    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
      break;

    if (error > 0) {
      error = 0;
      continue;
    }

    if (canonname)
      if (strchr(canonname, ':') ||
	  canonname[strspn(canonname, "0123456789.")] == '\0')
	flags |= LI_NUMERIC;

    if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
      SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
      error = ELI_MEMORY;
      break;
    }
    *return_result = li, return_result = &li->li_next;

    li->li_flags = flags;
    li->li_family = su->su_family;
    li->li_scope = scope;
    li->li_index = if_index;
    li->li_addrlen = sulen;
    li->li_addr = memcpy(li + 1, su, sulen);
    li->li_canonname = canonname;
    if (ifnamelen) {
      li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
    }

    canonname = NULL;
  }

  if (canonname)
    free(canonname);

  freeifaddrs(results);

  return error;
}
Beispiel #25
0
/**Initialize an authentication module instance.
 *
 * The function auth_mod_init_default() initializes an authentication module
 * object used to authenticate the requests.
 *
 * @param am
 * @param base
 * @param root
 * @param tag,value,... tagged argument list
 *
 * @TAGS
 * AUTHTAG_REALM(), AUTHTAG_OPAQUE(), AUTHTAG_DB(), AUTHTAG_QOP(),
 * AUTHTAG_ALGORITHM(), AUTHTAG_EXPIRES(), AUTHTAG_NEXT_EXPIRES(),
 * AUTHTAG_BLACKLIST(), AUTHTAG_FORBIDDEN(), AUTHTAG_ANONYMOUS(),
 * AUTHTAG_FAKE(), AUTHTAG_ALLOW(), AUTHTAG_REMOTE(), and
 * AUTHTAG_MASTER_KEY().
 *
 * @return 0 if successful
 * @return -1 upon an error
 */
int auth_init_default(auth_mod_t *am,
                      auth_scheme_t *base,
                      su_root_t *root,
                      tag_type_t tag, tag_value_t value, ...)
{
    int retval = 0;

    ta_list ta;

    char const *realm = NULL, *opaque = NULL, *db = NULL, *allows = NULL;
    char const *qop = NULL, *algorithm = NULL;
    unsigned expires = 60 * 60, next_expires = 5 * 60;
    unsigned max_ncount = 0;
    unsigned blacklist = 5;
    int forbidden = 0;
    int anonymous = 0;
    int fake = 0;
    url_string_t const *remote = NULL;
    char const *master_key = "fish";
    char *s;

    ta_start(ta, tag, value);

    /* Authentication stuff */
    tl_gets(ta_args(ta),
            AUTHTAG_REALM_REF(realm),
            AUTHTAG_OPAQUE_REF(opaque),
            AUTHTAG_DB_REF(db),
            AUTHTAG_QOP_REF(qop),
            AUTHTAG_ALGORITHM_REF(algorithm),
            AUTHTAG_EXPIRES_REF(expires),
            AUTHTAG_NEXT_EXPIRES_REF(next_expires),
            AUTHTAG_MAX_NCOUNT_REF(max_ncount),
            AUTHTAG_BLACKLIST_REF(blacklist),
            AUTHTAG_FORBIDDEN_REF(forbidden),
            AUTHTAG_ANONYMOUS_REF(anonymous),
            AUTHTAG_FAKE_REF(fake),
            AUTHTAG_ALLOW_REF(allows),
            AUTHTAG_REMOTE_REF(remote),
            AUTHTAG_MASTER_KEY_REF(master_key),
            TAG_NULL());

    if (!realm) realm = "*";
    if (!allows) allows = "ACK, BYE, CANCEL";

    am->am_realm = su_strdup(am->am_home, realm);
    am->am_opaque = su_strdup(am->am_home, opaque);
    am->am_db = su_strdup(am->am_home, db);
    s = su_strdup(am->am_home, allows);
    if (s)
        msg_commalist_d(am->am_home, &s, &am->am_allow, NULL);
    am->am_expires = expires;
    am->am_next_exp = next_expires;
    am->am_max_ncount = max_ncount;
    am->am_blacklist = blacklist;
    am->am_forbidden = forbidden;
    am->am_anonymous = anonymous;
    am->am_fake = fake;
    am->am_remote = url_hdup(am->am_home, (url_t *)remote);
    am->am_algorithm = algorithm ? su_strdup(am->am_home, algorithm) : "MD5";
    am->am_nextnonce = !algorithm || su_casematch(algorithm, "MD5");
    if (next_expires == 0)
        am->am_nextnonce = 0;
    am->am_qop = su_strdup(am->am_home, qop);

    if (master_key) {
        su_md5_t md5[1];

        su_md5_init(md5);
        su_md5_strupdate(md5, master_key);
        su_md5_strupdate(md5, "70P 53KR37");
        su_md5_digest(md5, am->am_master_key);
    }

    auth_md5_hmac_key(am);

    /* Make sure that we have something
       that can be used to identify credentials */
    if (am->am_opaque && strcmp(am->am_opaque, "*") == 0) {
#ifndef HOST_NAME_MAX
#define HOST_NAME_MAX 255
#endif
        char hostname[HOST_NAME_MAX + 1];
        su_md5_t md5[1];
        uint8_t hmac[6];

        gethostname(hostname, sizeof hostname);

        auth_md5_hmac_init(am, md5);

        su_md5_strupdate(md5, hostname);
        su_md5_update(md5, ":", 1);
        if (am->am_remote)
            url_update(md5, am->am_remote);

        auth_md5_hmac_digest(am, md5, hmac, sizeof hmac);

        base64_e(hostname, sizeof hostname, hmac, sizeof hmac);

        am->am_opaque = su_strdup(am->am_home, hostname);

        if (!am->am_opaque) {
            retval = -1;
            SU_DEBUG_1(("%s: cannot create unique identifier\n", __func__));
        }
    }

    if (retval < 0)
        ;
    else if (db) {
        retval = auth_readdb(am);
        if (retval == -1) {
            int err = errno;
            SU_DEBUG_1(("auth-module: %s: %s\n", am->am_db, strerror(err)));
            errno = err;
        }
    }
    else {
        retval = auth_htable_resize(am->am_home, am->am_users, 0);
    }

    ta_end(ta);

    return retval;
}
Beispiel #26
0
/** Set various outbound and nat-traversal related options. */
int outbound_set_options(outbound_t *ob,
			 char const *_options,
			 unsigned interval,
			 unsigned stream_interval)
{
  struct outbound_prefs prefs[1] = {{ 0 }};
  char *s, *options = su_strdup(NULL, _options);
  int invalid;

  prefs->interval = interval;
  prefs->stream_interval = stream_interval;

#define MATCH(v) (len == sizeof(#v) - 1 && su_casenmatch(#v, s, len))

  if (options) {
    for (s = options; s[0]; s++) if (s[0] == '-') s[0] = '_';
  }

  prefs->gruuize = 1;
  prefs->outbound = 0;
  prefs->natify = 1;
  prefs->okeepalive = -1;
  prefs->validate = 1;
  prefs->use_rport = 1;

  for (s = options; s && s[0]; ) {
    size_t len = span_token(s);
    int value = 1;

    if (len > 3 && su_casenmatch(s, "no_", 3))
      value = 0, s += 3, len -= 3;
    else if (len > 4 && su_casenmatch(s, "not_", 4))
      value = 0, s += 4, len -= 4;

    if (len == 0)
      break;
    else if (MATCH(gruuize)) prefs->gruuize = value;
    else if (MATCH(outbound)) prefs->outbound = value;
    else if (MATCH(natify)) prefs->natify = value;
    else if (MATCH(validate)) prefs->validate = value;
    else if (MATCH(options_keepalive)) prefs->okeepalive = value;
    else if (MATCH(use_connect)) prefs->use_connect = value;
    else if (MATCH(use_rport)) prefs->use_rport = value;
    else if (MATCH(use_socks)) prefs->use_socks = value;
    else if (MATCH(use_upnp)) prefs->use_upnp = value;
    else if (MATCH(use_stun)) prefs->use_stun = value;
    else
      SU_DEBUG_1(("outbound(%p): unknown option \"%.*s\"\n",
		  (void *)ob->ob_owner, (int)len, s));

    s += len;
    len = strspn(s, " \t\n\r,;");
    if (len == 0)
      break;
    s += len;
  }

  invalid = s && s[0];
  if (invalid)
    SU_DEBUG_1(("outbound(%p): invalid options \"%s\"\n",
		(void *)ob->ob_owner, options));
  su_free(NULL, options);
  if (invalid)
    return -1;

  if (prefs->natify &&
      !(prefs->outbound ||
	prefs->use_connect ||
	prefs->use_rport ||
	prefs->use_socks ||
	prefs->use_upnp ||
	prefs->use_stun)) {
    SU_DEBUG_1(("outbound(%p): no nat traversal method given\n",
		(void *)ob->ob_owner));
  }

  ob->ob_prefs = *prefs;
  ob->ob_reg_id = prefs->outbound ? 1 : 0;

  return 0;
}
Beispiel #27
0
int nua_stack_init(su_root_t *root, nua_t *nua)
{
  su_home_t *home;
  nua_handle_t *dnh;

  static int initialized_logs = 0;

  enter;

  if (!initialized_logs) {
    extern su_log_t tport_log[];
    extern su_log_t nta_log[];
    extern su_log_t nea_log[];
    extern su_log_t iptsec_log[];

    su_log_init(tport_log);
    su_log_init(nta_log);
    su_log_init(nea_log);
    su_log_init(iptsec_log);

    initialized_logs = 1;
  }

  nua->nua_root = root;

  home = nua->nua_home;
  nua->nua_handles_tail = &nua->nua_handles;
  sip_from_init(nua->nua_from);

  dnh = su_home_clone(nua->nua_home, sizeof (*dnh) + sizeof(*dnh->nh_prefs));
  if (!dnh)
    return -1;

  dnh->nh_prefs = (void *)(dnh + 1);
  dnh->nh_valid = nua_valid_handle_cookie;
  dnh->nh_nua = nua;
  nua_handle_ref(dnh); dnh->nh_ref_by_stack = 1;
  nua_handle_ref(dnh); dnh->nh_ref_by_user = 1;
  nh_append(nua, dnh);
  dnh->nh_identity = dnh;
  dnh->nh_ds->ds_local = nua->nua_from;
  dnh->nh_ds->ds_remote = nua->nua_from;

  if (nua_stack_set_defaults(dnh, dnh->nh_prefs) < 0)
    return -1;

  if (nua_stack_set_params(nua, dnh, nua_i_none, nua->nua_args) < 0)
    return -1;

  /* XXX - soa should know what it supports */
  nua->nua_invite_accept = sip_accept_make(home, SDP_MIME_TYPE);

  nua->nua_accept_multipart = sip_accept_format(home, "%s, %s",
						SDP_MIME_TYPE,
						"multipart/*");

  nua->nua_nta = nta_agent_create(root, NONE, NULL, NULL,
				  NTATAG_MERGE_482(1),
				  NTATAG_CLIENT_RPORT(1),
				  NTATAG_UA(1),
#if HAVE_SOFIA_SMIME
				  NTATAG_SMIME(nua->sm),
#endif
				  TPTAG_STUN_SERVER(1),
				  TAG_NEXT(nua->nua_args));

  dnh->nh_ds->ds_leg = nta_leg_tcreate(nua->nua_nta,
				       nua_stack_process_request, dnh,
				       NTATAG_NO_DIALOG(1),
				       TAG_END());

  if (nua->nua_nta == NULL ||
      dnh->nh_ds->ds_leg == NULL ||
      nta_agent_set_params(nua->nua_nta, NTATAG_UA(1), TAG_END()) < 0 ||
      nua_stack_init_transport(nua, nua->nua_args) < 0) {
    SU_DEBUG_1(("nua: initializing SIP stack failed\n"));
    return -1;
  }

  if (nua_stack_set_from(nua, 1, nua->nua_args) < 0)
    return -1;

  if (nua->nua_prefs->ngp_detect_network_updates)
    nua_stack_launch_network_change_detector(nua);

  return 0;
}
Beispiel #28
0
/* NUA event callback */
static void nua_event_callback(nua_event_t event,
                               int status, char const *phrase,
                               nua_t *nua, nua_magic_t *magic,
                               nua_handle_t *nh, nua_hmagic_t *hmagic,
                               sip_t const *sip,
                               tagi_t tags[])
{
    int error;
    lua_State *L = (lua_State *)magic;

    SU_DEBUG_9(("nua_event_callback: event[%s] status[%d] phrase[%s] "
                "nua[%p] magic[%p] nh[%p] hmagic[%p] sip[%p] tags[%p]\n",
                nua_event_name(event), status, phrase, nua, magic, nh, hmagic, sip, tags));

    /* put nua userdatum at stack and check if it is ok. */
    luasofia_userdata_table_get(L, nua);

    if (lua_isnil(L, -1)) {
        SU_DEBUG_1(("nua_event_callback: nua userdata not found on userdata_table!\n"));
        return;
    }

    luaL_checkudata(L, -1, NUA_MTABLE);

    /* put env table at stack */
    lua_getfenv(L, -1);

    /* put callback table at stack */
    lua_rawgeti(L, -1, ENV_CALLBACK_INDEX);
    if (lua_isnil(L, -1)) {
        lua_pop(L, 3);
        SU_DEBUG_1(("nua_event_callback: callback table not found!\n"));
        return;
    }

    /* get event callback */
    lua_rawgeti(L, -1, event);
    if (lua_isnil(L, -1)) {
        lua_pop(L, 1);
        /* get event default callback */
        lua_rawgeti(L, -1, NUA_EVENT_DEFAULT_INDEX);
        if (lua_isnil(L, -1)) {
            lua_pop(L, 4);
            SU_DEBUG_9(("nua_event_callback: event[%s] callback not found!\n", nua_event_name(event)));
            return;
        }
    }

    lua_pushinteger(L, event);
    lua_pushinteger(L, status);
    lua_pushstring(L, phrase);
    lua_pushvalue(L, -7);

    /* get magic field */
    lua_rawgeti(L, -7, ENV_MAGIC_INDEX);

    if (nh) { 
        /* put nua_handle userdatum at stack */
        luasofia_userdata_table_get(L, nh);
        if (lua_isnil(L, -1)) {
            /* create a new nua_handle userdatum */
            lua_pop(L, 1);
            luasofia_nua_handle_create_userdata(L, nh);
            lua_pushnil(L);
        } else {
            /* check if it is a nua_handle */
            luaL_checkudata(L, -1, NUA_HANDLE_MTABLE);
            
            /* put env table at stack */
            lua_getfenv(L, -1);
        }
    } else {
        lua_pushnil(L);
        lua_pushnil(L);
    }

    sip ? lua_pushlightuserdata(L, (void*)sip) : lua_pushnil(L);

    tags ? lua_pushlightuserdata(L, (void*)tags) : lua_pushnil(L);

    SU_DEBUG_9(("nua_event_callback: calling lua callback\n"));
    if ((error = lua_pcall(L, 9, 0, 0)) != 0) {
        if (error == LUA_ERRMEM) 
            SU_DEBUG_0(("nua_event_callback: memory allocation error! error[%s]\n", lua_tostring(L, -1)));
        else
            SU_DEBUG_1(("nua_event_callback: error on calling callback! error[%s]\n", lua_tostring(L, -1)));
        lua_pop(L, 1);
    }
    lua_pop(L, 3);
}
Beispiel #29
0
server_t *server_create(url_t const *url,
			tag_type_t tag, tag_value_t value, ...)
{
  server_t *srv;
  msg_mclass_t const *mclass = NULL;
  tp_name_t tpn[1] = {{ NULL }};
  su_root_t *root = NULL;
  http_server_t const *server = NULL;
  int persistent = 0;
  char const *server_str = SERVER_VERSION;
  ta_list ta;

  ta_start(ta, tag, value);
  tl_gets(ta_args(ta),
	  NTHTAG_ROOT_REF(root),
	  NTHTAG_MCLASS_REF(mclass),
	  TPTAG_REUSE_REF(persistent),
	  HTTPTAG_SERVER_REF(server),
	  HTTPTAG_SERVER_STR_REF(server_str),
	  TAG_END());

  if (!root || !url ||
      (url->url_type != url_http && url->url_type != url_https)
      || !(srv = su_home_new(sizeof(*srv)))) {
    ta_end(ta);
    return NULL;
  }

  tpn->tpn_proto = url_tport_default((enum url_type_e)url->url_type);
  tpn->tpn_canon = url->url_host;
  tpn->tpn_host =  url->url_host;
  tpn->tpn_port = url_port(url);

  srv->srv_tports = tport_tcreate(srv, nth_server_class, root,
				  TPTAG_IDLE(600000),
				  TPTAG_TIMEOUT(300000),
				  ta_tags(ta));

  srv->srv_persistent = persistent;
  srv->srv_max_bodylen = 1 << 30; /* 1 GB */

  if (tport_tbind(srv->srv_tports, tpn, http_tports,
		  TAG_END()) >= 0 ||
      tport_tbind(srv->srv_tports, tpn, http_no_tls_tports,
		  TAG_END()) >= 0) {
    srv->srv_root = root;
    srv->srv_mclass = mclass ? mclass : http_default_mclass();
    srv->srv_mflags = MSG_DO_CANONIC;

    if (server)
      srv->srv_server = http_server_dup(srv->srv_home, server);
    else
      srv->srv_server = http_server_make(srv->srv_home, server_str);

    tport_get_params(srv->srv_tports,
		     TPTAG_QUEUESIZE_REF(srv->srv_queuesize),
		     TAG_END());
  }
  else {
    SU_DEBUG_1(("nth_server_create: cannot bind transports "
		URL_FORMAT_STRING "\n",
		URL_PRINT_ARGS(url)));
    server_destroy(srv), srv = NULL;
  }

  ta_end(ta);

  return srv;
}
Beispiel #30
0
/* Use HOSTADDR6 */
static
int localinfo6(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  char *addr, *ifname;
  int flags, error;
  su_localinfo_t *li = NULL;
  su_sockaddr_t *su;
  int const su_sockaddr_size = sizeof(*su);

  error = ELI_NOADDRESS;

#if defined(__APPLE_CC__)
  {
    su_sockaddr_t *sa;
    int salen = sizeof(*sa);
    int s;

    if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
      if ((addr = getenv("HOSTADDR6"))) {

	li = calloc(1, sizeof(su_localinfo_t));
	sa = calloc(1, sizeof(su_sockaddr_t));

	sa->su_family = AF_INET6;
	if (su_inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0)
	  goto err;

	s = su_socket(AF_INET6, SOCK_DGRAM, 0);
	if (s == -1) {
	  SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
		      su_strerror(su_errno())));
	  return ELI_SYSTEM;
	}

	error = getsockname(s, (struct sockaddr *) sa, &salen);
	if (error < 0 && errno == SOCKET_ERROR) {
	  SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
		      su_strerror(su_errno())));
	}

	error = bind(s, (struct sockaddr *) sa, salen);

	if (error < 0) {
	  SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
		      su_strerror(su_errno())));
	  goto err;
	}

	su_close(s);

	li->li_family = sa->su_family;
	li->li_scope = LI_SCOPE_GLOBAL;
	li->li_index = 0;
	li->li_addrlen = su_sockaddr_size(sa);
	li->li_addr = sa;

	if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0)
	  goto err;

	li->li_flags = NI_NUMERICHOST;
      }
    }

    *rresult = li;
    return 0;
  }
#endif


  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
    if ((addr = getenv("HOSTADDR6"))) {
      flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);

      if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
	error = ELI_MEMORY;
	goto err;
      }
      li->li_flags = flags;
      li->li_scope = LI_SCOPE_GLOBAL, li->li_index = 2, ifname = "eth";
      li->li_addrlen = sizeof(*su);
      li->li_addr = su = (su_sockaddr_t *)(li + 1);
      su->su_family = li->li_family = AF_INET6;
      if (su_inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
	goto err;
      if (li->li_flags & LI_IFNAME)
	li->li_ifname = ifname;
      if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0)
	goto err;
      else if (error > 0) {
	free(li); li = NULL;
      }
    }
  }

  *rresult = li;

  return 0;

err:
  if (li) su_freelocalinfo(li);
  return error;
}