From 63eae8581032880cbe406d7dbba94e82f01e754f Mon Sep 17 00:00:00 2001 From: Jennifer Richards Date: Fri, 11 Nov 2016 21:14:54 -0500 Subject: [PATCH] Open all ports for servers. Disallow IPv4-mapped IPv6 addrs. --- include/tr_event.h | 7 +- include/trp_internal.h | 4 +- include/trust_router/tid.h | 7 +- tid/tids.c | 174 ++++++++++++++++++++------------------------- tr/tr_main.c | 2 +- tr/tr_tid.c | 34 +++++---- tr/tr_trp.c | 36 +++++----- trp/trps.c | 120 +++++++++++++++++-------------- 8 files changed, 197 insertions(+), 187 deletions(-) diff --git a/include/tr_event.h b/include/tr_event.h index 16a1067..dc93860 100644 --- a/include/tr_event.h +++ b/include/tr_event.h @@ -37,10 +37,13 @@ #include +#define TR_MAX_SOCKETS 10 + /* struct for hanging on to a socket listener event */ struct tr_socket_event { - int sock_fd; /* the fd for the socket */ - struct event *ev; /* its event */ + size_t n_sock_fd; /* how many of those are filled in? */ + int sock_fd[TR_MAX_SOCKETS]; /* the fd for the socket */ + struct event *ev[TR_MAX_SOCKETS]; /* its events */ }; /* prototypes */ diff --git a/include/trp_internal.h b/include/trp_internal.h index eb89692..23d20e8 100644 --- a/include/trp_internal.h +++ b/include/trp_internal.h @@ -234,7 +234,9 @@ int trps_get_listener(TRPS_INSTANCE *trps, TRP_AUTH_FUNC auth_handler, const char *hostname, unsigned int port, - void *cookie); + void *cookie, + int *fd_out, + size_t max_fd); TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps); void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg); TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn); diff --git a/include/trust_router/tid.h b/include/trust_router/tid.h index 6aa3336..b491b6a 100644 --- a/include/trust_router/tid.h +++ b/include/trust_router/tid.h @@ -150,12 +150,9 @@ TR_EXPORT void tidc_destroy (TIDC_INSTANCE *tidc); /* TID Server functions, in tid/tids.c */ TR_EXPORT TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx); -TR_EXPORT int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, - TIDS_AUTH_FUNC *auth_handler, const char *hostname, - unsigned int port, void *cookie); TR_EXPORT int tids_get_listener (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler, - TIDS_AUTH_FUNC *auth_handler, const char *hostname, - unsigned int port, void *cookie); + TIDS_AUTH_FUNC *auth_handler, const char *hostname, + unsigned int port, void *cookie, int *fd_out, size_t max_fd); TR_EXPORT int tids_accept(TIDS_INSTANCE *tids, int listen); TR_EXPORT int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp); TR_EXPORT int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg); diff --git a/tid/tids.c b/tid/tids.c index 47ecfcb..e272d37 100644 --- a/tid/tids.c +++ b/tid/tids.c @@ -108,36 +108,69 @@ static void tids_destroy_response(TIDS_INSTANCE *tids, TID_RESP *resp) } } -static int tids_listen (TIDS_INSTANCE *tids, int port) +static int tids_listen(TIDS_INSTANCE *tids, int port, int *fd_out, size_t max_fd) { - int rc = 0; - int conn = -1; - int optval = 1; - - union { - struct sockaddr_storage storage; - struct sockaddr_in in4; - } addr; - - struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4; - - saddr->sin_port = htons (port); - saddr->sin_family = AF_INET; - saddr->sin_addr.s_addr = INADDR_ANY; - - if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0))) - return conn; + int rc = 0; + int conn = -1; + int optval = 1; + struct addrinfo *ai=NULL; + struct addrinfo *ai_head=NULL; + struct addrinfo hints={.ai_flags=AI_PASSIVE, + .ai_family=AF_UNSPEC, + .ai_socktype=SOCK_STREAM, + .ai_protocol=IPPROTO_TCP}; + char *port_str=NULL; + + port_str=talloc_asprintf(NULL, "%d", port); + if (port_str==NULL) { + tr_debug("tids_listen: unable to allocate port."); + return -1; + } - setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + getaddrinfo(NULL, port_str, &hints, &ai_head); + talloc_free(port_str); - if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in)))) - return rc; + /* TODO: listen on all ports */ + for (ai=ai_head; ai!=NULL; ai=ai->ai_next) { + if (ai->ai_family==AF_INET6) { + ai=talloc_memdup(NULL, ai, sizeof(struct addrinfo)); /* get a permanent copy of this */ + break; + } + } + freeaddrinfo(ai_head); - if (0 > (rc = listen(conn, 512))) - return rc; + if (ai==NULL) { + tr_debug("tids_listen: no addresses available for listening."); + return -1; + } - tr_debug("tids_listen: TID Server listening on port %d", port); - return conn; + if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) { + tr_debug("tids_listen: unable to open socket."); + talloc_free(ai); + return -1; + } + + optval=1; + setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); +/* setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); */ + + rc=bind(conn, ai->ai_addr, ai->ai_addrlen); + talloc_free(ai); + if (rc<0) { + char errmsg[255]; + tr_debug("tids_listen: unable to bind to socket (%s).", strerror_r(errno, errmsg, 255)); + close(conn); + return -1; + } + + if (0 > (rc = listen(conn, 512))) { + tr_debug("trps_listen: unable to listen on bound socket."); + close(conn); + return rc; + } + + tr_debug("tids_listen: TID Server listening on port %d", port); + return conn; } /* returns EACCES if authorization is denied */ @@ -400,33 +433,36 @@ int tids_get_listener(TIDS_INSTANCE *tids, TIDS_AUTH_FUNC *auth_handler, const char *hostname, unsigned int port, - void *cookie) + void *cookie, + int *fd_out, + size_t max_fd) { - int listen = -1; + size_t n_fd=0; + size_t ii=0; tids->tids_port = port; - if (0 > (listen = tids_listen(tids, port))) { - char errbuf[256]; - if (0 == strerror_r(errno, errbuf, 256)) { - tr_debug("tids_get_listener: Error opening port %d: %s.", port, errbuf); - } else { - tr_debug("tids_get_listener: Unknown error openining port %d.", port); - } - } - - if (listen > 0) { + n_fd=tids_listen(tids, port, fd_out, max_fd); + if (n_fd==0) + tr_debug("tids_get_listener: Error opening port %d"); + else { /* opening port succeeded */ tr_debug("tids_get_listener: Opened port %d.", port); /* make this socket non-blocking */ - if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) { - tr_debug("tids_get_listener: Error setting O_NONBLOCK."); - close(listen); - listen=-1; + for (ii=0; ii 0) { + if (n_fd>0) { /* store the caller's request handler & cookie */ tids->req_handler = req_handler; tids->auth_handler = auth_handler; @@ -434,7 +470,7 @@ int tids_get_listener(TIDS_INSTANCE *tids, tids->cookie = cookie; } - return listen; + return n_fd; } /* Accept and process a connection on a port opened with tids_get_listener() */ @@ -468,58 +504,6 @@ int tids_accept(TIDS_INSTANCE *tids, int listen) return 0; } -/* Process tids requests forever. Should not return except on error. */ -int tids_start (TIDS_INSTANCE *tids, - TIDS_REQ_FUNC *req_handler, - TIDS_AUTH_FUNC *auth_handler, - const char *hostname, - unsigned int port, - void *cookie) -{ - int listen = -1; - int conn = -1; - pid_t pid; - - tids->tids_port = port; - if (0 > (listen = tids_listen(tids, port))) - perror ("Error from tids_listen()"); - - /* store the caller's request handler & cookie */ - tids->req_handler = req_handler; - tids->auth_handler = auth_handler; - tids->hostname = hostname; - tids->cookie = cookie; - - tr_info("Trust Path Query Server starting on host %s:%d.", hostname, port); - - while(1) { /* accept incoming conns until we are stopped */ - - if (0 > (conn = accept(listen, NULL, NULL))) { - perror("Error from TIDS Server accept()"); - return 1; - } - - if (0 > (pid = fork())) { - perror("Error on fork()"); - return 1; - } - - if (pid == 0) { - close(listen); - tids_handle_connection(tids, conn); - close(conn); - exit(0); /* exit to kill forked child process */ - } else { - close(conn); - } - - /* clean up any processes that have completed */ - while (waitpid(-1, 0, WNOHANG) > 0); - } - - return 1; /* should never get here, loops "forever" */ -} - void tids_destroy (TIDS_INSTANCE *tids) { /* clean up logfiles */ diff --git a/tr/tr_main.c b/tr/tr_main.c index 5eb825e..7df04ee 100644 --- a/tr/tr_main.c +++ b/tr/tr_main.c @@ -141,7 +141,7 @@ int main(int argc, char *argv[]) TR_INSTANCE *tr = NULL; struct cmdline_args opts; struct event_base *ev_base; - struct tr_socket_event tids_ev; + struct tr_socket_event tids_ev = {0}; struct event *cfgwatch_ev; configure_signals(); diff --git a/tr/tr_tid.c b/tr/tr_tid.c index 63744ab..1ccc54f 100644 --- a/tr/tr_tid.c +++ b/tr/tr_tid.c @@ -161,6 +161,7 @@ static int tr_tids_req_handler (TIDS_INSTANCE *tids, retval=-1; goto cleanup; } + tr_debug("tr_tids_req_handler: Community was a COI, switching."); /* TBD -- In theory there can be more than one? How would that work? */ if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) { @@ -341,6 +342,7 @@ int tr_tids_event_init(struct event_base *base, TALLOC_CTX *tmp_ctx=talloc_new(NULL); struct tr_tids_event_cookie *cookie=NULL; int retval=0; + size_t ii=0; if (tids_ev == NULL) { tr_debug("tr_tids_event_init: Null tids_ev."); @@ -362,25 +364,29 @@ int tr_tids_event_init(struct event_base *base, talloc_steal(tids, cookie); /* get a tids listener */ - tids_ev->sock_fd=tids_get_listener(tids, - tr_tids_req_handler, - tr_tids_gss_handler, - cfg_mgr->active->internal->hostname, - cfg_mgr->active->internal->tids_port, - (void *)cookie); - if (tids_ev->sock_fd < 0) { + tids_ev->n_sock_fd=tids_get_listener(tids, + tr_tids_req_handler, + tr_tids_gss_handler, + cfg_mgr->active->internal->hostname, + cfg_mgr->active->internal->tids_port, + (void *)cookie, + tids_ev->sock_fd, + TR_MAX_SOCKETS); + if (tids_ev->n_sock_fd==0) { tr_crit("Error opening TID server socket."); retval=1; goto cleanup; } - /* and its event */ - tids_ev->ev=event_new(base, - tids_ev->sock_fd, - EV_READ|EV_PERSIST, - tr_tids_event_cb, - (void *)tids); - event_add(tids_ev->ev, NULL); + /* Set up events */ + for (ii=0; iin_sock_fd; ii++) { + tids_ev->ev[ii]=event_new(base, + tids_ev->sock_fd[ii], + EV_READ|EV_PERSIST, + tr_tids_event_cb, + (void *)tids); + event_add(tids_ev->ev[ii], NULL); + } cleanup: talloc_free(tmp_ctx); diff --git a/tr/tr_trp.c b/tr/tr_trp.c index a3b32b4..2b93969 100644 --- a/tr/tr_trp.c +++ b/tr/tr_trp.c @@ -396,6 +396,7 @@ TRP_RC tr_trps_event_init(struct event_base *base, TR_INSTANCE *tr) struct tr_trps_event_cookie *sweep_cookie=NULL; struct timeval zero_time={0,0}; TRP_RC retval=TRP_ERROR; + size_t ii=0; if (tr->events != NULL) { tr_notice("tr_trps_event_init: tr->events was not null. Freeing before reallocating.."); @@ -426,28 +427,31 @@ TRP_RC tr_trps_event_init(struct event_base *base, TR_INSTANCE *tr) trps_cookie->cfg_mgr=tr->cfg_mgr; /* get a trps listener */ - listen_ev->sock_fd=trps_get_listener(tr->trps, - tr_trps_msg_handler, - tr_trps_gss_handler, - tr->cfg_mgr->active->internal->hostname, - tr->cfg_mgr->active->internal->trps_port, - (void *)trps_cookie); - if (listen_ev->sock_fd < 0) { + listen_ev->n_sock_fd=trps_get_listener(tr->trps, + tr_trps_msg_handler, + tr_trps_gss_handler, + tr->cfg_mgr->active->internal->hostname, + tr->cfg_mgr->active->internal->trps_port, + (void *)trps_cookie, + listen_ev->sock_fd, + TR_MAX_SOCKETS); + if (listen_ev->n_sock_fd==0) { tr_crit("Error opening TRP server socket."); retval=TRP_ERROR; tr_trps_events_free(tr->events); tr->events=NULL; goto cleanup; } - trps_cookie->ev=listen_ev->ev; /* in case it needs to frob the event */ - - /* and its event */ - listen_ev->ev=event_new(base, - listen_ev->sock_fd, - EV_READ|EV_PERSIST, - tr_trps_event_cb, - (void *)(tr->trps)); - event_add(listen_ev->ev, NULL); + + /* Set up events for the sockets */ + for (ii=0; iin_sock_fd; ii++) { + listen_ev->ev[ii]=event_new(base, + listen_ev->sock_fd[ii], + EV_READ|EV_PERSIST, + tr_trps_event_cb, + (void *)(tr->trps)); + event_add(listen_ev->ev[ii], NULL); + } /* now set up message queue processing event, only triggered by * tr_trps_mq_cb() */ diff --git a/trp/trps.c b/trp/trps.c index 9a96466..fcddf4f 100644 --- a/trp/trps.c +++ b/trp/trps.c @@ -278,8 +278,10 @@ TRP_RC trps_send_msg(TRPS_INSTANCE *trps, TRP_PEER *peer, const char *msg) return rc; } -/* Listens on all interfaces */ -static int trps_listen(TRPS_INSTANCE *trps, int port) +/* Listens on all interfaces. Returns number of sockets opened. Their + * descriptors are stored in *fd_out, which should point to space for + * up to max_fd of them. */ +static size_t trps_listen(TRPS_INSTANCE *trps, int port, int *fd_out, size_t max_fd) { int rc = 0; int conn = -1; @@ -291,57 +293,66 @@ static int trps_listen(TRPS_INSTANCE *trps, int port) .ai_socktype=SOCK_STREAM, .ai_protocol=IPPROTO_TCP}; char *port_str=NULL; + size_t n_opened=0; port_str=talloc_asprintf(NULL, "%d", port); if (port_str==NULL) { tr_debug("trps_listen: unable to allocate port."); return -1; } - rc=getaddrinfo(NULL, port_str, &hints, &ai_head); + getaddrinfo(NULL, port_str, &hints, &ai_head); talloc_free(port_str); /* TODO: listen on all ports */ - for (ai=ai_head; ai!=NULL; ai=ai->ai_next) { + for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_openedai_next) { + if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) { + tr_debug("trps_listen: unable to open socket."); + continue; + } + + optval=1; + if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) + tr_debug("trps_listen: unable to set SO_REUSEADDR."); /* not fatal? */ + if (ai->ai_family==AF_INET6) { - ai=talloc_memdup(NULL, ai, sizeof(struct addrinfo)); /* get a permanent copy of this */ - break; + /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure + * if still relevant) */ + if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) { + tr_debug("trps_listen: unable to set IPV6_V6ONLY. Skipping interface."); + close(conn); + continue; + } + } + + rc=bind(conn, ai->ai_addr, ai->ai_addrlen); + if (rc<0) { + tr_debug("trps_listen: unable to bind to socket."); + close(conn); + continue; + } + + if (0>listen(conn, 512)) { + tr_debug("trps_listen: unable to listen on bound socket."); + close(conn); + continue; } + + /* ok, this one worked. Save it */ + fd_out[n_opened++]=conn; } freeaddrinfo(ai_head); - if (ai==NULL) { + if (n_opened==0) { tr_debug("trps_listen: no addresses available for listening."); return -1; } - if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) { - tr_debug("trps_listen: unable to open socket."); - talloc_free(ai); - return -1; - } - - optval=1; - setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); -/* setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); */ + tr_debug("trps_listen: TRP Server listening on port %d on %d socket%s", + port, + n_opened, + (n_opened==1)?"":"s"); - rc=bind(conn, ai->ai_addr, ai->ai_addrlen); - talloc_free(ai); - - if (rc<0) { - char errmsg[255]; - tr_debug("trps_listen: unable to bind to socket (%s).", strerror_r(errno, errmsg, 255)); - close(conn); - return -1; - } - - if (0>listen(conn, 512)) { - tr_debug("trps_listen: unable to listen on bound socket."); - close(conn); - return -1; - } - - tr_debug("trps_listen: TRP Server listening on port %d", port); - return conn; + return n_opened; } /* get the currently selected route if available */ @@ -445,32 +456,35 @@ int trps_get_listener(TRPS_INSTANCE *trps, TRP_AUTH_FUNC auth_handler, const char *hostname, unsigned int port, - void *cookie) + void *cookie, + int *fd_out, + size_t max_fd) { - int listen = -1; - - if (0 > (listen = trps_listen(trps, port))) { - char errbuf[256]; - if (0 == strerror_r(errno, errbuf, 256)) { - tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf); - } else { - tr_debug("trps_get_listener: Unknown error openining port %d.", port); - } - } + size_t n_fd=0; + size_t ii=0; - if (listen > 0) { + n_fd=trps_listen(trps, port, fd_out, max_fd); + if (n_fd==0) + tr_debug("trps_get_listener: Error opening port %d."); + else { /* opening port succeeded */ tr_debug("trps_get_listener: Opened port %d.", port); - /* make this socket non-blocking */ - if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) { - tr_debug("trps_get_listener: Error setting O_NONBLOCK."); - close(listen); - listen=-1; + /* make the sockets non-blocking */ + for (ii=0; ii 0) { + if (n_fd>0) { /* store the caller's request handler & cookie */ trps->msg_handler = msg_handler; trps->auth_handler = auth_handler; @@ -479,7 +493,7 @@ int trps_get_listener(TRPS_INSTANCE *trps, trps->cookie = cookie; } - return listen; + return n_fd; } TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn) -- 2.1.4