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; }
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); }
/** 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; }
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; }
/** 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; }
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; } }
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; }
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; }
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; } }
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; }
/** 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; }
/** 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; }
/** 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"); }
/** 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; }
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; }
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; }
/** 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; }
/** 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; }
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; }
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; }
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; }
/**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; }
/** 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; }
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; }
/* 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); }
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; }
/* 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; }